单向数据流
一.什么是单向数据流
Vue官方文档解释为:
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
简单来说就是通过prop传递数据时,数据从父组件流向子组件,在子组件中不能修改数据的值,请看一个例子说明:
</html>
<!DOCTYPE html>
<html>
<head>
<title>one-way data flow</title>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app1">
<custom-component :count="1"></custom-component>
</div>
<script type="text/javascript">
Vue.component('custom-component', {
props: ['count'],
template: '<div><input type="button" value="改变count的值" @click="changeCount" />{{count}}</div>',
methods: {
changeCount() {
this.count++;
}
}
});
var testApp = new Vue({
el: '#app1'
});
</script>
</body>
</html>
打开浏览器,显示如下:
按F12调出开发者工具,点击按钮,控制台会显示vue警告,提示错误:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “count”
虽然渲染结果正确,但是vue给我们弹出了警告,所以我们应该遵循单向数据流,不应该在子组件中更改prop的值。
二.如何在子组件中更改prop的值
既然无法在子组件中直接更改父组件中传递的prop值,那么有没有间接的方法呢?答案是Yes。Vue官方文档提供了两种方法:data()属性和computed属性。
1.通过data属性:
</html>
<!DOCTYPE html>
<html>
<head>
<title>one-way data flow</title>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app1">
<custom-component :count="1"></custom-component>
</div>
<script type="text/javascript">
Vue.component('custom-component', {
props: ['count'],
template: '<div><input type="button" value="改变count的值" @click="changeCount" />{{counter}}</div>',
//添加data,注意data在component中必须是一个函数
data(){
return {
counter:this.count
}
},
methods: {
changeCount() {
this.counter++; //改变的是data中返回的counter,而不是改变props中的count值
}
}
});
var testApp = new Vue({
el: '#app1'
});
</script>
</body>
</html>
2.通过计算属性:如果需要显示的值,是以prop值为基础,然后进行改变,可以通过computed属性改变后,然后渲染。
</html>
<!DOCTYPE html>
<html>
<head>
<title>one-way data flow</title>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app1">
<custom-component name="唐维娟"></custom-component>
</div>
<script type="text/javascript">
Vue.component('custom-component', {
props: ['name'],
template: '<span>{{show}}</span>', //这里使用计算属性show,而不是name
computed: {
show() {
return `${this.name}今天又在睡懒觉。`;
}
},
});
var testApp = new Vue({
el: '#app1'
});
</script>
</body>
</html>
渲染结果: