现在,Vue.js 已成为前端开发的热门框架。有很多工程师利用 Vue.js 的便利性和强大功能。但是,我们完成的某些解决方案可能未遵循最佳做法。今天本文就盘点一下那些鲜为人知的 Vue 技术。
路由器参数解耦
相信这是大多数人处理组件中路由参数的方式:
1 2 3 4 5 6 7
| export default { methods: { getRouteParamsId() { return this.$route.query.id } } }
|
在组件内部使用 $route
会对某个 URL
产生强耦合,这限制了组件的灵活性。
正确的解决方案是向路由器添加 props
。
1 2 3 4 5 6 7 8
| const router = new VueRouter({ routes: [{ path: '/:id', component: Component, props: true }] })
|
这样,组件可以直接从 props
获取 id
。
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
| const router = new VueRouter({ routes: [{ path: '/:id', component: Component, props: router => ({ id: router.query.id }) }] })
|
这里参数涉及两种, 分别是路由的 params
和 query
,需要注意区分
如果两种参数一起使用,可如下配置:
1 2 3 4 5 6 7 8 9
| const router = new VueRouter({ path: 'test/:id', component: () => import('../views/test.vue'), name: 'test', props: router => ({ id: router.params.id, name: router.query.name }) })
|
对应的页面就可以像这样获取参数
1 2 3 4 5 6 7 8
| export default { props: ['id', 'name'], mounted() { console.log(this.id) console.log(this.name) } }
|
监听多个变量
watcher
不能监听多个变量,但我们可以将目标组合在一起作为一个新的 computed
,并监视这个新的 “变量”。
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
| export default { data() { return { msg1: 'apple', msg2: 'banana' } }, compouted: { 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 } } }
|
函数式组件
函数组件 是无状态的(没有响应式数据),没有生命周期或方法,因此无法实例化, 创建一个函数组件非常容易,你需要做的就是在 SFC
中添加一个 functional: true
属性,或者在模板中添加 functional
。由于它像函数一样轻巧,没有实例引用,所以渲染性能提高了不少, 函数组件依赖于上下文,并随着其中给定的数据而突变。
下列示例与 vue 官方文档示例不同,它是基于 vue-cli
构建的项目写法,更贴近日常使用,也更适合新手学习
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <template> <test-components text="test"></test-components> </template>
<script> export default { components: { testComponents: { functional: true, props: { text: { type: String, required: true } }, render: function (createElement, context) { return createElement('h1', context.props.text) } } } } </script>
|
组件生命周期 Hook
通常,你可以像这样监听子组件的生命周期(例如 mounted
)
1 2 3 4 5 6 7 8 9 10 11 12 13
| <script> export default { mounted () { this.$emit('onMounted') } } </script>
<template> <Child @onMounted="handleOnMounted" /> </template>
|
还有另一种简单的解决方案,你可以改用 @hook:mount
在 Vue
内部系统中使用。
1 2 3 4
| <template> <Child @hook:mounted="handleOnMounted" /> </template>
|
样式穿透
在开发中修改第三方组件样式是很常见,但由于 scoped
属性的样式隔离,可能需要去除 scoped
或是另起一个 style
。这些做法都会带来副作用(组件样式污染、不够优雅),样式穿透在 css
预处理器中使用才生效。
我们可以使用 >>>
或 /deep/
解决这一问题:
1 2 3 4 5 6 7 8 9 10
| <style scoped> 外层 >>> .el-checkbox { display: block; font-size: 26px;
.el-checkbox__label { font-size: 16px; } } </style>
|
1 2 3 4 5 6 7 8 9 10
| <style scoped> /deep/ .el-checkbox { display: block; font-size: 26px;
.el-checkbox__label { font-size: 16px; } } </style>
|
事件参数 $event
$event
是事件对象的特殊变量,在一些场景能给我们实现复杂功能提供更多可用的参数
原生事件
在原生事件中表现和默认的事件对象相同
1 2 3 4 5
| <template> <div> <input type="text" @input="inputHandler('hello', $event)" /> </div> </template>
|
1 2 3 4 5 6 7
| export default { methods: { inputHandler(msg, e) { console.log(e.target.value) } } }
|
自定义事件
在自定义事件中表现为捕获从子组件抛出的值
my-item.vue:
1 2 3 4 5 6 7
| export default { methods: { customEvent() { this.$emit('custom-event', 'some value') } } }
|
App.vue:
1 2 3 4 5 6
| <template> <div> <my-item v-for="(item, index) in list" @custom-event="customEvent(index, $event)"> </my-list> </div> </template>
|
1 2 3 4 5 6 7
| export default { methods: { customEvent(index, e) { console.log(e) } } }
|
触发监听执行多个方法
你可以传入回调数组,它们会被逐一调用,形式包括字符串、函数、对象
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', immaediate: true } ] }, methods: { sayName1() { console.log('sayName1==>', this.name) }, sayName2() { console.log('sayName2==>', this.name) }, sayName3() { console.log('sayName3==>', this.name) } } }
|
Watch 中的引号
在 vuejs 项目中, 免不了使用 watch, 而在我们项目代码中经常看到 watch 监听的属性部分,有些有引号,有些没引号,甚至有些不用引号不行,官方文档没有详细说明这个引号的作用,所以很多人弄不清楚它又什么作用。
对象具体属性的 watch
可以直接用引号把属性括起来,就可以实现对象中特定属性的监听事件
1 2 3 4 5 6 7
| watch: { 'queryData.name': { handler: function() { //do something } } }
|
很多时候,我们监听一个属性,不会使用到改变前后的值,只是为了执行一些方法,这时可以使用字符串代替
1 2 3 4 5 6 7 8 9 10 11
| data:{ name:'Joe' }, watch:{ name:'sayName' }, methods:{ sayName(){ console.log(this.name) } }
|