一、父组件传递参数给子组件
-
1、父组件传递参数
<template> <div> <Son1 :name="name" :age="20" :bookList="['三国演义', '西游记']" :details="{'name': '张三', address: '广东深圳'}" :isActive="false" /> </div> </template>
-
2、在子组件中定义接收
<template> <div> <hr /> <h3>我是子组件</h3> <p>{{name}}</p> <p>{{age}}</p> <p>{{bookList}}</p> <p>{{details}}</p> <p>{{isActive}}</p> </div> </template> <script> export default { name: 'son1', props: { name: { type: String, default: '', }, age: { type: Number, default: 0, }, bookList: { // 如果是对象或者数组必须使用下函数生成的方式 type: Array, default: () => [], }, details: { type: Object, default: () => ({}), }, isActive: { type: Boolean, default: false, }, }, mounted() { console.log(this); }, }; </script> <style scoped></style>
二、子组件修改父组件传递的数据
由于
vue
属于单向数据流,子组件中不直接修改父组件的数据,而是在组件触发事件或者派发通知到父组件,通知父组件修改数据,父组件数据被修改了,传递到子组件中,子组件的数据也被修改了。
方式一、直接在子组件中定义方法,然后通过emit
发出一个事件到父组件中修改(类似回调函数的方式)
-
1、在子组件中
<template> <div> <hr /> <h3>我是子组件</h3> <p>{{name}}</p> <button @click="change">修改</button> </div> </template> <script> export default { name: 'son1', props: { name: { type: String, default: '', }, }, mounted() { console.log(this); }, methods: { change() { // 对父组件派发一个change事件 this.$emit('change', '哈哈,我是子组件过来的'); }, }, }; </script> <style scoped></style>
-
2、在父组件中使用,然后修改数据
<template> <div> <!--在父组件中使用change事件--> <Son1 :name="name" @change="change" /> </div> </template> <script> import Son1 from './Son1'; export default { name: 'parent1', data() { return { name: '哈哈', }; }, methods: { change(value) { this.name = value; }, }, mounted() { console.log(this); }, components: { Son1, }, }; </script> <style scoped></style>
方式二、子组件中派发的事件名称叫input:value
(和方式一一样的)
-
1、子组件中
// 子组件中派发一个input:value的事件给父组件 this.$emit('input:value', '?哈哈');
-
2、父组件中
html <template> <div> <!--父组件接收子组件的input:value事件--> <Son1 :name="name" @input:value="change"></Son1> <!-- 或者直接将函数写在行间 <Son1 :name="name" @input:value="(val)=>this.name=val" ></Son1> --> </div> </template> <script> import Son1 from './Son1'; export default { name: 'parent1', data() { return { name: '哈哈', }; }, methods: { change(value) { this.name = value; }, }, mounted() { console.log(this); }, components: { Son1, }, }; </script> <style scoped></style>
方式三、使用修饰符sync
数据同步,注意点:子组件必须派发的是update:属性
事件
-
1、子组件中派发的事件名称
<template> <div> <h1> 我是子组件内容 </h1> <button @click="change1">使用sync的方式</button> </div> </template> <script> export default { methods: { change1() { this.$emit('update:name', '?哈哈'); }, }, }; </script>
-
2、父组件中
<template> <div> <!-- 使用的方式一 --> <Son1 :name="name" @update:name="(val)=>this.name=val"></Son1> <!-- 使用的方式二 --> <Son1 :name.sync="name"></Son1> </div> </template>
方式四、子组件中接收的是value
属的时候,派发的事件是input
-
1、子组件
<template> <div> <hr /> <h3>我是子组件</h3> <p>{{value}}</p> <button @click="change">修改</button> </div> </template> <script> export default { name: 'son1', props: { value: { // 必须是value属性 type: String, default: '', }, }, mounted() { console.log(this); }, methods: { change() { // 发送的事件也是定死的input this.$emit('input', '哈哈,我是子组件过来的'); }, }, }; </script> <style scoped></style>
-
2、父组件中
<template> <div> <Son1 :value="name" @input="(val)=>this.name=val"></Son1> <!-- 可以进一步简写成这样 --> <Son1 v-model="name"></Son1> </div> </template> <script> import Son1 from './Son1'; export default { name: 'parent1', data() { return { name: '哈哈', }; }, }; </script>
三、孙组件修改父父组件的数据
主要的思路是孙组件派发事件通知父组件修改数据,父组件派发事件通知父组件修改
方式一、孙组件中使用$parent.$emit
派发事件
-
1、孙组件
... changeVal () { this.$parent.$emit('input', '孙组件修改的'); }, changeAge () { this.$parent.$emit('changeAge', 40); } ...
-
2、父组件
<template> <div> <hr /> <h3>我是子组件</h3> <p>{{value}}==={{age}}</p> <hr /> <h3>孙组件</h3> <Grandson1 :value="value" :age="age" /> </div> </template> <script> import Grandson1 from './Grandson1'; export default { name: 'son1', props: { value: { type: String, default: '', }, age: { type: Number, default: 0, }, }, methods: {}, components: { Grandson1, }, }; </script> <style scoped></style>
-
3、父父组件
<template> <div> <Son1 v-model="name" :age="age" @changeAge="val => this.age = val"></Son1> </div> </template>
方式二、使用自己扩展到Vue
原型上的$dispatch
方法
-
1、扩展方法
import App from './App'; import Vue from 'vue'; Vue.prototype.$dispatch = function(eventName, value) { let parent = this.$parent; // 循环递归派发事件 while (parent) { parent.$emit(eventName, value); parent = parent.$parent; } }; const vm = new Vue({ el: '#app', render: (h) => h(App), });
-
2、孙组件中使用
... methods: { changeVal () { this.$dispatch('input', '孙孙组件修改的') }, changeAge () { this.$dispatch('changeAge', 40) } }, ...
-
3、父父组件中
<Son1 v-model="name" :age="age" @changeAge="val => this.age = val"></Son1>
四、自定义广播
类似
angularjs
中的广播,其实也就是一个发布者与订阅者的关系,发布一个消息,订阅的组件就执行
-
1、在
main.js
中扩展方法Vue.prototype.$broadcast = function(enevtName, value) { // 递归查找全部的子组件 const broadcast = (children) => { children.forEach((child) => { child.$emit(enevtName, value); if (child.$children) { broadcast(child.$children); } }); }; broadcast(this.$children); };
-
2、组件中订阅广播
<template> <div> <Grandson1 :value="value" :age="age" @say="say" /> </div> </template> <script> ... methods: { say (val) { console.log(`我是孙组件中的广播,接收的消息是:${val}`) } }, ... </script>
-
3、发出一个广播通知
... mounted () { this.$broadcast('say', '放假了'); }, ...