❤️vue组件通信

小明的学习圈子2023-12-09前端

一、vue组件通信

1、props(父向子传递)

  • 父组件使用子组件时,自定义属性(属性名任意,属性值为要传递的数据)
  • 子组件通过props接收父组件数据,通过自定义属性的属性名

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <child_temp v-bind:child_msg="parent_msg" :chlid_movies="parent_movies"></child_temp>
</div>

<template id="child_temp">
    <div>
        <ul>
            <li v-for="item in chlid_movies">{{item}}</li>
        </ul>
        <p>{{child_msg}}</p>
        <p>{{chlid_movies}}</p>
        <p>{{myname}}</p>
        <!--<button @click="child_btn">子按钮</button>-->
    </div>
</template>
</body>
<script src="../../js/vue.js"></script>
<script>

    const child_temp = {
        template:'#child_temp',
        /*props:['chlid_movies','child_msg'],*/
        props:{
            //props的扩展,包括类型,默认值,是否必须等
            //1类型限制
            /*chlid_movies:Array,
            child_msg:String*/
            //2.提供默认值,扩展
            chlid_movies:{
              type:Array,
              default() {
                  return [];
              }
            },
            child_msg: {
                type: String,
                required: true,
                default() {
                    //如果把child_temp模板里的v-bind:child_msg="parent_msg"去掉,页面就会显示这里的值
                    return ["子_我是子组件默认值,当使用父组件data里的属性值得时候,如果没有用v-bind绑定,会取到我这一串值"];
                }
            }/*,
            methods:{
                child_btn(){
                    alert("我是子组件的方法")
                }
            }*/
        },
        data(){
            return {
                myname:"子_我是子属性自己的值,我使用的是自己组件里的data的属性值"
            }
        }
    }
    var vm = new Vue({
            el:"#app",
        data:{
            parent_msg:"父_我是父组件里的信息,传到了子组件",
            parent_movies:['父_火影','父_海贼王','父_柯南']
        },
        components:{
            child_temp
            }
        })
</script>
</html>

效果:

img

2、props验证(参照上边代码例子)

props:定义需要从父组件中接收的属性

  • items:是要接收的属性名称

  • type:限定父组件传递来的必须是数组

  • default:默认值

  • required:是否必须

验证支持的数据类型

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

动态静态传递

给 prop 传入一个静态的值:

<temp child_msg="大家好,我是组件"/>

给 prop 传入一个动态的值: (通过v-bind从数据模型中,获取title的值)

<temp :child_msg="parent_msg"/>

3、子向父的通信:$emit

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <!--父组件模板-->
    <div id="app">
        <!--监听子组件发射出的btn_child_click事件,find_parent_click要在父组件里定义methods-->
        <chlid_temp v-on:btn_child_click="find_parent_click"></chlid_temp>
    </div>
    <!--子组件模板-->
    <template id="chlid_temp">
        <div>
            <button v-for="item in movies"
                    @click="btn_ckik(item)">
                    {{item.id}}-{{item.name}}
            </button>
        </div>
    </template>
</body>
<script src="../../js/vue.js"></script>
<script>
    //子组件
    const chlid_temp = {
        template:"#chlid_temp",
        data(){
            return{
                movies:[
                    {id:"1",name:"火影"},
                    {id:"2",name:"海贼"},
                    {id:"3",name:"七大罪"},
                    {id:"4",name:"菜鸟java是怎么炼成的"},
                    {id:"5",name:"菜鸟是怎么变菜的"},
                ]
            }
        },
        methods:{
            btn_ckik(ev){
                //自定义事件
                this.$emit("btn_child_click",ev)
            }
        }
    }
    //父组件
    var vm =  new Vue({
        el:"#app",
        data:{
            msg:"我是父组件的信息-msg"
        },
        components:{
            chlid_temp
        },
        methods:{
            find_parent_click(ev){

                 console.log(ev)
                 console.log(ev.id +"  "+ev.name)

            }
        }
    });
</script>
</html>

效果:

img

4、父子通信示例

需求:父组件里的num1和num2,和子组件里的num1和num2实现双向绑定,并且input1里的num1输入后input2里num2的值会相应的变为num1值得100倍,反之num2是num1的100分之1.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        <temp :c_num1="p_num1"
              :c_num2="p_num2"
              @data_cnum1_change="parent_cnum1_change"
              @data_cnum2_change="parent_cnum2_change"
        ></temp>
    </div>
    <template id="temp">
        <div>

            <h3>props:{{c_num1}}</h3>
            <h3>data:{{data_cnum1}}</h3>
            <!--<input type="text" v-model="data_cnum1">-->
            input1:<input type="text" :value="data_cnum1" @input="num1_input">
            <h3>props:{{c_num2}}</h3>
            <h3>data:{{data_cnum2}}</h3>
            <!--<input type="text" v-model="data_cnum2">-->
            <!--<input type="text" :value="data_cnum2" @input="data_cnum2=$event.target.value">-->
            input2:<input type="text" :value="data_cnum2" @input="num2_input">
        </div>
    </template>
</body>
<script src="../../js/vue.js"></script>
<script>
    const temp={
        template:"#temp",
        props:{
            c_num1:Number,
            c_num2:Number

        },
        data(){
           return{
               data_cnum1:this.c_num1,
               data_cnum2:this.c_num2
           }
        },
        methods:{
            num1_input(e){
                //1 将input的value赋值到data_cnum1上
                this.data_cnum1 = e.target.value;
                //2 为了让父组件可以改值,发出一个事件
                this.$emit("data_cnum1_change",this.data_cnum1);
                //3 同事修改data_cnum2的值(data_cnum2的值是data_cnum1的100倍)
                this.data_cnum2 = this.data_cnum1 * 100;
                this.$emit("data_cnum2_change",this.data_cnum2)
            },
            num2_input(e){
                this.data_cnum2 = e.target.value;
                this.$emit("data_cnum2_change",this.data_cnum2);
                //(data_cnum2的值是data_cnum1的100分之一倍)
                this.data_cnum1 = this.data_cnum2 / 100;
                this.$emit("data_cnum1_change",this.data_cnum1)
            }
        }
    }
    var vm = new Vue({
        el:"#app",
        data:{
            p_num1:1,
            p_num2:0
        },
        components:{
            temp
        },
        methods:{
            parent_cnum1_change(data_cnum1){
                //默认传过来的是Strnig类型,需要转换成number
                console.log(typeof data_cnum1)

                this.p_num1 = parseInt(data_cnum1);
            },
            parent_cnum2_change(data_cnum2){
                this.p_num2 = parseInt(data_cnum2);

            }
        }
    })
</script>
</html>

img

img

img

二、父子组件访问方式

1、父访问子

  • 父访问子使用使用$children或$refs

$children的缺陷:通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值。但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化。有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs$refs的使用:$refs和ref指令通常是一起使用的。首先,我们通过ref给某一个子组件绑定一个特定的ID。其次,通过this.$refs.ID就可以访问到该组件了。

例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
     <cpn></cpn>
     <cpn></cpn>
     <cpn></cpn>
     <cpn ref="ref_name"></cpn>
    <button @click="btnClick">按钮</button>
    {{message}}
</div>

<template id="cpn">
    <div>我是子组件</div>
</template>
<script src="../../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message: '你好啊'
        },
        methods: {
            btnClick() {
                // 1.$children
                console.log(this.$children);
                for (let v of this.$children) {
                  console.log(v.child_name);
                  v.childMessage();
                  this.message = v.child_name;
                }
                console.log(this.$children[3].child_name+'================');
                /*console.log(this.$children[4].child_name+'++++++++++++');*/
                // 2.$refs => 对象类型, 默认是一个空的对象 ref='ref-name'
                console.log(this.$refs.ref_name.child_name+"----------");
            }
        },
        components: {
            cpn: {
                template: '#cpn',
                data() {
                    return {
                        child_name: '我是子组件的name哈哈'
                    }
                },
                methods: {
                    childMessage() {
                        console.log('childMessage');
                    }
                }
            },
        }
    })
</script>

</body>
</html>

2、子访问父

  • 通过$parent子访问父
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <button @click="rootclik()">根组件按钮</button>
    <cpn></cpn>
</div>

<template id="cpn">
    <div>
        <h2>我是cpn组件</h2>
        <ccpn></ccpn>
    </div>
</template>

<template id="ccpn">
    <div>
        <h2>我是子组件</h2>
        <button @click="btnClick">按钮</button>
    </div>
</template>

<script src="../../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message: '我是ccpn组件的根组件的name'
        },
        methods: {
            rootclik(){
            console.log("我是根组件root的事件")
            }
        },
        components: {
            cpn: {
                template: '#cpn',
                data() {
                    return {
                        name: '我是ccpn组件的父组件的name'
                    }
                },
                methods: {
                    parentclik(){
                        console.log("我是父组件parent的事件")
                    }
                },
                components: {
                    ccpn: {
                        template: '#ccpn',
                        methods: {
                            btnClick() {
                                // 1.访问父组件$parent
                                console.log("======parent start============")
                                console.log(this.$parent);
                                console.log(this.$parent.name);
                                console.log(this.$parent.parentclik());
                                console.log("======parent end============")

                                // 2.访问根组件$root
                                console.log("======root start============")
                                console.log(this.$root);
                                console.log(this.$root.message);
                                console.log(this.$root.rootclik());
                                console.log("======root end============")
                            }
                        }
                    }
                }
            }
        }
    })
</script>

</body>
</html>
Last Updated 2024/4/6 11:55:17