文章结构
父组件怎么发送数据
父组件给子组件传递数据,发送者就是父组件,那么怎么发送数据给子组件呢?
步骤
1、引入:在父组件中引入子组件
2、挂载:components中挂载
3、传值:通过键值对的形式书写在子组件身上(注意:传递js表达式(常量,变量,数字,
对象,数组),要加:冒号。不加的话,vue模板解析会认为是一个字符串)
<template>
<div>
<!-- 3、传递 -->
<Son
name="张三"
:age="18"
:hobby="['吃饭', '睡觉', '打豆豆']"
:lover="{ name: '李四', age: 18 }"
noProp="noProp"
></Son>
</div>
</template>
<script>
// 1、引入
import Son from "./components/Son.vue";
export default {
name: "App",
// 2、挂载
components: {
Son,
},
};
</script>
<style>
</style>
子组件怎么接收?
父组件已经传递值了,那么子组件怎么接收呢?
有两种接收方式:
1、数组的形式(简单接收)
2、对象的形式(复杂接收,可以设置类型校验,默认值,是否必传,以及自定义校验规则)
简单接收
<template>
<div>
<div>Son组件</div>
<div>{{ name }}</div>
<div>{{age}}</div>
<div>{{hobby}}</div>
<div>{{lover}}</div>
<div>{{variable}}</div>
</div>
</template>
<script>
export default {
name: "web-son",
// 简单接收
props: ["name", "age", "hobby", "lover", "variable"],
};
</script>
<style scoped>
</style>
顺利接收
复杂接收
<template>
<div>
<div>Son组件</div>
<div>{{ name }}</div>
<div>{{ age }}</div>
<div>{{ hobby }}</div>
<div>{{ lover }}</div>
<div>{{ variable }}</div>
</div>
</template>
<script>
export default {
name: "web-son",
props: {
name: String,
age: Number,
hobby: {
// 允许传递多种数据类型
type: [Array, Object],
},
lover: {
type: Object,
// 必须传值
required: true,
},
variable: {
type: String,
// 父组件不传这个数据,那么这个值的默认值就为default的内容
default: "我是默认值",
// 自定义校验函数,返回值为true则校验通过,否则不通过
validator: function(value){
// value为父组件传递的值
// 常用的场景,封装组件库时,规定这个props值只能是哪些值
return ["变量","我是默认值"].indexOf(value) != -1
}
},
/* 说明:一般required和default不一块使用,因为没有啥
意义,必传就一定用不上默认值 */
},
};
</script>
<style scoped>
</style>
顺利接收
不满足校验规则的一些报错信息(常见于用开源ui组件库时)
数据类型不对
当类型为String的name,我传入一个数字12时,报错翻译过来就是无效的prop类型检验
失败,应该传入一个字符串,但是12是一个数字
必传未传
这个报错就比较容易理解了,丢失了一个必传的prop "lover"
自定义校验函数未通过
当我给variable传入一个"变量2",报错信息为,对prop值variable自定义校验函数失败
props接收的值存在哪?
为什么我们按照这种方式传值之后,可以直接在组件中通过this.xxx访问到呢?
我们打印一下当前的组件VueComponent对象查看一下
mounted(){
console.log(this);
}
可以发现,vue直接从_props中将这些属性添加到了当前的组件实例身上,所以我们才能
通过this.xxx访问得到。
父组件传了,子组件props未声明接收,值去哪了?
认真阅读的读者发现了,我在父组件中传的noProp字符串,怎么没在子组件中接收呢?
它们去哪了呢?其实vue对于这种情况也做了处理。vue将变量(传了但是props未接收的),
就会被放在vue组件实例.$attrs身上,它和$listeners属性牵扯到vue2另外一种组件通信,
后续将在专栏中补充,这两个属性在封装ui组件库,在进行多代关系的组件通信时十分有用
为什么不建议子组件修改props?
从之前打印的实例对象发现,实例对象身上并没有与之对应get和set方法。(_props对象
上有)并且如果我们直接通过this.xxx = ?修改props的值,vue会报错。eslint代码检验
也会报错。如果通过this._props.xxx = ?修改props的值,可以修改成功,但是根据vue的数据流,子组件虽然更改了值,由于数据是从父组件来的,父组件的值并没有被修改,因此子组件重新渲染的时候,值依然是父组件中的值。并且如果你这么做,谷歌浏览器控制台也会弹出warn
想要修改props的值怎么办?
从之前控制台的warn可以发现,vue官方给予我们提示了,你可以使用data或者computed
来复制一份props中的值,然后再进行修改以及后续业务逻辑的处理。(补充:根据vue源
码得知,props的加载顺序在data和computed之前,因此在data或computed中访问props
中的值不会是undefined)
data() {
return {
sonName: this.name + "son",
};
},
computed: {
sonName2() {
return this.name + "son";
},
},
.sync修饰符
当给子组件传递一个值时,使用.sync修饰,会给子组件的消息发布与订阅的消息队列添加
一个update:变量名。代码演示。
App.vue
<template>
<div>
<!-- 3、传递 -->
<Son
...
:page.sync="page"
></Son>
<div>father-page:{{page}}</div>
</div>
</template>
<script>
// 1、引入
import Son from "./components/Son.vue";
export default {
name: "App",
data() {
return {
...
page: 1
};
},
// 2、挂载
components: {
Son,
},
};
</script>
<style>
</style>
Son.vue
mounted() {
...
this.$emit("update:page",2);
},
完整代码
App.vue父组件
<template>
<div>
<!-- 3、传递 -->
<Son
name="张三"
:age="18"
:hobby="['吃饭', '睡觉', '打豆豆']"
:lover="{ name: '李四', age: 18 }"
:variable="variable"
@clg="
{
() => {
console.log();
};
}
"
noProp="noProp"
:page.sync="page"
></Son>
<div>father-page:{{page}}</div>
</div>
</template>
<script>
// 1、引入
import Son from "./components/Son.vue";
export default {
name: "App",
data() {
return {
variable: "变量",
page: 1
};
},
// 2、挂载
components: {
Son,
},
};
</script>
<style>
</style>
Son.vue子组件
<template>
<div>
<div>Son组件</div>
<div>{{ name }}</div>
<div>{{ sonName }}</div>
<div>{{ sonName2 }}</div>
<div>{{ age }}</div>
<div>{{ hobby }}</div>
<div>{{ lover }}</div>
<div>{{ variable }}</div>
</div>
</template>
<script>
export default {
name: "web-son",
data() {
return {
sonName: this.name + "son",
};
},
computed: {
sonName2() {
return this.name + "son";
},
},
props: {
name: String,
age: Number,
hobby: {
// 允许传递多种数据类型
type: [Array, Object],
},
lover: {
type: Object,
// 必须传值
required: true,
},
variable: {
type: String,
// 父组件不传这个数据,那么这个值的默认值就为default的内容
default: "我是默认值",
// 自定义校验函数,返回值为true则校验通过,否则不通过
validator: function (value) {
// value为父组件传递的值
// 常用的场景,封装组件库时,规定这个props值只能是哪些值
return ["变量", "我是默认值"].indexOf(value) != -1;
},
},
/* 说明:一般required和default不一块使用,因为没有啥
意义,必传就一定用不上默认值 */
},
mounted() {
console.log(this);
// this.name="zhangsan";
// this._props.name = "zhangsan";
this.$emit("update:page",2);
},
};
</script>
<style scoped>
</style>