父子组件生命周期顺序
渲染过程:
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
- 当父组件执行完beforeMount挂载开始后,会依次执行子组件中的钩子,直到全部子组件mounted挂载到实例上,父组件才会进入mounted钩子
- 子级触发事件,会先触发父级beforeUpdate钩子,再去触发子级beforeUpdate钩子,下面又是先执行子级updated钩子,后执行父级updated钩子
更新过程
子组件: beforeUpdate(父) - beforeUpdate(子)-updated(子)- updated(父)
父组件:beforeUpdate(父)- updated(父))
销毁过程
beforeDestroy(父)- beforeDestroy(子)- destroyed(子)- destroyed(父)
父子组件之间的传值
-
props:父组件直接绑定在子组件的标签上,子组件通过props接收传递过来的参数。
父组件:
<template> <i-activities-item :content="content"/> </template>
子组件
<template> <div>{{ content }}</div> </template> <script> export default { name: '', props: { content: { // 定义接收的类型 还可以定义多种类型 [String, Undefined, Number] // 如果required为true,尽量type允许undefined类型,因为传递过来的参数是异步的。或者设置默认值。 type: String, // 定义是否必须传 required: true, // 定义默认值 default: '暂无' }, }, }; </script>
-
$emit:触发当前实例上的事件。附加参数都会传给监听器回调。
<div id="app"> <counter @inc="addnumber"></counter> </div> <script> Vue.component('counter', { template: '<div @click="add">点击一下</div>', methods: { add: function() { this.$emit('inc', '大老虎') } }, }) </script>
-
sync修饰符:在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源。
<text-document v-bind:title="doc.title" v-on:update:title="doc.title = $event" ></text-document>
<text-document v-bind:title.sync="doc.title"></text-document>
this.$emit('update:title', newTitle)
-
attrs和listeners
attrs:包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=“attrs” 传入内部组件——在创建高级别的组件时非常有用。
listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
<div id="app"> <child :foo="foo" :bar="bar" @one.native="triggerOne" @two="triggerTwo"> <child> </div> <script> let Child = Vue.extend({ template: '<h2>{{ foo }}</h2>', props: ['foo'], created() { console.log(this.$attrs, this.$listeners) // -> {bar: "parent bar"} // -> {two: fn} // 这里我们访问父组件中的 `triggerTwo` 方法 this.$listeners.two() // -> 'two' } }) new Vue({ el: '#app', data: { foo: 'parent foo', bar: 'parent bar' }, components: { Child }, methods: { triggerOne() { alert('one') }, triggerTwo() { alert('two') } } }) </script>
-
provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的上下文特性很相似。<div id="app"> <child> </child> </div> <script> // 全局变量 let EventBus = new Vue() // 子组件 let Child = Vue.extend({ template: '<h2>child</h2>', created() { console.log(EventBus.message) // -> 'hello' EventBus.$emit('received', 'from child') } }) new Vue({ el: '#app', components: { Child }, created() { // 变量保存 EventBus.message = 'hello' // 事件监听 EventBus.$on('received', function(val) { console.log('received: ' + val) // -> 'received: from child' }) } }) </script>
-
EventBus:思路就是声明一个全局Vue实例变量EventBus,把所有的通信数据,事件监听都存储到这个变量上,这样就到达在组件间实现数据共享,有点类似Vuex。但是这种方式只适合极小的项目,复杂的项目还是推荐Vuex。
-
Vuex :官方推荐,VueX是一个专门为Vue.js应用程序开发的状态管理模式
-
$root:当前组件树的根Vue实例,如果当前实例没有父实例,此实例将会是自己。通过访问根组件也能进行数据之间的交互,但极小情况下回直接修改父组件中的数据.
-
$parent:父实例,如果当前实例有的话,通过访问父实例也能进行数据之间的交互,但极小情况下回直接修改父组件中的数据