Vue组件传值、refs、插槽

一、组件传值

1.父组件向子组件传值

因为子组件本身不能拿到父组件的data数据来用,所以在子组件里用props接收,props是一个数组

父组件向子组件传值
<div >
    <com1 :parent="msg" :parentarr="arr"></com1>
</div>
<template >
    <div>
        {{parent}}
        <ul>
            <li v-for="i in parentarr">{{i}}</li>
        </ul>
    </div>
</template>
<script src="lib/vue-2.4.0.js"></script>
<script type="text/javascript">            
var vm=new Vue({
    el:"#app",
    data:{
        msg:"父组件的msg",
        arr:[1,2,3],
    },
    components:{
        com1:{
            template:"#com",
            props:["parent",'parentarr'],//父组件向子组件传值,用props    
        }
    }
})
</script>

2.子组件向父组件传值

子组件不能直接使用父组件的data和methods,子组件向父组件传值用 @和$emit实现(通过函数的形式传出,在父组件接收)

做法:

在父组件里定义一个@xxx="xxx2"的方法,父组件把方法传递给子组件,this.$emit()的第一个参数和xxx的名称一样,父元素的方法xxx2传一个实参进去就相当于是当前传回来的值

this.$emit("fun1",this.xxx) 方法名字/要传出的值

子组件向父组件传值
<div >
    <com-name @fun1="getData"></com-name>
</div>

<template >
    <div>
        <button @click="getsonData">调用父组件的getdata</button>
    </div>
</template>
<script src="lib/vue-2.4.0.js"></script>
<script type="text/javascript">
var vm=new Vue({
    el:"#app1",
    data:{
        fromson:""
    },
    methods:{
        getData(x){//传实参
            console.log("父元素的方法getdata拿到子组件里的数据是==="+x)
            this.fromson=x;
        }
    },
    components:{
        comName:{
            template:"#com2",
            data(){
                return {
                    sonmsg:"子组件里的msg"
                }
            },
            methods:{
                getsonData(){
                    this.$emit("fun1",this.sonmsg)//$emit调用fun1
                }
            }
        },
        
    }
})
</script>

二、refs获取dom节点

Vue不提倡用原生的dom操作获取节点,它封装了自己的方法来实现获取dom

做法:

给要获取的dom一个ref属性,起一个名字,通过this.$refs来得到组件里所有有ref属性的dom节点,返回的是一个json

<div >
   <p ref="p1">父组件里的p</p>
   <button @click="getCon">获取内容</button>
   <com ref="login"></com>
</div>
<template >
    <div>
        <p>{{sonmsg}}</p>
    </div>
</template>
<script src="lib/vue.js"></script>
<script>
    Vue.component("com",{
        template:"#login",
        data(){
            return {
                sonmsg:"子组件的msg"
            }
        },
    })
    var vm=new Vue({
        el:"#app",
        methods:{
            getCon(){
                console.log(this.$refs.login.sonmsg)//子组件的msg
                console.log(this.$refs.p1.innerHTML)//父组件里的p
            }
        }
    })
</script>

那么,子组件向父组件传值就有俩种方法

①用@和$emit

②组件也可以有ref属性,可以通过组件的ref属性拿到子组件的data和method

三、插槽 (slot) 可以更好的去复用组件

插槽是将父组件中的子组件模板数据正常显示出来

假设组件的名称为child

1.插槽的概念

child组件开标签和闭标签之间的内容正常不会显示在页面中,如果想要让他显示,用slot标签代表这些内容,想要让她在哪儿显示就放在模板的哪个位置

理解插槽:

组件就相当于是封装的html 那么插槽就相当于是封装函数里的参数,是每次调用时候都可以赋不同的值的东西

2.具名插槽(传递name属性)

给放在child开标签和闭标签之间的模板或者组件加上v-slot:自定义名字 的指令,在用的时候使用slot标签,在子组件中的 <slot><slot> 里面添加 name='自定义名字' ,通过name属性选择调用哪个插槽。如果父组件中有一部分没有添加 slot 属性,则此处就是默认的插槽,在子组件中的slot直接就是使用的父组件的默认插槽部分

总:在<template>元素上使用v-slot:自定义名字 指令

<template v-slot:header>
    <div>AAA</div>
</template>

<header>
    <slot name="header"></slot>
</header>

v-slot 只能添加在<template>上,v-slot的缩写#

<template #header>
    <div>AAA</div>
</template>

3.后备内容

在<slot></slot>标签中的内容将在没有匹配到插槽内容时渲染

4.作用域插槽 (让插槽内容可以访问到子组件中的数据)

插槽虽然是属于这个组件的,但是因为他没有放在组件的模板里,所以不能直接使用组件的data数据,如果要想使用组件的data 应该用属性传值的方法把数据传过去 在插槽里通过v-slot:xx="" 等号后面的值接收数据,接收到的数据是一个json 因为有可能传过来不只一个值

v-slot:xx="yy" xx代表插槽的名字 yy代表接收到组件的data数据

<div >
    <child>
        <template   v-slot:head="datas">
            <div>
                <h5>组件child里的头部模板=={{datas.textcon}}</h5>
            </div>
        </template>
        
        <template v-slot:foot>    
            <div>
                <h5>组件child里的尾部模板</h5>
            </div>
        </template>

        <template>
            <div>我是一个没有名字的插槽</div>
        </template>
    </child>

    <child>
        <template v-slot:head>
            <div>
                <h4>第二次调用组件child的头部模板</h4>
            </div>
        </template>
        <template v-slot:foot>
            <div>
                <h4>第二次调用组件child的的尾部模板</h4>
            </div>
        </template>
    </child>

</div>
<template >
    <div>
        <header>
            <slot name="head" :textcon="text" ></slot>
        </header>
        <p>{{text}}</p>
        <slot>AA</slot>
        <!-- 后备内容放在slot标签里,如果插槽没有传过来内容的话 默认显示AA,如果传过来内容就取代AA -->
        <footer>
            <slot name="foot"></slot>
        </footer>
    </div>
</template>
<script src="lib/vue.js"></script>
<script>
    Vue.component("child", {
        template: "#login",
        data() {
            return {
                text: "子组件的内容",
            }
        },
    })

    var vm = new Vue({
        el: "#app",
    })
</script>