【VUE】003. 组件通信(二)——进阶组件通信

268 阅读2分钟

进阶组件通信

01. 祖先与后代

  • 通过 provideinject可以进行跨级组件通信

    只能祖先给后代传值

    这个注入的值,主要用于读取,不建议更改

    确实需要更改,可以从祖先传一个函数,在祖先内进行更改

    // 在祖先元素提供
    provide(){
        return {
            foo: '123123',
            app: this // 甚至可以直接返回这个祖先实例
        }
    }
    
    // 后代元素
    export default {
        // 在后代元素注入祖先元素提供的值
        inject: ['foo']
    }
    

02. 派发与广播

  • 通过$on$emit定义两个自定义事件进行父子组件间的通信

    $emit会在当前组件上触发事件,然后在父组件上用v-on监听这个事件

    也可以通过$on在当前组件自己监听自己

  • 通过向上/向下递归遍历,寻找到指定name的组件

  • 每个组件都应设置一个组件名name,且组件名应该是唯一的

    在子组件可以调用dispatch方法

    • 用于向上级查找指定的组件,并触发自定义事件和传递数据
    • 上级组件需要用$on监听这个事件

    在父组件可以调用broadcast方法

    • 用于向下级查找指定的组件,并触发自定义事件和传递数据
    • 下级组件需要用$on监听这个事件
    // componentName--组件名,eventName--事件名,params--传递参数
    function broadcast(componentName, eventName, params) {
        // 获取当前组件的 子组件数组,遍历查找指定组件名的 子组件
        this.$children.forEach(child => {
            // 获取当前子组件的组件名
            const name = child.$options.name;
    
            if (name === componentName) {
                // 如果当前子组件的组件名与查找的组件名一致,则在当前子组件派发事件
                child.$emit.apply(child, [eventName].concat(params));
            } else {
                // 否则,在当前子组件中查找其子组件,继续向下查找
                broadcast.apply(child, [componentName, eventName].concat([params]));
            }
        });
    }
    
    function dispatch(componentName, eventName, params) {
        // 获取当前组件的父组件 或者 根组件
        let parent = this.$parent || this.$root;
        // 获取其父组件的组件名
        let name = parent.$options.name;
    
        while (parent && (!name || name !== componentName)) {
            // 没有组件名 或者 组件名非查找的组件名,则继续向上查找
            parent = parent.$parent;
            if (parent) {
                name = parent.$options.name;
            }
        }
        // 跳出上面循环,则表示 没有父组件 | 找到对应的组件了
        if (parent) {
            // 父组件存在,则表示找到了指定组件名的组件
            parent.$emit.apply(parent, [eventName].concat(params));
        }
    }
    

03.关于mixin混入

  • 使用mixin混入,可以分发Vue组件中的可复用功能

    • 混入对象可以包含任意组件选项,如生命周期、基础数据、实例方法
    • 当组件使用时,混入对象的所有选项都将被【混入】到组件中
    // mixin.js文件-----
    let mixin = {
        // 写法同组件内的写法一致
        data(){return {}},
        created(){},
        methods:{}
    }
    export default mixin
    
    // 组件中-----
    import mixin from './mixin'
    export default {
        // 局部混入
        mixins: [mixin]
    }
    
    // 全局混入
    Vue.mixin({ mixin })
    
    • 同名的钩子函数(createdmounted),将合并为一个数组,且混入对象的钩子将在组件钩子之前调用
    • 对象选项(methodscomponents),将被合并为同一个对象,当组件有冲突时,以组件优先

    • 混入不同组件的【混入对象】,他们的方法和参数不共享

    • 当我们需要全局去注入一些methodsfilterhooks时我们就可以使用mixin来实现

    • 注意:一旦使用全局混入,它将影响每一个之后创建的 Vue 实例

  • 可以通过混入mixin将上面的派发与广播方法混入到需要的组件中

    export default {
        methods: {
            dispatch(componentName, eventName, params) {
                dispatch.call(this, componentName, eventName, params);
            },
            broadcast(componentName, eventName, params) {
                broadcast.call(this, componentName, eventName, params);
            }
        }
    };
    

04. 组件构造器Extend

  • Vue.extend 的作用,就是基于 Vue 构造器,创建一个【类】,用于扩展实例

    • 它的参数跟new Vue的基本一样

    • 但data要跟组件一样,是个函数

    • 再配合$mount,就可以渲染组件,并且挂载到任意指定的节点上

    extend创建的是一个组件构造器,而不是一个具体的组件实例

    可以理解为构造了一个和vue组件内部有一样结构的对象

    最终还是要通过Vue.components注册才可以使用

    let Profile = Vue.extend({
        template: '',
        data() {
            return {
            }
        }
    })
    // 方式一:创建 Profile 实例,并挂载到一个元素上
    new Profile().$mount('#app')
    // 方式二:
    new Profile({ el: "#app" })
    
    // 方式三:文档之外手动挂载
    let myProfile = new Profile().$mount();
    export default {
        mounted(){
            // 因为这里是通过获取节点的方式添加到某个元素内,所以一定要在钩子函数中挂载,确保当前页面的dom节点加载完成
            let app = document.getElementById('app')
            app.appendChild(myProfile.$el)
        }
    }
    
    // 注册组件
    Vue.component('myProfile', Profile)
    // 或者在局部组件
    export default {
        components: {
            'myProfile': Profile
        }
    }
    

本人前端小菜鸡,如有不对请谅解