Vue基础知识点

153 阅读5分钟

生命周期钩子函数

beforeCreate获取不到propsdata中的数据,因为这些数据的初始化都在initState中。
created可以访问到data,但是组件还没有被挂载,所以是看不到的。
breforeMount开始创建VDOM,最后执行mounted,并将VDOM渲染为真实的DOM并且渲染数据。组件中如果有子组件的话,会递归挂载子组件,只有当所有的子组件全部挂在完毕,才会执行根组件的挂载钩子。
接下来是数据更新是会调用的钩子函数beforeUpdateupdated
另外还有keep-alive独有的生命周期。分别是activeddeactivated。用keep-alive包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行deactivated钩子函数,命中缓存渲染后会执行actived钩子函数。
最后就是销毁组件的钩子函数beforeDestorydestroyed。前者适合移除事件、定时器等,否则可能会引起内存泄露的问题。但是进行一系列的销毁操作,如果有子组件,所有子组件销毁完毕后才会执行根组件的destroyed钩子函数。

组件通信

组件通信一般分为:

  • 父子组件通信
  • 兄弟组件通信
  • 跨多层级组件通信
  • 任意组件

父子通信

父组件通过props传递数据给子组件,子组件通过emit发送时间传递数据给父组件,这两种方式是最常用的父子通信实现办法。
这种父子通信方式也就是最典型的单项数据流,父组件通过props传递数据,子组件不能直接修改props,而是必须通过发送事件的方式告知父组件修改数据。
另外着两种方式还可以通过语法糖v-model来直接实现,因为v-model默认会解析成名为valueprop和名为input的事件。这种语法糖的方式是典型的双向绑定,常用于UI控件上,但是究其根本,还是通过事件的方法让父组件修改数据。
当然我们还可以通过防伪$parent$children对象来访问组件实例中的方法和数据。
vue2.3及以上的版本的话还可以使用$listeners.sync这两个属性。
$listeners属性会将父组件中(不含.native修饰器的)v-on事件监听器传给子组件,子组件可以通过访问$listeners来自定义监听器。
.sync属性是个语法糖,可以很简单的实现子组件和父组件通信

<!-- 父组件 -->
<input :value.sync="value" />
<!-- 等同于 -->
<input :value="value" @input:value="v => value = v"/>

<!-- 子组件 -->
<script>
    this.$emit('update:value', 1);
</script>

兄弟组件通信

对于这种情况可以通过查找父组件中的子组件实现,也就是this.$parent.$children,在$children中可以通过组件的name查询到需要的组件实例,然后进行通信。

跨多层次组件通信

对于这种情况可以使用vue2.2新增的APIprovide/inject,虽然文档中不推荐直接使用在业务中。
假设父组件parent,然后有一个垮了多层级的子组件child。

// 父组件 parent
export default {
    provide: {
        text: '这是父组件'
    }
}

// 子组件
export default {
    inject: ['text'],
    mounted() {
        console.log(this.text); // 这是父组件
    }
}

任意组件

这种方式可以通过vuex 或者Event Bus解决。

extend能做什么

这个api很少用到,作用是扩展组件生成一个构造函数,通常会与$mount一起使用

let Componet = Vue.extend({
    template: '<div>test</div>'
});
new Componet().$mount('#app');
let SuperComponet = Vue.extend(Component);
new SuperComponent({
    created() {
        console.log(1);
    }
});
new SuperComponent().$mount('#app');

mixin 和 mixins 区别

mixin用于全局混入,会影响到每个组件实例,通常插件都是这样做初始化的。

Vue.mixin({
    beforeCreate() {
        // 这种方式会影响到每个组件的breforeCreate钩子函数
    }
])

虽然文档不建议我们在应用中直接使用mixin,但是如果不滥用的话也是很有帮助的,比如可以全局混入封装好的ajax或者一些工具函数等等。
mixins应该是我们最常用的扩展组件的方式了。如果多个组件中有相同的业务逻辑,就可以将这些逻辑剥离出来,通过mixins混入代码。
另外需要注意的是mixins混入的钩子函数会先与组件内的钩子函数执行,并且在遇到同名选项的时候也会选择性的进行合并。

computed 和 watch 区别

computed是计算属性,以来其他属性计算值,并且computed的值有缓存,只有当计算值发生变化才会返回内容。
watch监听到值的变化才会执行回调,在回调中可以执行一些逻辑操作。
所以一般来说需要依赖别的属性来动态获得值的时候可以使用computed,对于监听到值的变化需要做一些复杂业务逻辑的情况可以使用watch
另外computedwatch还能支持对象的写法。

vm.$watch('obj', {
    deep: true,
    immediate: true,
    handler: function(val, oldVal) {}
})
var vm = new Vue({
    data: { a: 1 },
    computed: {
        aPlus: {
            get: function() {
                return this.a + 1
            },
            set: function(v) {
                this.a = v - 1
            }
        }
    }
})

keep-alive 组件有什么作用

如果我们需要组件切换的时候,保存一些组件的状态防止多次渲染,就可以使用keep-alive组件包裹需要保存的组件。
对于keep-alive组件来说,它拥有两个独有的生命周期钩子函数,分别是activateddeactivated。用keep-alive包裹的组件在切换是不会进行销毁,而是缓存到内存中并执行deactivated钩子函数,命中缓存渲染后会执行activated钩子函数。

v-show 与 v-if区别

v-show知识在display: nonedisplay: block之间切换。无论初始条件是什么都会被渲染出来,后面只会切换CSS,DOM还是一直保留着的。所以总的来说v-show在初始值渲染时有更高的开销,但是切换开销小,更适合频繁切换的场景。
v-if就得说到Vue底层的编译了。当属性初始为false时,组件就不会被渲染,知道条件为true,并且切换条件时会触发/挂载组件,所以总的来说在切换时开销更高,更适合不经常切换的场景。
v-if的这种惰性渲染机制,在必要的时候才去渲染组件,减少整个页面的初始渲染开销。

组件中data什么时候可以使用对象

组件复用是所有组件示例都会共享data,如果data是对象的话,就会造成一个组件修改data以后会影响到其他所有组件,所以需要将data写成函数,每次用到就调用一次函数获得新的数据。
当我们使用 new Vue()的方式的时候,无论我们将data设置为对象还是函数都是可以的,因为new Vue()的方式是生成一个根组件,该组件不会服用,也就不存在共享data的情况了。