likes
comments
collection
share

组件间传值&单项数据流

作者站长头像
站长
· 阅读数 26

父组件向子组件传值

子组件的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,控制台就会给出警告

备注

  1. 校验器validator它是一个函数
  2. 函数的参数表示父组件传递过来的值

父组件向子组件传很多值

如果父组件需要向子组件传递很多的值,如果一个个通过动态属性的方式向父组件传值太麻烦了,这时父组件可以向子组件传对象,将父组件需要向子组件传的值写到对象中

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')

备注

  1. 父组件通过属性传值的时候,使用content-abc这种命名
  2. 子组件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
评论
请登录