组件间传值&单项数据流
父组件向子组件传值
子组件的props用数组接收数据
静态传参
『静』的意思就是固定写死的,因为静态传参一般只能传字符串给子组件
const app = Vue.createApp({
template:`
<div>
<test/>
</div>
`
})
app.component('test',{
template:`<div>test</div>`
})
const vm = app.mount('#root')
这样父组件调用子组件的时候,只能展示内容为test
,现在如果希望在调用子组件的时候,子组件中的内容是自定义的该怎么做?
===> 通过静态属性的方式,将参数传递给子组件,叫『静态传参』
const app = Vue.createApp({
template:`
<div>
<test content="hello world"/>
</div>
`
})
app.component('test',{
props:["content"],
template:`<div>{{content}}</div>`
})
const vm = app.mount('#root')
父组件通过给子组件添加自定义属性content
传值
子组件通过props接收父组件传递过来的值,就可以在模板中使用这个值
这样子组件展示的内容就不是固定的,而是父组件在调用子组件时传递给他什么内容就展示什么内容
动态传参
有的时候,我们可能向子组件传递number类型的“123”,如果用之前静态传参的方式传递数据,得到的数据类型却是字符串,这与需求不匹配
const app = Vue.createApp({
template:`
<div>
<test content="123"/>
</div>
`
})
app.component('test',{
props:["content"],
template:`<div>{{typeof content}}</div>`
})
const vm = app.mount('#root')
这时我们就需要使用动态传参的方式将number类型的数传给子组件
const app = Vue.createApp({
data() {
return {
num: 123
}
},
template:`
<div>
<test v-bind:content="num"/>
</div>
`
})
app.component('test',{
props:["content"],
template:`<div>{{typeof content}}</div>`
})
const vm = app.mount('#root')
『动』的意思就是灵活的,动态传参可以传任意数据类型的数据给子组件,父组件通过v-bind
在子组件上绑定属性content
,并关联父组件中的data向子组件传值,而父组件中的data是灵活的可修改的
传值校验
子组件可以对父组件传递过来的值进行校验,包括值及值的数据类型的校验等
子组件的props使用对象接收
可以传哪些数据类型
- String
- Boolean
- Array
- Object
- Function
- Symbol
简单举几个例子:
1. String类型
const app = Vue.createApp({
data() {
return {
num: 123
}
},
template:`
<div>
<test :content="num"/>
</div>
`
})
app.component('test',{
props:{
content: String
},
template:`<div>{{typeof content}}</div>`
})
const vm = app.mount('#root')
如上面组件test只接收String类型的数据,如果传的是number类型的123,就会警告
2.Function类型
父组件如果给子组件传递的是函数,那么子组件中就可以调用这个传递过来的函数
const app = Vue.createApp({
data() {
return {
num: () => {alert(123)}
}
},
template:`
<div>
<test :content="num"/>
</div>
`
})
app.component('test',{
props:{
content: Function
},
methods:{
handleClick() {
alert("456")
this.content()
}
},
template:`<div @click="handleClick">{{typeof content}}</div>`
})
const vm = app.mount('#root')
额外的校验
子组件除了对父组件传递过来的值的数据类型进行校验外,还可以对其他方面进行校验
1. required
必填
父组件必须向子组件传的属性,否则就会给出警告
const app = Vue.createApp({
data() {
return {
num: 123
}
},
template:`
<div>
<test :content="num"/>
</div>
`
})
app.component('test',{
props:{
content: {
type: Number,
required: true
}
},
template:`<div @click="handleClick">{{typeof content}}</div>`
})
const vm = app.mount('#root')
如果不传父组件不向子组件传递content
属性那么就会给出警告
2. default
默认值
如果父组件不给子组件传属性,那么子组件就会给它一个默认值
如果父组件给子组件传属性,那么组件就会使用props接收父组件这个属性传递过来的值
const app = Vue.createApp({
data() {
return {
num: 123
}
},
template:`
<div>
<test />
</div>
`
})
app.component('test',{
props:{
content: {
type: Number,
default: 456
}
},
template:`<div>{{content}}</div>`
})
const vm = app.mount('#root')
当然默认值不一定只是一个基础数据类型,也可以是一个函数
const app = Vue.createApp({
data() {
return {
num: 123
}
},
template:`
<div>
<test />
</div>
`
})
app.component('test',{
props:{
content: {
type: Number,
default: function() {
return 789
}
}
},
template:`<div>{{content}}</div>`
})
const vm = app.mount('#root')
3. validator
有的时候我们可能对父组件传过来的值有些限制,比如要求传过来的值要小于1000
const app = Vue.createApp({
data() {
return {
num: 1234
}
},
template:`
<div>
<test :content="num"/>
</div>
`
})
app.component('test',{
props:{
content: {
type: Number,
validator: function(value) {
return value < 1000
},
default: function() {
return 789
}
}
},
template:`<div>{{content}}</div>`
})
const vm = app.mount('#root')
如上图所示,如果父组件传递过来的值大于1000,控制台就会给出警告
备注
- 校验器
validator
它是一个函数- 函数的参数表示父组件传递过来的值
父组件向子组件传很多值
如果父组件需要向子组件传递很多的值,如果一个个通过动态属性的方式向父组件传值太麻烦了,这时父组件可以向子组件传对象,将父组件需要向子组件传的值写到对象中
const app = Vue.createApp({
data() {
return {
num: 1234,
a: 456,
b: 789,
c: 666
}
},
template:`
<div>
<test :content="num" :a="a" :b="b" :c="c"/>
</div>
`
})
app.component('test',{
props:['content','a','b','c'],
template:`<div>{{content}} -- {{a}}-- {{b}}-- {{c}}</div>`
})
const vm = app.mount('#root')
运行结果
如果父组件向子组件上传递的值太多,就会导致子组件标签上的内容越来越长
如何解决这个问题呢?
我们可以在data中定义对象params
,将要传的值放到这个对象中以key value的形式
父组件向子组件传递这个对象的时候v-bind="params
const app = Vue.createApp({
data() {
return {
params:{
content: 1234,
a: 456,
b: 789,
c: 666
}
}
},
template:`
<div>
<test v-bind="params"/>
</div>
`
})
app.component('test',{
props:['content','a','b','c'],
template:`<div>{{content}} -- {{a}}-- {{b}}-- {{c}}</div>`
})
const vm = app.mount('#root')
这样也能得到我们想要的结果
备注
<test v-bind="params"/>
等价于
<test :content="params.content" :a="params.a" :b="params.b" :c="params.c"/>
传值的属性名太长?
const app = Vue.createApp({
data() {
return {
content: 1234,
}
},
template: `
<div>
<test :content-abc="content"/>
</div>
`
})
app.component('test', {
props: ['contentAbc'],
template: `<div>{{contentAbc}}</div>`
})
const vm = app.mount('#root')
备注
- 父组件通过属性传值的时候,使用
content-abc
这种命名- 子组件props接收值的时候,使用
contentAbc
驼峰命名
单项数据流
const app = Vue.createApp({
data() {
return {
num: 1,
}
},
template: `
<div>
<counter :count="num"/>
</div>
`
})
app.component('counter', {
props: ['count'],
template: `<div @click="count += 1">{{count}}</div>`
})
const vm = app.mount('#root')
现在想要每次点击子组件中的count的时候,都让从父组件传递过来的数据count加一
运行的时候发现报警告了
意思是子组件中接收的数据count
是『只读的』
单项数据流的概念:
即父组件可以向子组件传递数据,但是父组件传递过来的数据,子组件是不能直接修改的,因为vue中是单项数据流,也就是父组件中的数据可以流向子组件,但是子组件不能反向的修改父组件中数据
那么我们如何才能修改父组件传递过来的数据呢?
==> 我们可以在子组件的data中定义自己的数据(myCount
),将父组件传递过来的数据(count
)复制一份存到子组件自己的data中(myCount = this.count
),,接着就可以对子组件中自己的数据myCount
进行其他的读写操作
const app = Vue.createApp({
data() {
return {
num: 1,
}
},
template: `
<div>
<counter :count="num"/>
</div>
`
})
app.component('counter', {
props: ['count'],
data(){
return {
myCount: this.count
}
},
template: `<div @click="myCount += 1">{{myCount}}</div>`
})
const vm = app.mount('#root')
为什么vue中必须要有『单项数据流』的概念呢?为什么要这么做呢?
那么我们不妨看下如果没有单项数据流,允许子组件直接修改父组件传递过来的数据,看下会发生什么
const app = Vue.createApp({
data() {
return {
num: 1,
}
},
template: `
<div>
<counter :count="num"/>
<counter :count="num"/>
<counter :count="num"/>
</div>
`
})
app.component('counter', {
props: ['count'],
template: `<div @click="count += 1">{{count}}</div>`
})
const vm = app.mount('#root')
如果父组件中同时重复引用三个组件,那么页面中将展示三个计数器
假设现在点击第二个计数器,那么count就会加一
而count是父组件传递过来的数据(父组件自己data中的数据)
第一个子组件和第三个子组件使用的也是父组件的数据
那么第一个子组件和第三个子组件也会跟着加一
那么每个组件之间的数据就会相互的『耦合』,没办法区分开
vue中不允许子组件直接修改父组件传递过来的数据(父组件自己data中定义的数据),这样可以避免组件之间的『数据耦合』,让我们更好的维护数据,也避免出现潜在的bug
转载自:https://juejin.cn/post/7237424021758918713