父组件 → 子组件
- 父组件中,给子组件标签元素设置自定义属性
attrKey="attrVal" ,[属性值 attrVal ] 为需要传递的数据 子组件中,给组件实例设置 props 属性,属性值包含父组件给子组件标签元素设置的自定义 [属性名 attrKey ] 实现:父组件给子组件传递数据 props 可以是 [数组式写法] / [对象式写法] [对象式写法] 允许高级配置,eg:类型检测、默认值、自定义验证…
数组式写法
props 的属性值为数组时,其元素为父组件给子组件标签元素设置的自定义 [属性名 attrKey ] 注意:属性名 attrKey 不要用驼峰命名法,因为 html 代码不区分大小写
<template>
<div>
<Son name="superman" age="21" />
</div>
</template>
<script>
import Son from "./components/Son.vue";
export default {
name: "App",
components: { Son },
};
</script>
<template>
<div>
<h2>姓名: {{ name }}</h2>
<h2>年龄: {{ age }}</h2>
</div>
</template>
<script>
export default {
name: "Son",
props: ["name", "age"],
};
</script>
- 可以传递各种数据类型:① String、② Number、③ Boolean、④ Symbol、⑤ Date、 ⑥ Array、⑦ Object、⑧ Function
对象式写法(推荐)
props 的属性值为对象时,该对象的属性名为父组件给子组件设置的自定义 [属性名 attrKey ];属性值为配置对象 注意:属性名 attrKey 不要用驼峰命名法,因为 html 代码不区分大小写
① 修改父组件的模版:
<template>
<div>
<Son name="superman" :age="21" />
</div>
</template>
② 修改子组件的脚本:
<script>
export default {
name: "Son",
props: {
name: {
type: String,
require: true,
},
age: {
type: Number,
default: 18,
},
},
};
</script>
props: {
name: String,
age: Number,
},
- 默认值为 [对象 Object] / [数组 Array] / [函数 Function] 时,必须通过工厂函数获取
- 可以通过
validator 函数自定义限制条件
① 修改父组件模版:
<div>
<Son name="superman" />
</div>
② 修改子组件脚本:
props: {
name: {
type: String,
require: true,
validator(val) {
console.log("val", val);
return val == "superman";
},
},
age: {
type: [Number, Object],
default() {
return {
realAge: 81,
showAge: 18,
};
},
},
},
渲染问题(单向数据流)
- 父组件的数据更新时,子组件接收到的对应的数据也会被更新
- 因此,我们不可以在子组件中修改
props 传递过来的数据。否则:
- 控制台会发出警告(子组件中显示的数据还是会改变
- 一旦父组件的数据更新,子组件接收的对应数据也会被更新
- 总之,父组件数据的更新会向下传递至子组件,但子组件不能更新父组件中的数据
<template>
<div>
<h1>{{ showApp() }}</h1>
<button @click="num++">修改 age</button>
<hr />
<Son :age="num" />
</div>
</template>
<script>
import Son from "./components/Son.vue";
export default {
name: "App",
components: { Son },
data() {
return { num: 21 };
},
methods: {
showApp() {
console.log("showApp");
return "App";
},
},
};
</script>
<template>
<div>
<h2>{{ showSon() }}</h2>
<h2>年龄: {{ age }}</h2>
<button @click="age++">修改 age</button>
</div>
</template>
<script>
export default {
name: "Son",
props: ["age"],
methods: {
showSon() {
console.log("showSon");
return "Son";
},
},
};
</script>
在子组件中 修改父组件传递过来的数据:控制台抛出警告、子组件的数据可以被成功修改、重新渲染子组件 参与子组件数据显示的方法 showSon ,在页面完成时被调用一次;子组件修改数据后,重新渲染子组件,被调用一次
此时我们再在父组件中修改原数据,则子组件的数据也会被修改,就是说,子组件之前修改的数据会被覆盖 参与页面数据显示的方法 showApp 、showSon ,在页面完成时依次被调用一次;父组件修改数据后,页面重新渲染,再依次被调用一次
- 如果非得在子组件中获取并修改父组件传递的数据,我们可以将
props 中的数据赋值到 data 中 此时我们操作的,其实就是子组件自己的数据啦
<template>
<div>
<h2>{{ showSon() }}</h2>
<h2>年龄: {{ sonAge }}</h2>
<button @click="sonAge++">修改 sonAge</button>
</div>
</template>
<script>
export default {
name: "Son",
data() {
return { sonAge: this.age };
},
props: ["age"],
methods: {
showSon() {
console.log("showSon");
return "Son";
},
},
};
</script>
此时,子组件渲染的是 data 中的数据 sonAge 更新子组件 data 中的数据,子组件会被重新渲染、showSon 被调用 更新父组件的数据,父组件会被重新渲染、showApp 被调用;此时子组件不会被重新渲染
注意:自己的数据不要与接收的数据同名,否则会报错(页面会优先显示 props 的数据
引用类型数据
- 因为是赋值处理,所以传递引用类型数据要特别注意,因为引用类型的数据操作的是地址
此时,传递的是父组件的数据的引用;就是说,父子组件操作的是同一数据
<template>
<div>
<h1>{{ showApp() }}</h1>
<button @click="sonObj.num++">修改 age</button>
<hr />
<Son :ageObj="sonObj" />
</div>
</template>
<script>
import Son from "./components/Son.vue";
export default {
name: "App",
components: { Son },
data() {
return { sonObj: { num: 21 } };
},
methods: {
showApp() {
console.log("showApp");
return "App";
},
},
};
</script>
<template>
<div>
<h2>{{ showSon() }}</h2>
<h2>年龄: {{ ageObj.num }}</h2>
<button @click="ageObj.num++">修改 ageObj</button>
</div>
</template>
<script>
export default {
name: "Son",
props: ["ageObj"],
methods: {
showSon() {
console.log("showSon");
return "Son";
},
},
};
</script>
可以发现,页面初始化时,showApp 、showSon 依次被调用 不论在子组件还是在父组件中修改数据,都能成功修改数据、并重新渲染子组件模版,showSon 被调用
子组件 → 父组件
父组件给子组件传递函数,子组件给函数传入参数,从而实现子组件给父组件传递数据
- 通过自定义属性,父组件给子组件传递函数
- 子组件通过
props 属性接收该函数 - 在调用该函数时,传入数据作为参数
- 父组件就能 [以参数的形式] 接收到子组件传递过来的数据
<template>
<div>
<p>父组件数据:{{ msg }}</p>
<hr />
<Son :parentFun="parentFun" />
</div>
</template>
<script>
import Son from "./components/Son.vue";
export default {
name: "App",
components: { Son },
data() {
return { msg: "father" };
},
methods: {
parentFun(val) {
console.log("val", val);
this.msg += val;
},
},
};
</script>
<template>
<div class="son">
<button @click="parentFun(sonMsg)">
点击将子组件的数据传递给父组件
</button>
</div>
</template>
<script>
export default {
name: "Son",
props: ["parentFun"],
data() {
return { sonMsg: "son" };
},
};
</script>
|