vue $attrs 父组件和孙子组件的传值,传函数

上一篇我们说到provide/inject的依赖注入的传值方法,今天我们来说一下另一个父组件给孙子组件的传值方式$attrs

我们接着上一个例子继续来写

parent父组件

我们给child子组件穿了四个属性值(title,name,hobby,age

<template>
    <div>
        <button @click="add" >点击增加年龄</button>
        <child :title="title" :name='name' :hobby='hobby' :age='age'/>
    </div>
</template>
<script>
import child from '@/components/child'
export default {
    components:{child},
    data () {
        return {
            title:'自我介绍',
            name:'Tom',
            hobby:'like eat',
            age:4,
        }
    },
    methods:{
        add(){
            this.age ++

        },
    }
}
</script>

child子组件

child子组件使用props来接受,在child组件中引入childChild子组件,并使用v-bind将$attrs绑定在组件上就可在childChild组件中使用props或$attrs接收,按此规律可一直传递。

$attrs打印出来是一个对象,所以我们可以在子组件直接取你想要的数据值{{$attrs.name}}

当然当你的props不是空数组的话,也可以直接用{{name}}

 

<template>
<section>
    <div>我是子组件:{{$attrs}}</div>
    <childChild v-bind="$attrs"/>
</section>
</template>
<script>
import childChild from '@/components/childChild'
export default {
    props:[],
    // props:['name','age'],
    //props:['title','name','hobby','age'],
    components:{
        childChild
    },
    
}
</script>

看上面👆child组件中,我们注释的几个props,props他主要分三个情况,我们可以打印出来看一下

    1.  当child组件的props为[]时,$attrs会打印出所有的对象值

    child组件中:props:[],

             

    2. 当child组件的props为['name','age']时,$attrs会打印出除props里面属性值得对象

    child组件中:props:['name','age'],

    

    3.  当child组件的props为['title','name','hobby','age']时,当把所有的父组件传来的值都写到props的时候,$attrs会打印出空对象

    child组件中:props:['title','name','hobby','age'],

 

  

childChild组件

<template>
    <div>
         <div>我是子组件的组件:{{$attrs}}</div>
         <div>主题:{{$attrs.title}}</div>
         <div>姓名:{{$attrs.name}}</div>
         <div>爱好:{{$attrs.hobby}}</div>
         <div>年龄:{{$attrs.age}}</div>
         
    </div>
</template>

 

当然点击parent父组件的add按钮的时候(增加年龄),孙子组件也是会响应的

那当我们想现在在孙子组件里改变父组件的值,怎么办?$listeners给我们提供了一个思路,

我们只需要现在子组件引入的组件上绑定一个

<childChild v-bind="$attrs" v-on="$listeners"/>

在孙子组件用就$emit方法,这个不多说,相信很多小伙伴都懂了

<template>
    <div>
         <div>我是子组件的组件:{{$attrs}}</div>
         <div>主题:{{$attrs.title}}</div>
         <div>姓名:{{$attrs.name}}</div>
         <div>爱好:{{$attrs.hobby}}</div>
         <div>年龄:{{$attrs.age}}</div>
          <button @click="childChildChangeName" >改名字</button>
    </div>
</template>
<script>
export default {
    inject:['newFoo'],
    methods:{
        childChildChangeName(){
            this.$emit('changeName','Lili')
        }
    }
}
</script>

父组件就可以直接修改值了

<template>
    <div>
        <button @click="add" >点击增加年龄</button>
        <child :title="title" :name='name' :hobby='hobby' :age='age' @changeName='changeName'/>
    </div>
</template>
<script>
import child from '@/components/child'
export default {
    components:{child},
    data () {
        return {
            title:'自我介绍',
            name:'Tom',
            hobby:'like eat',
            age:4,
        }
    },
    methods:{
        add(){
            this.age ++
        },
        changeName(val){
            this.name = val
        }
    }
}
</script>

 

 

$attrs可以传函数吗?

经过测试发现$attrs不仅可以传对应参数,也可以传函数,我们下面以之前的例子说明一下

还是之前的parent父组件, 我们给child组件上传了一个changeName函数,因为组件太多我们暂时就已一代二代来区分子组件

parent父组件

<template>
    <div>
        <button @click="add" >点击增加年龄</button>
        <child :title="title" :name='name' :hobby='hobby' :age='age' :changeName='changeName' @changeTitle='changeTitle'/>
    </div>
</template>
<script>
import child from '@/components/child'
export default {
    components:{child},
    data () {
        return {
            title:'自我介绍',
            name:'Tom',
            hobby:'like eat',
            age:4,
        }
    },
    methods:{
        add(){
            this.age ++
        },
   changeName(val){
            this.name = val
        },
   changeTitle(val){
     this.title = val
     this.name ='张三'    } } }
</script>
第一代组件

下面是我们的child第一代子组件,同时我们也相继的给第二代组件childChild上在传一个函数,后面继续试一下子组件相互修改值

<button @click="$attrs.changeName(data)">一代组件修改父组件值</button>
我们打印出$attrs看一下

<template>
<section>
    <div>我是一代子组件:{{$attrs.title}}</div>
    <div>一代活动名称:{{activity.name}}</div>
    <div>一代活动地点:{{activity.place}}</div>
    <childChild v-bind="$attrs" v-on="$listeners" :changePlace='val => activity.place = val'  />
    <button @click="$attrs.changeName(data)">一代组件修改父组件值</button>
</section>
</template>
<script>
export default {
    data () {
        return {
            data:'小明',
            activity:{
                name:'活动名称',
                date:'活动时间',
                place:'学校'
            },
        }
    },
    props:[],
    // props:['name','age'],
    // props:['title','name','hobby','age'],
    components:{childChild},
    created(){
         console.log(this.$attrs)
    },
    
}
</script>

我们可以看到我们直接在第一点组件中调用$attrs.changeName(),并在里面传了一个定义的data值,修改name为data的‘小明’,点击按钮确实是可以触发,并修改name值,name值作为$attrs传的值,也会一起响应触发修改所有

我们可以看一下页面,name值被修改成功,同时,所有的$attrs值都被重新挂载修改

所以我们也可以不通过$emit来修改父组件的值,可以把函数作为三参数传给$attrs

第二代组件

我们上面给第二代子组件上也传了一个函数,我们这次试一下第三代组件修改第二代组件得值,我们看一下打印出来的数据

我们传的changePlace(),也打印出来了

我们在第二代组件里面又传了一个第三代组件,同时我们也给第三代组件穿了一个函数

childChildChangeName()是我们第三代组件将要执行的的反方法
<template>
    <div>
         <div>我是子组件的组件:{{$attrs}}</div>
         <div>主题:{{$attrs.title}}</div>
         <div>姓名:{{$attrs.name}}</div>
         <div>爱好:{{$attrs.hobby}}</div>
         <div>年龄:{{$attrs.age}}</div>
         <div>二代组件值:{{twoData}}</div>
        <threeChild v-bind="$attrs"  :changeTwoName='childChildChangeName'></threeChild>
    </div>
</template>
<script>
import threeChild from '@/components/threeChild'
export default {
    components:{threeChild},
    data () {
        return {
            twoData:'西游记'
        }
    },
    methods:{
        childChildChangeName(){
            this.$emit('changeTitle','重新自我介绍')
            this.twoData = '水浒传'
            this.$attrs.title = '安居客'//发现没有修改
        }
    }
}
</script>
第三代组件

这是我们第三代组件

我们可以回头看看第一代组件的页面

<childChild v-bind="$attrs" v-on="$listeners" :changePlace='val => activity.place = val'  />

<template>
    <section>
        <div>我是第三代组件:{{$attrs}}</div>
        <button @click="changeOne">三修改一代组件</button>
        <button @click="changeTwo">三修改二代组件</button>
    </section>
</template>
<script>
export default {
    methods:{
        changeOne(){
            this.$attrs.name='数据库打开'//发现不可以
            this.$attrs.changePlace('西校区')
        },
        changeTwo(){
            this.$attrs.changeTwoName()
        }    
    },
    mounted(){
    },
    created(){
         console.log('three',this.$attrs)
    },
}
</script>
我们点击按钮 one ,发现直接修改$attrs的属性值是不奏效的,在调取他的changePlace(),并传入修改的值
我们看一下修改后的页面,点击按钮确实触发了,


我们接着点击two按钮试一下,他调取的是第二组件的方法,第二组建的方法同时又用$emit,去触发了父组件的一个方法,同时也试着修改了该组件的$attrs值

我们可以看上面第二代组件的代码回顾一下

<threeChild v-bind="$attrs"  :changeTwoName='childChildChangeName'></threeChild>
具体方法是
childChildChangeName(){
            this.$emit('changeTitle','重新自我介绍')
            this.twoData = '水浒传'
            this.$attrs.title = '安居客'//发现没有修改
        }
修改的页面如下,我们发现除了直接修改$attrs的值不行,其他都可以,这说明要想修改$attrs的值,只能在传值的父组件中修改,其他的都不可以

 


posted @ 2019-10-25 16:50  吼吼酱  阅读(9399)  评论(0编辑  收藏  举报