v-cloak

在渲染的时候,为了防止页面显示双大括号,可以使用 v-cloak 指令来隐藏未编译的(双大括号)标签直到实例准备完毕

使用是在 css 定义

[v-cloak] {
display: none;
}
<div v-cloak>{{ message }}</div>

数组的修改

vue 不能检测以下变动的数组

  1. 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
  2. 当你修改数组的长度时,例如: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.set
Vue.set(vm.items, indexOfItem, newValue);
// vm.$set
vm.$set(vm.items, indexOfItem, newValue);
// Array.prototype.splice
vm.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);
}
}
// ...
};

最后 sassscss 选项配置改为如下即可

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 提供了三种守卫,全局守卫、路由独享守卫,组件内守卫

全局守卫有三个,beforeEachbeforeResolveafterEach

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`
},
};

vue-router 解析流程图

vue-router的解析流程图