本文面向对象,面向具有一定Vue.js编程经验的开发者。如果有谁需要Vue.js入门系列文章,请在评论区告诉我,我有时间会写给大家。对于大部分人来说,掌握了Vue.js的基本API之后,就已经可以正常开发前端网站了。但是如果你想更高效地使用Vue进行开发,成为Vue.js高手,那么你一定要认真学习我下面要教的5个技巧。第一招:简化Watchers场景还原:created(){this.fetchPostList()},watch:{searchInputValue(){this.fetchPostList()}}组件创建时,我们获取一个列表,监听输入同样的时间Box,每次有变化都要重新获取过滤后的列表是很常见的。有什么办法可以优化吗?动作分析:首先,在watchers中,可以直接使用函数的字面名字;第二,声明immediate:true表示在组件创建时立即执行。watch:{searchInputValue:{handler:'fetchPostList',immediate:true}}第二招:一劳永逸的组件注册场景还原:importBaseButtonfrom'./baseButton'importBaseIconfrom'./baseIcon'importBaseInputfrom'./baseInput'exportdefault{组件:{BaseButton,BaseIcon,BaseInput}}我们写了一堆基本的UI组件,每次需要用到这些组件,都得先导入,再声明组件,非常繁琐!秉承能偷懒就偷懒的原则,一定要想办法优化!动作分析:我们需要使用神器webpack,使用require.context()方法创建自己的(模块)context,实现自动动态require组件。该方法有3个参数:要搜索的文件夹目录、是否也搜索其子目录、匹配文件的正则表达式。我们在components文件夹下添加一个名为global.js的文件,使用webpack将所有需要的基础组件动态打包到这个文件中。importVuefrom'vue'functioncapitalizeFirstLetter(string){returnstring.charAt(0).toUpperCase()+string.slice(1)}constrequireComponent=require.context('.',false,/\.vue$///找到组件file以.vue命名的文件夹)requireComponent.keys().forEach(fileName=>{constcomponentConfig=requireComponent(fileName)constcomponentName=capitalizeFirstLetter(fileName.replace(/^\.\//,'').replace(/\.\w+$/,'')//因为获取到的文件名格式为:'./baseButton.vue',所以这里去掉头尾,只保留真正的文件名)Vue.component(componentName,componentConfig.default||componentConfig)})最后我们在main.js中导入'components/global.js',这样我们就可以随时随地使用这些基础组件,无需手动引入。第三招:路由器关键场景的还原:下面这个场景着实伤了很多程序员的心……首先,大家默认使用Vue-router来实现路由控制。假设我们正在写一个博客站点,需求是从/post-page/a跳转到/post-page/b。然后我们惊奇的发现,页面跳转后数据并没有更新?!原因是vue-router“智能地”发现这是同一个组件,然后决定重用这个组件,所以你写在created函数中的方法根本就没有执行。通常的解决办法是监听$route的变化来初始化数据,如下:data(){return{loading:false,error:null,post:null}},watch:{'$route':{handler:'resetData',immediate:true}},methods:{resetData(){this.loading=falsethis.error=nullthis.post=nullthis.getPost(this.$route.params.id)},getPost(id){}}bug是解决了,但是每次都这么写,也太不雅了吧?秉承能偷懒就偷懒的原则,我们希望代码这样写:data(){return{loading:false,error:null,post:null}},created(){this.getPost(this.$route.params.id)},methods(){getPost(postId){//...}}走位分析:如何实现这样的效果?答案就是给router-view加一个uniquekey,这样即使是publicComponent,只要url改变了,这个component肯定会重新创建。(虽然损失了一点点性能,但避免了无限的错误)。同时注意,我把key直接设置到路由的全路径,一箭双雕。第四招:万能的render函数场景还原:Vue要求每个组件只能有一个根元素,当你有很多的时候有一个根元素,vue会给你一个错误{{route.title}}}/router-link>ERROR-Componenttemplateshouldcontainexactlyonerootelement.Ifyouareusingv-ifonmultipleelements,usev-else-iftochaintheminstead.动作分析:有没有办法解决?答案是肯定的,但是这时候我们需要使用render()函数来创建HTML,而不是template。其实用js生成html的好处就是极其灵活和强大,不需要学习使用vue的功能有限的指令API,比如v-for,v-if。(reactjs完全丢弃模板)functional:true,render(h,{props}){returnprops.routes.map(route=>>{route.title})}第五招:无招无招的高阶组件划重点:此招威力无穷,请务必掌握。我们在写组件的时候,通常有必要从父组件传递一系列的props给子组件,父组件监听子组件发出的一系列事件。示例://父组件//子组件有以下优化点:1.父组件传给子组件的每一个props,我们都要在它之前的子组件的Props中显式声明可以使用。这样一来,我们的子组件每次都需要声明很多props,而我们实际上可以直接将placeholer等DOM原生属性从父组件传递给子组件,而无需声明。方法如下:$attrs包含父作用域不用作识别(和检索)的prop属性绑定(类和样式除外)。当一个组件没有声明任何props时,所有父范围绑定都包含在这里,并且可以通过v-bind="$attrs"传递给内部组件——在创建更高级别的组件时很有用。2.注意子组件的@focus=$emit('focus',$event)"其实什么都不做,只是把事件传回给父组件,其实和上面类似,我不需要显式声明:computed:{listeners(){return{...this.$listeners,input:event=>this.$emit('input',event.target.value)}}}$listeners包含父作用域中的v-on事件监听器(不带.native修饰符)。可以通过v-on="$listeners”到内部组件中——在创建更高级别的组件时非常有用。3.需要注意的是,由于我们的输入不是BaseInput组件的根节点,所以默认情况下父作用域不被认为是props的属性绑定“fallback”作为普通的HTML属性应用于子组件的根元素。所以我们需要设置inheritAttrs:false,这些默认行为会被去掉,上面两点的优化可以成功的。最终,掌握以上五招后,你就可以在Vue.js的海洋中自由驰骋了。