Appearance
props
子组件接收到后不能改变父组件传递的数据的指向,当父组件重新渲染时,数据会被覆盖。
js<Foo :msg="msg"></Foo> export default { // 简写 props:['msg'] // 完整写法 props:{ msg:{ type: String, // 限制类型 type: [String, Number, Object], // 限制类型 required: true, // 必要性 default: '默认值', // 默认值为基本数据类型 default: () => [], // 默认值为数组 default: () => ({}) // 默认值为对象 } }, }sync修饰符
实现了父组件向子组件传递的数据的双向绑定
js<Child :msg.sync="msg"></Child> export default { props:['msg'], mounted () { // 子组件修改数据 this.$emit('update:msg', 'world') } }v-model
和sync修饰符类似,实现了父组件向子组件传递的数据的双向绑定
js<Foo v-model="msg"></Foo> export default { props:['msg'], model: { // 定义修改时emit的事件名,默认为input event: 'updateMsg' } mounted () { // 子组件修改数据 // this.$emit('input', 'world') this.$emit('updateMsg', 'world') } }ref
标签中直接写 ref="xxx"
通过this.$refs.xxx获取
给html内置标签打ref,获取到的是真实的DOM节点
给组件标签打ref,获取到的是组件实例
js<Foo ref="foo"></Foo> export default { mounted () { const foo = this.$refs.foo foo.someData // 使用子组件的数据 foo.someMethod() // 调用子组件的方法 } }$emit / v-on
子组件通过派发事件的方式给父组件传递或触发父组件的某些操作
js// Foo.vue <button @click="$emit('sendMsg', 'hello')">按钮</button> // App.vue <Foo @sendMsg="recvMsg"></Foo> export default { components: { Foo }, methods: { recvMsg (msg) { console.log(msg) } } }$attrs / $listeners
多层嵌套组件传递数据时,如果只是传递数据,而不做中间处理的话可以用这个,比如父组件向孙子组件传递数据
$attrs:父标签中写的属性,不包括class、style以及props中接收的数据$listeners:父标签中绑定的事件,不包括.native修饰符的事件// App.vue 父组件 <Foo :name="name" :age="age"></Foo> // Foo.vue 子组件 <Bar v-bind="$attrs" msg=“hello”></Bar> export default { props: ['name'], mounted () { console.log(this.$attrs) // { age: 18 },因为name写进了props中 } } // Bar.vue 孙组件 export default { mounted () { console.log(this.$attrs) // { age: 18, msg: "hello" } } }$children / $parent
$children:获取到一个所有子组件(不包含孙子组件)的 VC实例组成的数组,可以拿到子组件中所有数据和方法等$parent:获取到父组件的VC实例,可以拿到父组件中所有数据和方法等// App.vue <Foo></Foo> export default { components: { Foo }, data () { return { name: 'Tom' } }, methods: { sayName () { } }, mounted () { console.log(this.$children[0].age) // 18 console.log(this.$children[0].sayAge) // ƒ sayAge() {} } } // Foo,vue export default { data () { return { age: 18 } }, methods: { sayAge () { } }, mounted () { console.log(this.$parent.name) // 'Tom' console.log(this.$parent.sayName) // ƒ sayName() {} } }provide / inject (依赖注入)
provide:祖先组件向所有后代组件注入依赖inject:在任何后代组件中都可以直接拿来用要注意的是 provide 和 inject 的绑定并不是响应式的,除非传入的就是一个可监听的对象
// App.vue <Foo></Foo> export default { components: { Foo }, data () { return { name: 'Tom' } }, methods: { sayName () { } }, // 对象形式,只能注入自定义数据,因为没有this provide: { constant: 'constant', // sayName: this.sayName, // 找不到 // name: this.name, // 找不到 } // 返回一个对象的函数形式,可以注入data和method等 provide () { return { constant: 'constant', sayName: this.sayName, name: this.name, } } } // Foo.vue export default { inject: ['constant', 'sayName', 'name'], mounted () { console.log(this.constant) console.log(this.sayName) console.log(this.name) } }EventBus
父子、兄弟、跨级组件都可以完成通信
// 事件总线,单独抽取成bus.js import Vue from "vue" const $bus = new Vue() export default $bus // App.vue import $bus from './bus' export default { methods: { handler () { $bus.$emit('sendMsg', 'hello') } }, } // Foo.vue import $bus from '../bus' export default { mounted () { $bus.$on('sendMsg', (msg) => { console.log(msg) }) }, beforeDestroy() { $bus.$off('sendMsg') }, } // 全局事件总线,main.js中注册 // 方法一 import Vue from 'vue' import App from './App.vue' Vue.prototype.$bus = new Vue() // 注册全局事件总线 new Vue({ render: h => h(App), }).$mount('#app') // 方法二 new Vue({ beforeCreate () { Vue.prototype.$bus = this // Vue.prototype.$bus = new Vue() }, render: h => h(App), }).$mount('#app')Vuex
父子、兄弟、跨级组件都可以完成通信
$root
获取当前组件实例所属根组件的实例(main.js),如果当前组件实例没有父实例,则实例将会是它自己
slot
将子组件的数据传给父组件,由父组件决定使用哪些数据
// Foo.vue <slot :age="age"></slot> // App.vue <Foo v-slot="{ age }"> {{ age }} </Foo>
父子组件通信:
- props
- ref
- .sync
- v-model
- $emit / v-on
- $children / $parent
- $attrs / $listeners
- Vuex
兄弟组件通信:
- Vuex
- EventBus
- $parent
跨层级组件通信:
- Vuex
- EventBus
- provide/inject
- $attrs / $listeners
- $root