概念
双向数据流:
父组件数据能传递到子组件,子组件接收数据,进行展示;此外子组件可以修改父组件中的数据
双向数据绑定的劣势:
它破环了单向数据流的简洁性, 这增加了分析数据时的难度
不要在子组件中,通过修改引用类型props中的数据,达到“父子组件数据同步”的需求!
这样会让数据流变得更加难以分析
父子之间通信(主要数据逻辑在父级完成)
父->子 : 组件标签上绑定自定义属性,挂载数据,子页面通过props获取
子->父:组件标签上绑定这个自定义事件,子组件中通过$emit('自定义事件'),触发自定义事件
组件通信方式很多
实例如下:
1.父级中
父级内容,子级在当前组件中
//父级数据
data: function() {
return {
data1: '挂载在 组件上的数据 '
}
},
methods: {
changemesfn2handle: function(val) {
console.log(val); //新的数据
this.data1 = '挂载在 组件上的数据 被改变了~~~~~~~~~~~~~~~~ ';
}
}
2.子组件中
我是子组件Mytag
{{parentdata}}
按钮
props: {
parentdata: {
type: String,
default:
'默认值'
}
},
methods: {
changeMes2: function() {
this.$emit("changemesfn2",'新的数据');
}
}
父子之间通信(主要数据逻辑在子级完成)
鉴于组件复用的原理,数据逻辑应该在父级来做操作
1.父级中
子组件直接修改父级
data: function() {
return {
yourdata:'挂载在 组件上的数据'
}
}
2.子组件中
我是子组件Mytag2
{{ fathermes }}
按钮
props: {
fathermes: {
type: String,
default: 'hello'
}
},
methods: {
changesyncfn: function() {
this.$emit('update:fathermes', '数据改变了~~~~~~');
}
}
父子之间通信(子组件在router-view中)
当子元素为router-view中的组件时候
1.父级
{{msg}}
methods: {
changemeshandle: function() {
this.msg = "挂载在的数据 从(子)改变(父)~~~~~~~~~~~~~~~~~~~~~~";
}
}
2.子级router-view
改变父级内容
methods: {
changeMes: function() {
this.$emit("changemesfn");
}
}
父子之间通信(通过v-model的方式传递数据)
v-model是 Vue的一个语法糖,在表单中,主要表现为:
在输入框、文本域中,v-bind:value="数据",v-on:input="事件处理"
在复选框,单选框中,v-bind:checked="布尔值",v-on:change="事件处理"
所以我们也可以借助v-model实现组件的数据传递
1.父组件内
data: function() {
return {
msg1: '我是父级数据~~~~~~~~'
}
}
2.子组件
按钮
...
props: {
value: { //通过value接收数据
type: String,
default:"默认值"
}
},
methods: {
fn1: function() {
this.$emit('input', '数据变化了'); //通过emit发送事件
}
}
组件内快速数据传递
方式1原理:通过根实例作为媒介
vm.emit中的第二个参数
事件可以由vm.$emit触发
通过根实例$emit,$on实现快速通信
1.借助Vue的$root找到根组件上的Vue实例对象
2.通过$root.$emit发布事件,通过$root.$on接收事件
例:
组件1 输入框,添加内容,发送事件
组件2 接收内容,渲染到ul-li列表
1.组件1 (发送新增的内容)
methods: {
addlist: function() {
var _val = this.$refs.input1.value;
this.$root.$emit('addlistfn', _val);
}
}
2.组件2(接收内容,渲染到页面)
列表:
- {{item}}
data: function() {
return {
arr: []
}
},
created() {
var that = this;
this.$root.$on('addlistfn',
function(val) {
that.arr.push(val);
console.log(this) //$parent undefined 根节点的Vue实例
console.log(this.$root == this) //true
console.log(that) //$parent 存在 //当前组件页面的Vue实例
});
}
上面实现的方法是借助于根实例,
另外,也可以通过在入口文件中,对根实例添加插件,Vue原型上增加$eventBus属性,值为new Vue()
使用新的Vue实例来做
在main.js文件中
Vue.use({
install(Vue){
Vue.prototype.$eventBus = new Vue();
}
})
事件总线(event bus)
将上面实现方式中的 $root 替换成 $eventBus 依然是可行的
这种方式的不足
1.操作事件总线中的组件越多,后续调试越麻烦
2.结果没有规则,不可调试
父组件获取子组件中数据 单向数据流
将ref挂载子组件上,父级通过$refs可以查找对应的组件,和上面的数据
ref 被用来给元素或子组件注册引用信息
1.引用信息将会注册在父组件的 $refs 对象上
2.如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素
3.如果用在子组件上,引用就指向组件实例:
因为 ref 本身是作为渲染结果被创建的,在初始渲染的时候你不能访问它们 - 它们还不存在!$refs 也不是响应式的
父组件中
是"{{mess4sondata}}"
data: function() {
return {
mess4sondata: ''
}
},
methods: {
getsondata: function() {
if (this.$refs.sonpage4.sondata) {
this.mess4sondata = this.$refs.sonpage4.sondata
};
}
}
子组件中
子页面的数据:{{sondata}}
data: function() {
return {
sondata: '我是子页面数据'
}
}
祖先传递孙子组件 (provide/inject 单向数据流)
祖辈们传递到孙子辈组件中
provide/inject这对选项需要一起使用,
以允许一个祖先组件向其所有子孙后代注入一个依赖,
不论组件层次有多深,并在起上下游关系成立的时间里始终生效
组先
export default {
name: "new",
provide: {
foo: 'hi'
}
}
孙子辈们组件
{{foo}}
export default {
name: "son1",
inject: {
foo: {
type: String,
default:'默认'
}
}
}
单层父子通信
父级获取子级的属性以及方法
this.$refs.(子级上挂载的ref名).(属性名)
this.$refs.(子级上挂载的ref名).(方法名)
子级获取父级的属性以及方法
this.$parent.(属性名);
this.$parent.(方法名);
多层获取,可以通过不断寻找父级方式,进行封装,如下:
后代传递到祖先(单向数据流)
通过封装函数的方式,核心语法是:
$emit('自定义事件','数据');
$parent
$on('自定义事件',callback);
祖先 App.vue 根实例
created() {
this.$on('aaa', function(val) {
console.log(val); //haha
})
}
祖孙组件
data: function() {
return {
sondata1: 'haha'
}
},
methods: {
sendit: function() {
function dispatch(that, eventName, data) {
let parent = that.$parent //传递this,以便能找到当前实例的$parent
// 循环知道找到根实例
while (parent) {
parent.$emit(eventName, data)
parent = parent.$parent
}
}
//调用函数
dispatch(this, 'aaa', this.sondata1);
}
}