44.Vue实现查找任意层级子元素和祖先元素

在vue中查找子元素和父元素提供了this.$parent、this.$children,但是如果需要查找任意层级子元素和祖先元素并没有直接的API,需要封装方法:

案例

index.vue

<template>
    <div>
        <!-- jq closest效果 -->
        jq closest效果 <br>
        <com2 @comParentItem="com2Fun">
            <!-- 父元素com1 -->
            <com1>
                <com2></com2>
            </com1>
        </com2>
        <br>
        <br>
        <com1>
            <!-- 父元素com1 -->
            <com2>
                <com1></com1>
            </com2>
        </com1>
    </div>
</template>
<script>
    import com1 from './com1'
    import com2 from './com2'
    export default {
        //
        components: {
            com1,
            com2
        },
        data(){
            return { }
        },
        methods: {
            /*
               com2Fun的方法
            */
            com2Fun(item){
                console.log('触发父元素事件------ ');
                console.log(item);
            }
        }
    }
</script>
<style>
    .item {
        border: 1px solid red;
        height: 30px;
        line-height: 30px;
    }
</style>

com1.vue

<!-- 组件一
    实现找到任意子元素
 -->
<template>
    <div>
        <slot>
            <com3 @click.native="showChild">
                <com3>
                    <com4 @comChilItem="comChilItemFun">
                        <com3 class="item" >
                            子元素列表1
                        </com3>
                        <com3  class="item">
                            子元素列表2
                        </com3>
                        <com3  class="item">
                            子元素列表3
                        </com3>
                    </com4>
                </com3>
            </com3>
        </slot>
    </div>
</template>
<script>
    import com3 from './com3'
    import com4 from './com4'
    export default {
        components: {
            com3,
            com4
        },
        data(){
            return {}
        },
        methods: {
            /*
                找到指定的子元素
            */
            broadcast(componentName, eventName, params, that){
            //
                broadcast.call(this, componentName, eventName, params, that);
                function broadcast(componentName, eventName, params, that) {
                    //遍历所有子组件
                    this.$children.forEach(child => {
                            var name = child.$options._componentTag.toLowerCase();
                            //寻找符合指定名称的子组件
                            // if (name === componentName) {
                            if (componentName.includes(name)) {
                                //在符合的自组件上触发的事件,但是不会再继续寻找符合名称的组件的子集,原因?
                                child.$emit.apply(child, [eventName].concat(params));
                            } else {
                                //不符合继续寻找他的子集(即孙子组件)
                                broadcast.apply(child, [componentName, eventName, params].concat([that]));
                            }
                    });
                }   
            },
            showChild(){
                //
                this.broadcast('com4', 'comChilItem', {children: '2'});
            },
            comChilItemFun(item){
                console.log('子组件被触发--------');
                console.log(item);
            }
        }
    }
</script>
   
<style>
</style>

com2.vue

<!-- 组件二 
    实现找到任意祖先元素
 -->
<template>
    <com1>
        <slot>
            <com4>
                <com1>
                    <com1 @click.native="showParent">
                        <com1 class="item" >
                            列表1
                        </com1>
                        <com1  class="item">
                            列表2
                        </com1>
                        <com1  class="item">
                            列表3
                        </com1>
                    </com1>
                </com1>
             </com4>
        </slot>
    </com1>

</template>
<script>
    import com1 from './com1.vue'
    import com4 from './com4.vue'
    export default {
        components: {
            com1,
            com4
        },
        data(){
            return {}
        },
        methods: {
            /*
                找到指定的父元素,仿jq的closest
            */
            dispatch(componentName, eventName, params){
                var parent = this.$parent || this.$root;
                var name = parent.$options._componentTag.toLowerCase();
                //寻找父级,如果父级不是符合的组件名,则循环向上查找
                // while (parent && (!name || name !== componentName)) {
                while (parent && (!name || !componentName.includes(name))) {
                    parent = parent.$parent;
                    if (parent) {
                    name = parent.$options._componentTag;
                    }
                }
                //找到符合组件名称的父级后,触发其事件。整体流程类似jQuery的closest方法
                if (parent) {
                    parent.$emit.apply(parent, [eventName].concat(params));
                }
            },
            
            showParent(){
               // 找到指定的祖先元素
               this.dispatch('com2', 'comParentItem', {parent: '1'});
            }
        }
    }
</script>
<style>
</style>

com3.vue

<!-- 组件一 -->
<template>
    <div>
        <slot>
            
        </slot>
    </div>
</template>
<script>
    export default {
        data(){
            return {}
        },
        methods: {

        }
    }
</script>
   
<style>
</style>

com4.vue

<!-- 组件一 -->
<template>
    <div>
        <slot>
            
        </slot>
    </div>
</template>
<script>
    export default {
        data(){
            return {}
        },
        methods: {

        }
    }
</script>
   
<style>
</style>
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容