前言本文主要介绍日常项目开发过程中的一些技巧,不仅可以帮助提高工作效率,还可以提升应用性能。下面总结一下我平时的一些工作技巧。minxin让组件重用变得灵活Vue提供了minxin,一种将组件属性插入组件的方法。个人建议尽量少用这个产品,但是有一个场景强烈推荐minxin:当某段代码在多个组件中重复出现,并且重复的代码块比较大时,将其作为一颗敏心,往往能给后期的维护带来极大的方便。比如我们在项目中封装了一个列表功能,有下拉刷新、加载自动请求数据、上拉加载下一页数据等,代码如下:exportdefault{data(){return{page:1,limit:10,busy:false,//请求拦截,防止多次加载finish:false,//请求是否完成,用于页面展示效果pageList:[],//页面数据reqParams:{},//页面请求参数,可以更改defaultParams:{},//页面请求参数,下拉刷新不会重置和更改routeName:'',//特殊情况,当页面需要复用其他people'slistsautoReq:true,//onload是否自己请求lodingText:'',//请求底部显示的文本noDataText:'Nodata',//自定义无数据复制lastText:'-我有底部line-',noData:false,//页面没有数据reqName:''}},created(){this.autoReq&&this.initPage(false,true)},onPullDownRefresh(){this.pullDownRefreshFn()},onReachBottom(){this.reachBottomFn()},methods:{//heavy设置初始化数据initPage(saveParams=true,refresh=false){//初始化所有变量this.page=1this.busy=falsethis.finish=falsethis.noData=falsethis.lodingText='数据加载'if(saveParams){const{page,limit}=this.reqParamspage?this.page=page:''limit?this.limit=limit:''}else{this.reqParams={}}this.getCommonList(refresh)},//下拉刷新函数pullDownRefreshFn(){this.initData()this.initPage(false,true)},//上载函数reachBottomFn(){this.getCommonList()},//重新加载设置数据,方便调用(一般在外面自定义清除一些数据)initData(){//重置数据里的变量,这样外面引用mixin的时候,下拉刷新重置变量},//列表获取数据接口asyncgetCommonList(refresh){if(!this.reqName)returnif(this.busy)returnthis.busy=truethis.finish=falseconsthttpFn=this.$http||getApp().globalData.$http//兼容nvuetry{constquery={...this.defaultParams,...this.reqParams,page:this.page,limit:this.limit}const{data}=awaithttpFn(this.reqName,query)if(this.page===1)this.pageList=[]/***[Node.JS中用concat和push连接两个或多个数组的性能比较](http://ourjs.com/detail/5cb3fe1c44b4031138b4a1e2)*那么两者在node.js中是怎样的性能?我们做了一组测试数据,两种方式测试了100万次*push比concat方式快3倍左右。因为push只是在原有数组的基础上进行修改,所以速度会更快。*push返回的是数组的长度,所以不需要重新定义变量就可以判断*[Array.prototype.push.apply(arr1,arr2)不能自动触发DOM更新](https://www.imooc.com/wenda/详情/494323)*因为this.pageList.push!==Array.prototype.push,this.pageList.push指向vue重写的方法*/this.finish=trueconstresLen=data.list?data.list.length:0if(resLen===0){this.resSuccess(data,refresh)return}constlistLen=this.pageList.push.apply(this.pageList,data.list)if(listLen0){this.$nextTick(()=>{setTimeout(()=>{thisthis.lodingText=this.lastText},100)})}else{thisthis.lodingText=this.noDataTextthis.noData=true}}refresh&&uni.stopPullDownRefresh()this.finishInit(data)},//请求做某事(方便引用外部导入的文件)finishInit(data){//请求completesomething//console.log('Listrequestcompleted');}}}很多人看到这一幕,你应该会疑惑为什么不把它封装成一个组件呢?由于很多列表样式不同,封装到一个组件中扩展性不是很好,但是我们可以通过minxin来简化代码:{{item}}我们只需要定义请求参数,请求的地址,列表的样式就可以实现一个好的列表功能。拯救复杂的模板——render函数项目中有时模板中会有多个判断。如果按照下面的代码来写业务逻辑,代码会显得冗余和凌乱。插槽><插槽><插槽>
现在使用render函数重写上面的例子:.level,this.$slots.default);}};一劳永逸的组件注册组件在使用前需要先导入再注册:importBaseButtonfrom'./baseButton'importBaseIconfrom'./baseIcon'importBaseInputfrom'./baseInput'exportdefault{组件:{BaseButton,BaseIcon,BaseInput}}现在可以在模板中使用BaseButton、BaseIcon和BaseInput:但是如果组件太多,每次都要导入每个要用的组件,然后注册组件,会增加很多代码!我们应该如何优化它?这时候我们就需要使用webpack的require.context()方法来创建自己的(模块)context,从而实现自动动态require组件。该方法需要3个参数:要查找的文件夹目录、是否也要查找子目录、匹配文件的正则表达式。我们先在components文件夹下添加一个名为global.js的文件(里面包含了一些高频组件),使用require.context将所有需要的高频组件动态封装在这个文件中。然后在main.js文件中导入global.js文件。//global.js文件importVuefrom'vue'functionchangeStr(str){returnstr.charAt(0).toUpperCase()+str.slice(1)}constrequirerequireComponent=require.context('./',false,/\.vue$/)//查找同目录下以vue结尾的组件constinstall=()=>{requireComponent.keys().forEach(fileName=>{letconfig=requireComponent(fileName)console.log(config)//./child1.vue然后使用正则化得到child1letcomponentName=changeStr(fileName.replace(/^\.\//,'').replace(/\.\w+$/,''))Vue.component(componentName,config.default||config)})}exportdefault{install//将install方法暴露给外界}//main.jsimportindexfrom'./components/global.js'Vue.use(index)最后我们可以使用这些高层页面中随时随地的Audio组件,无需手动一一导入。隐藏大招——在hook开发过程中,我们有时需要创建一个定时器,而这个定时器必须在组件销毁前销毁。代码如下:mounted(){//创建一个定时器this.timer=setInterval(()=>{//...},500);},//销毁这个定时器。beforeDestroy(){if(this.timer){clearInterval(this.timer);this.timer=null;}}有个明显的缺点:timer定时器的创建和清理不在一个地方,容易忘记清理!我们可以使用hooks来整合代码,让代码更容易维护:mounted(){lettimer=setInterval(()=>{//...},500);this.$once("hook:beforeDestroy",function(){if(timer){clearInterval(timer);timer=null;}});}在Vue组件中,可以使用once来监听所有的生命周期钩子函数,比如监听组件的更新钩子函数可以写成this.$on('hook:updated',()=>{})。除了上述应用之外,hook还可以对外监控组件的生命周期功能。在某些情况下,我们需要知道子组件何时在父组件中被创建、挂载或更新。比如你想监听第三方组件CustomSelect渲染时的updatedhook,可以使用@hook:updated来实现:简单暴力routerkey我们在开发项目的时候,可能会遇到这样一个问题:当页面切换到同一个路由但是参数地址不同,比如/detail/1,跳转到/detail/2,之后数据没有更新页面跳转?路由配置如下:{path:"/detail/:id",name:"detail",component:Detail}这是因为vue-router会识别两个路由使用同一个组件进行复用,不会会重新创建组件,自然不会触发组件的生命周期钩子,导致跳转后没有数据更新。那么我们如何解决这个问题呢?我们可以向router-view组件添加一个属性键。示例如下:该方法主要是利用虚拟DOM比较两个节点是否相同,如果key不相同同样的,会判断router-view组件是一个新的节点,所以先销毁该组件,然后再重新创建一个新的组件,这样会重新触发组件中的生命周期。高精度权限控制--自定义指令directive我们通常在一个元素中添加v-if/v-show来判断用户是否有权限,但是如果判断条件比较繁琐,需要判断多个地方,这段代码方法不仅不雅而且多余。针对这种情况,我们可以封装一个命令权限,可以简单快速的实现按钮级的权限判断。我们先新建一个array.js文件,用来存放权限相关的全局函数//array.jsexportfunctioncheckArray(key){letarr=['admin','editor']letindex=arr.indexOf(key)if(index>-1){returntrue//withpermission}else{returnfalse//withoutpermission}}然后将数组文件挂载到全局//main.jsimport{checkArray}from"./common/array";Vue.config.productionTip=false;Vue.directive("permission",{inserted(el,binding){letpermission=binding.value;//获取v-permission的值if(permission){lethasPermission=checkArray(permission);if(!hasPermission){//没有权限移除Dom元素el.parentNode&&el.parentNode.removeChild(el);}}}});最后我们可以通过页面中的自定义命令v-permission来判断:permissionbutton1//会显示权限按钮2//不显示权限按钮3//会显示