v-cloak
在渲染的时候,为了防止页面显示双大括号,可以使用 v-cloak 指令来隐藏未编译的(双大括号)标签直到实例准备完毕
使用是在 css 定义
[v-cloak] { display: none;}
<div v-cloak>{{ message }}</div>
数组的修改
vue 不能检测以下变动的数组
- 当你利用索引直接设置一个项时,例如:
vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:
vm.items.length = newLength
举个例子:
var vm = new Vue({ data: { items: ['a', 'b', 'c'], },});vm.items[1] = 'x'; // 不是响应性的vm.items.length = 2; // 不是响应性的
上面两个都不会重新渲染视图
为了解决第一类问题,以下两种方式都可以实现和vm.items[indexOfItem] = newValue
相同的效果,同时也将触发状态更新
// Vue.setVue.set(vm.items, indexOfItem, newValue);// vm.$setvm.$set(vm.items, indexOfItem, newValue);// Array.prototype.splicevm.items.splice(indexOfItem, 1, newValue);
为了解决第二类问题,你可以使用数组的splice
方法
vm.items.splice(newLength);
对象的修改
vue 不能检测对象属性的添加或删除
var vm = new Vue({ data: { a: 1, },});vm.a = 1; // vm.a是响应式的vm.b = 2; // vm.b不是响应式的
如果要新增对象属性,可以用Vue.set(object, key, value)
Vue.set(vm.data, 'b', 2);// 或者vm.$set(vm.data, 'b', 2);
如果需要新增多个响应式属性,可以这样
vm.data = Object.assign({}, vm.data, { c: 4, d: 5,});
.sync 修饰符
vue 推荐通过事件触发的模式来同步父组件传递的属性值,例如
<Parent :title="title" @updateTitle="updateHandle"/>
父组件通过 :title
传递 title 属性,设置监听 updateTitle
事件
注意子组件不允许直接修改 title 的值,如果在子组件 this.title 赋值的话会报错
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders
可以通过 this.$emit('updateTitle', Math.random())
来触发父组件做出修改 title 的操作
虽然通过上面可以实现父子间的通信,但是有一个更简单的方法就是使用 sync 修饰符来实现,在属性添加 .sync
修饰符后 vue 会自动帮我们绑定 :update:[prop]
事件方法,例如
<Parent :title.sync="title" />
相当于
<Parent :title="title" v-on:update:title="val => title = val" />
子组件就可以直接通过触发 :update:[prop]
方法提示父组件更新对应的 title 值
this.$emit('update:title', newTitle);
v-model 的节流和防抖
有时候需要监听 input 框触发远程搜索功能,为了避免触发的频率过高,可以使用节流函数,第三方例如 lodash 或者 underscore 的_.throttle(function, wait, [options])
使用的方法如下,也可以使用防抖函数_.debounce(func, [wait=0], [options={}])
来实现输入完成后再触发
<template> <div id="app"> <input type="text" v-model="uname" /> </div></template><script> export default { name: 'app', data() { return { uname: '', }; }, watch: { uname(val, oldVal) { this.handleSearch(1, val); }, }, methods: { handleSearch: _.throttle(function (page, key) { console.log(page, key); }, 800), }, };</script>
按键修饰符
vue 提供了常用按键的别名,方便我们使用
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
比如要实现按回车键提交表单,可以使用下面的方法
<!-- 同上 --><input v-on:keyup.enter="submit" /><!-- 缩写语法 --><input @keyup.enter="submit" />
vuex 获取 store 的状态
获取 store 的 state 方法有两种
- 在组件里面通过 this.$store.state.count
this.$store.state.count;
- 通过 mapState 辅助函数只是用来方便我们获取 store 里的状态
{ computed: mapState({ count: (state) => state.count, });}// 更简单的写法{ computed: mapState(['count']);}
如果要与组件自身的计算属性混合使用,可以使用对象展开运算符
computed: { name () { return this.firstName + this.lastName; }, ...mapState({ // ... })}
全局 sass 变量和 mixin
本地安装 npm i sass-resources-loader -D
这个模块,在 build/utils.js
文件里面找到 cssLoaders
方法,添加如下代码
exports.cssLoaders = function (options) { // ... function resolveResouce(fileName) { // 全局sass文件,可以直接在vue文件使用,全局的变量或者mixin return path.resolve(__dirname, '../src/assets/scss/' + fileName); } function generateSassResourceLoader() { var loaders = [ cssLoader, 'sass-loader', { loader: 'sass-resources-loader', options: { resources: [ resolveResouce('_mixin.scss'), resolveResouce('_variable.scss'), ], }, }, ]; if (options.extract) { return ExtractTextPlugin.extract({ use: loaders, fallback: 'vue-style-loader', }); } else { return ['vue-style-loader'].concat(loaders); } } // ...};
最后 sass
和 scss
选项配置改为如下即可
return { css: generateLoaders(), postcss: generateLoaders(), less: generateLoaders('less'), sass: generateSassResourceLoader(), // generateLoaders('sass', { indentedSyntax: true }), scss: generateSassResourceLoader(), // generateLoaders('sass'), stylus: generateLoaders('stylus'), styl: generateLoaders('stylus'),};
子组件继承父组件的样式
一般在写 vue 单文件组件样式的时候我们会写 scope 来限制样式的作用于当前组件,但是如果要让子组件也继承当前组件的样式,就可以通过深度作用选择器
.a >>> .b { /* ... */}
>>>
在 sass/less 文件的写法为/deep/
vue-router 守卫
vue-router 提供了三种守卫,全局守卫、路由独享守卫,组件内守卫
全局守卫有三个,beforeEach
和 beforeResolve
和 afterEach
router.beforeResolve 是 2.5.0+新增的,在导航被确认之前,同时在所有的组件内守卫和异步路由组件被解析之后,解析守卫就会被调用
const router = new VueRouter({ ... })router.beforeEach((to, from, next) => { // ...})router.beforeResolve((to, from, next) => { // ...})router.afterEach((to, from) => { // ...})
路由独享守卫只有一个,beforeEnter
在路由定义的时候单独配置的守卫
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... }, }, ],});
组件内守卫有三个 beforeRouteEnter
和 beforeRouteUpdate
和 beforeRouteLeav
这里需要注意两点
beforeRouteEnter
不能访问this
,因为守卫在导航确认前被调用,新的组件还没被创建,但是可以通过传一个回调给next
,就可以访问到实例了
beforeRouteEnter (to, from, next) { next(vm => { // 通过 `vm` 访问组件实例 })}
beforeRouteLeave
是导航离开组件调用,可以通过next(false)
来取消跳转
一个完整的组件内路由导航守卫如下
const Foo = { template: `...`, beforeRouteEnter(to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate(to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave(to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` },};