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的解析流程图