Vue父子组件的那些事


一、Vue组件:父传子

1.子组件获取父组件的数据

子组件通过prop获取父组件的数据。注:input 中的v-model自动监听数据的变化

<body>
    <div id="app">
        <father></father>
    </div>
</body>
<!-- 父组件 -->
<template id="father">
    <div>
        <h1>父组件</h1>
        <input type="text" v-model="message" />
        <hr />
        <son :getmoney="money" :flow="num" :msg="message"></son>
    </div>
</template>
<!-- 子组件 -->
<template id="son">
    <div>
        <h1>子组件</h1>
        <h3>{{getmoney}}</h3>
        <h3>{{msg}}</h3>
        <button @click="func(msg)">点击</button>
    </div>
</template>
<script>
    // 父组件用prop传值
    var son = {
        template: "#son",
        props: ["getmoney", "flow", "msg"],
        methods: {
            func(val) {
                console.log(val);
            },
        },
    };
    Vue.component("father", {
        template: "#father",
        data() {
            return {
                money: "爸爸给你10万块",
                num: 10,
                message: "",
            };
        },
        components: {
            son,
        },
    });
    var vue = new Vue({
        el: "#app",
        data: {},
        methods: {},
    });
</script>

分页面展示

<template>
    <div id="app">
        <h1>父组件</h1>
        <input type="text" v-model="message" />
        <hr />
        <child :getmoney="money" :flow="num" :msg="message" />
    </div>
</template>

<script>
    import child from "./components/child.vue";
    export default {
        name: "App",
        components: {
            child,
        },
        data() {
            return {
                money: "爸爸给你10万块",
                num: 10,
                message: "",
            };
        },
    };
</script>
<template>
    <div class="child">
        <h1>子组件</h1>
        <h3>{{getmoney}}</h3>
        <h3>{{msg}}</h3>
        <button @click="func(msg)">点击</button>
    </div>
</template>

<script>
    export default {
        name: "child",
        props: ["getmoney", "flow", "msg"],
        methods: {
            func(val) {
                console.log(val);
            },
        },
    };
</script>

2.子组件调用父组件的方法

Vue中子组件调用父组件的方法,这里有三种方法提供参考

第一种方法是直接在子组件中通过this.$parent.event来调用父组件的方法

父组件

<template>
    <div>
        <child></child>
    </div>
</template>
<script>
    import child from "~/components/child";
    export default {
        components: {
            child,
        },
        methods: {
            fatherMethod() {
                console.log("测试");
            },
        },
    };
</script>

子组件

<template>
    <div>
        <button @click="childMethod()">点击</button>
    </div>
</template>
<script>
    export default {
        methods: {
            childMethod() {
                this.$parent.fatherMethod();
            },
        },
    };
</script>

第二种方法是在子组件里用$emit向父组件触发一个事件

父组件监听这个事件就行了,相当于子组件给父组件传值。如tree中暴露出接口,父组件直接使用。

父组件

<template>
    <div>
        <child @fatherMethod="fatherMethod"></child>
    </div>
</template>
<script>
    import child from "~/components/dam/child";
    export default {
        components: {
            child,
        },
        methods: {
            fatherMethod() {
                console.log("测试");
            },
        },
    };
</script>

子组件

<template>
    <div>
        <button @click="childMethod()">点击</button>
    </div>
</template>
<script>
    export default {
        methods: {
            childMethod() {
                this.$emit("fatherMethod");
            },
        },
    };
</script>

第三种是父组件把方法传入子组件中,在子组件里直接调用这个方法

父组件

<template>
    <div>
        <child :fatherMethod="fatherMethod"></child>
    </div>
</template>
<script>
    import child from "~/components/dam/child";
    export default {
        components: {
            child,
        },
        methods: {
            fatherMethod() {
                console.log("测试");
            },
        },
    };
</script>

子组件

<template>
    <div>
        <button @click="childMethod()">点击</button>
    </div>
</template>
<script>
    export default {
        props: {
            fatherMethod: {
                type: Function,
                default: null,
            },
        },
        methods: {
            childMethod() {
                if (this.fatherMethod) {
                    this.fatherMethod();
                }
            },
        },
    };
</script>

三种都可以实现子组件调用父组件的方法,但是效率有所不同,根据实际需求选择合适的方法。

二、Vue组件:子传父

1.父组件获取子组件的数据

方法1:给相应的子组件标签上加 ref ="child",使用this.$refs.child.msg获取msg的内容

<template>
    <div id="app">
        <h1>父组件</h1>
        <button @click="getmsg">点击</button>
        <div>{{msg}}</div>
        <hr />
        <child ref="child" />
    </div>
</template>

<script>
    import child from "./components/child.vue";
    export default {
        name: "App",
        components: {
            child,
        },
        data() {
            return {
                msg: "",
            };
        },
        methods: {
            getmsg() {
                this.msg = this.$refs.child.msg;
            },
        },
    };
</script>
<template>
    <div class="child">
        <h1>子组件</h1>
    </div>
</template>

<script>
    export default {
        name: "child",
        data() {
            return {
                msg: "这是子组件传给父组件的数据",
            };
        },
    };
</script>

通过ref绑定,使用this.$refs.child.msg获取msg的内容。该方法父组件可以获取到子组件的方法,并调用。

方法2:通过$emit()

<body>
    <div id="app">
        <father></father>
    </div>
</body>
<!-- 父组件 -->
<template id="father">
    <div>
        <h1>父组件</h1>
        {{message}}
        <hr />
        <son @sendmsg="getmsg"></son>
    </div>
</template>
<!-- 子组件 -->
<template id="son">
    <div>
        <h2>子组件</h2>
        <button @click="click">点击</button>
    </div>
</template>
<script>
    // 子组件
    var son = {
        template: "#son",
        data() {
            return {
                msg: "这是子组件传给父组件的数据",
            };
        },
        methods: {
            click() {
                this.$emit("sendmsg", this.msg); //触发事件,用方法接收
            },
        },
    };

    // 父组件
    Vue.component("father", {
        template: "#father",
        components: {
            son,
        },
        data() {
            return {
                message: "",
            };
        },
        methods: {
            getmsg(val) {
                console.log(val);
                this.message = val;
            },
        },
    });

    var vue = new Vue({
        el: "#app",
        data: {},
        methods: {},
    });
</script>

分页面展示

<!-- 父组件 -->
<template>
    <div id="app">
        <h1>父组件</h1>
        {{msg}}
        <hr />
        <child @sendmsg="getmsg" />
    </div>
</template>

<script>
    import child from "./components/child.vue";
    export default {
        name: "App",
        components: {
            child,
        },
        data() {
            return {
                msg: "",
            };
        },
        methods: {
            getmsg(val) {
                console.log(val);
                this.msg = val;
            },
        },
    };
</script>
<!-- 子组件 -->
<template>
    <div class="child">
        <h1>子组件</h1>
        <button @click="func">点击</button>
    </div>
</template>

<script>
    export default {
        name: "child",
        data() {
            return {
                msg: "这是子组件传给父组件的数据",
            };
        },
        methods: {
            func() {
                this.$emit("sendmsg", this.msg); //触发事件,用方法接收
            },
        },
    };
</script>

从上面可以看出,当this.$emit()携带参数时,可以传参到父组件,同时可以调用父组件的方法;

2.父组件调用子组件的方法

给相应的子组件标签上加 ref ="child",然后通过this.$refs.child.func()获取func()的方法。

三、Vue的$on,$emit的使用

vue中使用 $emit(eventName) 触发事件,使用 $on(eventName) 监听事件,为同级事件

$emit(eventName)触发当前实例上的事件,附加参数都会传给监听器回调。

$on(eventName)监听当前实例上的自定义事件。事件可以由 vm.$emit 触发。回调函数会接收所有传入事件触发函数的额外参数。

下面通过几个实例来演示一下怎么使用

实例1 本页面单个事件

<template>
    <div>
        <el-button type="primary" @click="isClick">点击</el-button>
    </div>
</template>

<script>
    export default {
        methods: {
            isClick() {
                this.$emit("isLeft", "点击事件!"); //与this.$on 同级使用
            },
        },
        mounted() {
            this.$on("isLeft", val => {
                console.log(val);
            });
        },
    };
</script>

以上代码,是通过按钮的点击事件,然后this.$emit传递事件,然后this.$on捕获本页面的事件

实例2 本页面多个事件

<template>
    <div>
        <el-button type="primary" @click="isClick">点击</el-button>
        <el-button type="primary" @click="isClickOther">点击</el-button>
    </div>
</template>

<script>
    export default {
        methods: {
            isClick() {
                this.$emit("isLeft", "点击事件!");
            },
            isClickOther() {
                this.$emit("isRight", ["点击1", "点击2"]);
            },
        },
        mounted() {
            this.$on("isLeft", val => {
                console.log(val);
            });
            this.$on("isRight", (...val) => {
                console.log(val);
            });
            this.$on(["isLeft", "isRight"], () => {
                console.log(666);
            });
        },
    };
</script>

以上例子,是本页面的两个点击事件,可以同时监听两个事件,也可以同时传多个参数

实例3 非父子组件传值(通过bus传值)

子组件1

<template>
    <div>
        <div>left</div>
        <el-button type="primary" @click="isClick">点击</el-button>
    </div>
</template>

<script>
    import eventBus from "./js/eventBus";
    export default {
        methods: {
            isClick() {
                eventBus.$emit("isLeft", "点击事件!");
            },
        },
    };
</script>

子组件2

<template>
    <div>
        <div>right</div>
        {{ name }}
    </div>
</template>

<script>
    import eventBus from "./js/eventBus";
    export default {
        data() {
            return {
                name: "right默认值",
            };
        },
        mounted() {
            eventBus.$on("isLeft", info => {
                this.name = info;
            });
        },
    };
</script>

父组件

<template>
    <div>
        <el-row>
            <el-col :span="12">
                <leftChlid></leftChlid>
            </el-col>
            <el-col :span="12">
                <rightChild></rightChild>
            </el-col>
        </el-row>
    </div>
</template>

<script>
    import leftChlid from "./components/leftChlid";
    import rightChild from "./components/rightChild";
    export default {
        components: {
            leftChlid,
            rightChild,
        },
    };
</script>

以上例子就是 left组件传值给bus,然后right组件监听 busisLest事件,当left组件触发事件的时候,right组件就会触发方法,替换页面的值

小结

1.使用 $emit 传递事件

2.使用 $on 监听事件

3.可以本页面使用,也可以父子组件使用,也可以非关联组件使用

四、总结

1:父组件向子组件传值:使用 prop 向子组件传值;

2:子组件实时监听父组件传来的值的变化:使用 watch 去监听父组件传来的值;

3:父组件可以通过 this.$refs.name. 去访问子组件的值或方法;

4:子组件可以通过 this.$parent. 去访问父组件的值或方法;

5:父组件可以通过 this.$store.dispatch 去监听子组件的值;

下次我们说说$attrs和$listeners


文章作者: 弈心
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 弈心 !
评论
  目录