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 许可协议。转载请注明来源 弈心 !
评论
  目录