记录一下开发中使用的 vue 技巧
路由参数解耦
一般在组件内使用路由参数, 大多数人会这样做:
1 2 3 4 5 6 7
   | export default {   methods: {     getParamsId () {       return this.$route.params.id     }   } }
  | 
 
在组件中使用 $route 会使之与其对应路由形成高度耦合, 从而使组件只能在某些特定的 URL 上使用, 限制了其灵活性.
正确的做法是通过 props 解耦
1 2 3 4 5 6 7
   | const router = new VueRouter({   routes: [{     path: '/user/:id',     component: User,     props: true   }] })
  | 
 
将路由的 props 属性设置为 true 后, 组件内可通过 props 接收到 params 参数
1 2 3 4 5 6 7 8
   | export default {   props: ['id'],   methods: {     getParamsId () {       return this.id     }   } }
  | 
 
另外你还可以通过函数模式来返回 props
1 2 3 4 5 6 7 8 9
   | const router = new VueRouter({   routes: [{     path: '/user/:id',     component: User,     props: route => ({       id: route.query.id     })   }] })
  | 
 
文档: 路由组件传参 | Vue Router
函数式组件
函数式组件是无状态, 它无法实例化, 没有任何的生命周期和方法. 创建函数式组件也很简单, 只需要在模板添加 functional 声明即可. 一般适合只依赖于外部数据的变化而变化的组件, 因其轻量, 渲染性能也会有所提高.
组件需要的一切都是通过 context 参数传递. 它是一个上下文对象, 具体属性查看文档. 这里 props 是一个包含所有绑定属性的对象.
函数式组件
1 2 3 4 5 6 7 8
   | <template functional>   <div class="list">     <div class="item" v-for="item in props.list" :key="item.id" @click="props.itemClick(item)">       <p>{{item.title}}</p>       <p>{{item.content}}</p>     </div>   </div> </template>
   | 
 
父组件使用
1 2 3 4 5
   | <template>   <div>     <List :list="list" :itemClick="item => (currentItem = item)"></List>   </div> </template>
   | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | import List from '@/components/List.vue' export default {   components: {     List   },   data () {     return {       list: [{         title: 'title',         content: 'content'       }],       currentItem: ''     }   } }
   | 
 
文档: 函数式组件
watch
触发 watch 监听执行多个方法
使用数组可以设置多项, 形式包括字符串、函数、对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | export default {   data: {     name: 'Joe'   },   watch: {     name: [       'sayName1',       function (newVal, oldVal) {         this.sayName2()       },       {         handler: 'sayName3',         immediate: true       }     ]   },   methods: {     sayName1 () {       console.log('sayName1==>', this.name)     },     sayName2 () {       console.log('sayName2==>', this.name)     },     sayName3 () {       console.log('sayName3==>', this.name)     }   } }
  | 
 
watch 监听多个变量
watch 本身无法监听多个变量. 但我们可以将需要监听的多个变量通过计算属性返回对象, 再监听这个对象来实现 “监听多个变量”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
   | export default {   data () {     return {       msg1: 'apple',       msg2: 'banana'     }   },   computed: {     msgObj () {       const {         msg1,         msg2       } = this       return {         msg1,         msg2       }     }   },   watch: {     msgObj: {       handler (newVal, oldVal) {         if (newVal.msg1 != oldVal.msg1) {           console.log('msg1 is change')         }         if (newVal.msg2 != oldVal.msg2) {           console.log('msg2 is change')         }       },       deep: true     }   } }
  | 
 
文档: watch
程序化的事件侦听器
比如, 在页面挂载时定义计时器, 需要在页面销毁时清除定时器. 这看起来没什么问题. 但仔细一看 this.timer 唯一的作用只是为了能够在 beforeDestroy 内取到计时器序号, 除此之外没有任何用处.
1 2 3 4 5 6 7 8 9 10
   | export default {   mounted () {     this.timer = setInterval(() => {       console.log(Date.now())     }, 1000)   },   beforeDestroy () {     clearInterval(this.timer)   } }
  | 
 
如果可以的话最好只有生命周期钩子可以访问到它. 这并不算严重的问题, 但是它可以被视为杂物.
我们可以通过 $on 或 $once 监听页面生命周期销毁来解决这个问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | export default {   mounted () {     this.createInterval('hello')     this.createInterval('world')   },   createInterval (msg) {     let timer = setInterval(() => {       console.log(msg)     }, 1000)     this.$once('hook:beforeDestroy', function () {       clearInterval(timer)     })   } }
  | 
 
使用这个方法后, 即使我们同时创建多个计时器, 也不影响效果. 因为它们会在页面销毁后程序化的自主清除.
文档: 程序化的事件侦听器