将介绍 Vue.js 中,父组件和子组件之间 Prop 之间数据流向关系,以及一些注意事项。涉及知识点:
父组件和子组件之间 Prop 的关系
什么是单向下行绑定
子组件试图修改 Prop 的情况
在 Vue.js 中,所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
前面介绍子组件修改 Prop 不会影响父组件的 Prop,因此不建议这么做。但是,也有例外,下面列举了两种常见的试图变更一个 prop 的情形:
(1)这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值,例如:
props: ['initialCounter'], data: function () { return { counter: this.initialCounter } }
(2)这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性,例如:
props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
注意:在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。
该示例定义了一个子组件,且在根组件和子组件均定义了按钮,该按钮用来对 count 加一操作。例如:
<html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue</title> <!-- 使用 CDN 引入 Vue 库 --> <!-- <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> --> <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.9/vue.js"></script> </head> <body> <div id="app"> <h1> count: {{ count }} <button v-on:click="incrParent">count++</button> </h1> <my-component my-title="Hello Vue.js" v-bind:my-count="count"></my-component> </div> <script type="text/javascript"> Vue.component("my-component", { props: { myTitle: String, myCount: Number }, template: ` <div style="background:red;"> <h2>{{myTitle}}</h2> <p>Count: {{myCount}}</p> <p> <button v-on:click="incr">myCount++</button> </p> </div> `, methods: { incr: function(){ this.myCount += 1; } } }); var app = new Vue({ el: "#app", data: { count: 1024 }, methods: { incrParent: function(){ this.count += 1; } } }); </script> </body> </html>
运行效果图:
上图中,当我们点击组件外的按钮增加 count 会影响子组件,而点击子组件内部的按钮增加 count,并不会影响父组件。