由于组件 HelloVue 中 data 里的数据 str 是固定的,所以页面上显示的时候内容就是一样的:
而实际开发中,复用的组件里显示的内容往往是不同的,比如下面的图片中显示的每个文章介绍其实用的是一个组件,但是每个介绍的内容却是不同的,这就需要从父组件中传递不同的内容给子组件。
那么如何从父组件中把内容传给子组件呢?
prop 的使用方法
基础使用
当父组件给子组件的 prop 传递一个值的时候,这个值就变成了子组件实例的一个属性。
现在我们给 HelloVue 组件传递一个标题:
- 父组件中,传一个 title 给子组件:
<template>
<div id="app">
<!-- 注意!title1 和 title2 是父组件的 data 中定义的数据,title 则是子组件中接收数据时的变量名 -->
<HelloVue :title="title1"></HelloVue>
<HelloVue :title="title2"></HelloVue>
</div>
</template>
有两点需要注意一下:
-
title1 和 title2 是父组件的 data 中定义的数据,而 title 则是子组件中接收数据时的变量名;
-
因为 title1 和 title2 是变量,所以 title 前需要加
如果不加 :,那么在子组件中收到的 title 值就是 “title1” 和 “title2”。2.子组件中,用 prop 接收 title:
<template>
<div class="hello">
<!-- 第二步:在页面上显示 title 的值,写法和显示 data 里定义的数据一样 -->
<h1>{{ title }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloVue',
// 第一步:在 prop 属性中接收 title
props: ['title']
};
</script>
注意,在子组件中 prop 属性的写法,因为传过来的值可能不止一个,因此这里是个数组,其中的每一项均为传过来的值的名称。
上面这种写法没有声明所传值的类型,如果要声明类型可以参看进阶使用方法。
进阶使用:附带类型声明
我们可以用下面的写法给值声明类型,类型首字母要大写:
<script>
export default {
name: 'HelloVue',
// 在 prop 属性中接收 title,其类型为 String
props: {
title: String
}
};
</script>
这里 prop 是一个对象,当传入的值有多个的时候,可以用逗号隔开,还可以用下面的写法给值设置一些要求:
props: {
title: String,
// 多类型
likes: [String, Number],
// 带有默认值
isPublished: {
type: Boolean,
default: true
},
// 必填
commentIds: {
type: Array,
required: true
},
author: Object,
callback: Function,
contactsPromise: Promise
}
从上面的示例中,我们知道了怎么通过 prop 实现父到子的数据传递,那么能不能用 prop 实现子到父的数据传递呢?
答案是,不能。现在就来解释一下什么叫“单向数据流”。
单向数据流
单向数据流指的是父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
这样可以防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
简单来说:
- prop 可以实现父到子的数据传递;
- 父组件中的数据变化,会通过 prop 传递到子组件;
- 子组件不能直接修改父组件通过 prop 传递过来的数据;
但实际开发中常会遇到传到子组件中的数据需要处理后才能使用的情况,比如排序、格式化等,这时候怎么办呢?
1. prop 传入的数据需要处理
这时我们就可以用前面提到的计算属性对数据进行处理:
props: ['initialTitle'],
computed: {
normalizedTitle: function () {
// 对传入的 initialTitle 进行去空格、字母小写化处理
return this.initialTitle.trim().toLowerCase()
}
}
2. prop 传入的数据作为本地数据使用
如果想将 prop 传递的初始值作为一个本地数据使用,可以定义一个本地的 data 属性并将这个 prop 用作其初始值:
props: ['initialTitle'],
data: function () {
return {
// 要读取 prop 里的 initialTitle,要在前面加 “this.”
// 将传入的 initialTitle 作为本地属性 title 的初始值
title: this.initialTitle
}
}
接下来可以直接修改 title,而不必改变父组件的 initialTitle。
在某些情况下,我们还可以通过自定义事件,调用父组件中定义的方法,在父组件中修改数据,然后让数据的更新自动向下流动到子组件中。“自定义事件”这个概念会在后面讲解。