父子通信结合双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn :cnum1="num1" :cnum2="num2"></cpn>
</div>
<template id="cpn">
<div>
<p>{{cnum1}}</p>
<input type="text" v-model="cnum1">
<p>{{cnum2}}</p>
<input type="text" v-model="cnum2">
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
num1: 1,
num2: 0
},
components: {
cpn: {
template: '#cpn',
props: {
cnum1: Number,
cnum2: Number,
}
}
}
});
</script>
</body>
</html>
会残生以下报错:
如下修改
给子组件增加自己的data函数:
data() {
return {
dnum1: this.cnum1,
dnum2: this.cnum2
};
}
然后修改动态绑定的对象
<div>
<p>{{cnum1}}</p>
<input type="text" v-model="dnum1">
<p>{{cnum2}}</p>
<input type="text" v-model="dnum2">
</div>
子向父传递数据正确操作
如果想是实现父组件的num子组件里的的dnum变化,且dum1和dum2存在数量关系。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn :cnum1="num1" :cnum2="num2"
@num1change="num1Change"
@num2change="num2Change">
</cpn>
</div>
<template id="cpn">
<div>
<h2>prpos里的data:{{cnum1}}</h2>
<h2>子组件的data:{{dnum1}}</h2>
<!-- <input type="text" v-model="dnum1">-->
<input type="text" :value="dnum1" @input="dnum1Change">
<h2>prpos里的data:{{cnum2}}</h2>
<h2>子组件的data:{{dnum2}}</h2>
<!-- <input type="text" v-model="dnum2">-->
<input type="text" :value="dnum2" @input="dnum2Change">
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
num1: 1,
num2: 0
},
//父组件定义自己的接受函数
methods: {
num1Change(value) {
this.num1 = parseFloat(value);
},
num2Change(value) {
this.num2 = parseFloat(value);
},
},
components: {
cpn: {
template: '#cpn',
props: {
cnum1: Number,
cnum2: Number,
},
data() {
return {
dnum1: this.cnum1,
dnum2: this.cnum2
};
},
methods: {
dnum1Change(event) {
this.dnum1 = event.target.value;
//发射函数,将改变后的子组件数据dnum1传给父组件
this.$emit('num1change', this.dnum1);
//同时修改dum2的值为num1的100倍
this.dnum2 = this.dnum1 * 100;
this.$emit('num2change', this.dnum2);
},
dnum2Change(event) {
this.dnum2 = event.target.value;
//发射函数,将改变后的子组件数据dnum2传给父组件
this.$emit('num2change', this.dnum2);
//同时修改dum1的值为num2的100倍
this.dnum1 = this.dnum2 * 100;
this.$emit('num1change', this.dnum1);
}
}
}
}
});
</script>
</body>
</html>
上边说了,动态绑定不能是prpos里的变量,否则,子组件直接可以修改父组件,这里又要父组件跟着子组件数据修改,这不矛盾吗?
这其实不矛盾,这里父组件的数据修改,还是通过父组件自己的函数来修改自己,而不是直接由子组件行为来修改,我可以修改,但是必须是你子组件告诉我修改啥,我父组件自己修改,而不是你直接来给我修改。
具体步骤
1.拆分双向绑定为数据绑定和事件绑定
<div>
<h2>prpos里的data:{{cnum1}}</h2>
<h2>子组件的data:{{dnum1}}</h2>
<input type="text" :value="dnum1" @input="dnum1Change">
<h2>prpos里的data:{{cnum2}}</h2>
<h2>子组件的data:{{dnum2}}</h2>
<input type="text" :value="dnum2" @input="dnum2Change">
</div>
将v-model拆分为动态绑定 子组件data和输入框数据修改事件。
拆开的目的是因为我们要获取到子组件的实时数据,子组件的实时数据是输入框的value给的。如果直接使用v-model,发送出子组件实时data的步骤无法触发。我们没有地方来编写这个事件。
methods: {
dnum1Change(event) {
this.dnum1 = event.target.value;
//发射函数,将改变后的子组件数据dnum1传给父组件
this.$emit('num1change', this.dnum1);
//同时修改dum2的值为num1的100倍
this.dnum2 = this.dnum1 * 100;
this.$emit('num2change', this.dnum2);
},
dnum2Change(event) {
this.dnum2 = event.target.value;
//发射函数,将改变后的子组件数据dnum2传给父组件
this.$emit('num2change', this.dnum2);
//同时修改dum1的值为num2的100倍
this.dnum1 = this.dnum2 * 100;
this.$emit('num1change', this.dnum1);
}
}
}
事件函数有一个参数,调用时省略,会默认将事件event作为参数给这个形参。
如果没有参数,想调用,就是用$event来调用。
我们需要得到实时的输入框数据给子组件数据,同时为了修改父组件数据,那必须要让父组件知道,$emit发射出一个函数,带有子组件data值。
引号内是方法名,后边是参数。方法名是用来绑定父组件的方法的,
2。父组件自己的函数接受子组件的函数和参数。
//父组件定义自己的接受函数
methods: {
num1Change(value) {
this.num1 = parseFloat(value);
},
num2Change(value) {
this.num2 = parseFloat(value);
},
},
<cpn :cnum1="num1" :cnum2="num2"
@num1change="num1Change"
@num2change="num2Change">
</cpn>
这里父组件的函数定义一个参数是为了接受子组件传递的参数,直接调用不传参数,不会获取event事件。
类型必须转换,传过来的数字会被当成字符串,要转换回来
3.方法可以复用。
dnum1Change(event) {
this.dnum1 = event.target.value;
//发射函数,将改变后的子组件数据dnum1传给父组件
this.$emit('num1change', this.dnum1);
//同时修改dum2的值为num1的100倍
this.dnum2 = this.dnum1 * 100;
this.$emit('num2change', this.dnum2);
},
同时可以发送两个或多个方法出去,但是他们方法名和参数一样时,可以复用。同样的num2change既可以接受
this.dnum2 = event.target.value;
//发射函数,将改变后的子组件数据dnum2传给父组件
this.$emit('num2change', this.dnum2);
又可以接收
//同时修改dum2的值为num1的100倍
this.dnum2 = this.dnum1 * 100;
this.$emit('num2change', this.dnum2);
更一步说明了发射函数第一个参数会被创建成方法,不同地方发射函数的参数相同,会被当成同一方法,
总结
所谓动态绑定属性和事件的监听:不过是将一个自定义/系统定义的属性/方法名与另外一个自定义的属性/方法动态联系起来。一定是对应关系,一个属性与另一个属性,一个方法与另一个方法。语法糖可能省略。
等号后边的引号并不代表其是一个字符串,而是将其当作变量或方法名的标志。不要见到引号路边的就是字符串。
如果要实现响应式,就必须发生关联,这也就是动态绑定的目的。
何为系统定义属性/方法(事件):
:value="dnum1" @input="dnum1Change"
何为自定义的属性/方法(事件)
:cnum1="num1" :cnum2="num2" @num1change="num1Change" @num2change="num2Change"
我们绑定点击事件,是为了系统知道,触发点击事件,执行等号后边的方法。
绑定自定义方法也是一样的。
@click="btn01Click"
父子通信时方法名不要用驼峰命名,切记,否则不报错,就是不正确执行,在vue.js使用中,而不是脚手架中。
watch属性简写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch</title>
</head>
<body>
<div id="app">
<cpn :cnum1="num1" :cnum2="num2"
@num1change="num1Change"
@num2change="num2Change">
</cpn>
</div>
<template id="cpn">
<div>
<h2>prpos里的data:{{cnum1}}</h2>
<h2>子组件的data:{{dnum1}}</h2>
<input type="text" v-model="dnum1">
<h2>prpos里的data:{{cnum2}}</h2>
<h2>子组件的data:{{dnum2}}</h2>
<input type="text" v-model="dnum2">
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
num1: 1,
num2: 0
},
//父组件定义自己的接受函数
methods: {
num1Change(value) {
this.num1 = parseFloat(value);
},
num2Change(value) {
this.num2 = parseFloat(value);
},
},
components: {
cpn: {
template: '#cpn',
props: {
cnum1: Number,
cnum2: Number,
},
data() {
return {
dnum1: this.cnum1,
dnum2: this.cnum2
};
},
watch: {
dnum1(newValue) {
//同时修改dum2的值为dnum1实时数据的的100倍
this.dnum2 = newValue * 100;
/*同时将dnum1的实时数据发送出去*/
this.$emit('num1change', newValue);
},
dnum2(newValue) {
//同时修改dum1的值为num2的100倍
this.dnum1 = newValue / 100;
this.$emit('num2change', newValue);
}
}
}
}
});
</script>
</body>
</html>
一旦观察的变量(键)发生变化,就会执行回调函数(值),很容易实现。
要注意的是,你想把什么东西发送出去,你目前得到的是什么数据。
可以有两个参数:newValue , oldVlue,默认只用写一个参数,获取实时的新值,也可以有俩个。