vue组件能力的透传

671 阅读2分钟

前言

在我们的日常开发中经常会二次封装一些已有的组件,但是如果一个个的透传属性、事件、插槽等给已有组件的话那就太麻烦了,其实vue提供了属性、事件监听、插槽等批量透传的能力。

一、vue组件能力的透传

其实这种批量透传组件能力的属性和extend很像,都能够实现组件的”继承“。ps:后面可以单独再出一章讲解下extend的应用哈~

vue中批量透传属性可以使用v-bind:$attrs,批量透传事件监听可以使用v-on:$listeners,批量透传插槽可以遍历$slots$scopeSlots,我们可以打印一下组件实例看看具体内容的。

image.png

当然如果某些能力不想透传的话,我们可以过滤掉$attrs$listeners$slots$scopeSlots等的一些内容。

二、二次封装el-autocomplete组件

话不多说,直接上代码(以el-autocomplete为例)

子组件

        <el-autocomplete
            v-model="tempValue"
            v-bind="$attrs"
            v-on="$listeners"
        >
            <template v-for="(index, name) in $slots" :slot="name">
                <slot v-if="!ignore_slot.includes(name)" :name="name"></slot>
            </template>
            <template v-for="(index, name) in $scopedSlots" v-slot:[name]="data">
                        <slot :name="name" v-bind="data"></slot>
                    </template>
        </el-autocomplete>
        <div class="append">
            <slot name="append"></slot>
        </div>
export default {
    props: {
        value: {
            type: null
        }
    },
    data() {
        return {
            ignore_slot: ['prepend', 'append'],
        }
    },
    computed: {
        tempValue: {
            get() {
                return this.value
            },
            set(v) {
                this.$emit('input', v)
            }
        }
    }
}

父组件

        <inherit-autocomplete
            ref="autocomplete"
            class="inherit-input2"
            v-model="value2"
            size="small" 
            placeholder="我透传部分插槽"
            :fetch-suggestions="querySearch"
            @focus="focus"
            @blur="blur"
        >
            <template slot="prefix">
                <div class="fix">前面</div>
            </template>
            <template slot="suffix">
                <i class="el-icon-edit fix"></i>
            </template>
            <template slot="prepend">
                <div>无效的插槽</div>
            </template>
            <template slot="append">
                <div>我是重新定义的插槽</div>
            </template>
            <template slot-scope="{ item }">
                <div class="name">{{ item.value }}</div>
                <span class="addr">{{ item.address }}</span>
            </template>
        </inherit-autocomplete>
        <div>{{eventText}}</div>
export default {
    components: {
        InheritAutocomplete
    },
    data() {
        return {
            value1: '我是新组件',
            value2: '',
            restaurants: [
                { "value": "三全鲜食(北新泾店)", "address": "长宁区新渔路144号" },
                { "value": "Hot honey 首尔炸鸡(仙霞路)", "address": "上海市长宁区淞虹路661号" },
            ],
            eventText: ''
        }
    },
    methods: {
        querySearch(queryString, cb) {
            const results = queryString ? this.restaurants.filter(this.createFilter(queryString)) : this.restaurants;
            // 调用 callback 返回建议列表的数据
            cb(results);
        },
        createFilter(queryString) {
            return (restaurant) => {
            return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
            };
        },
        focus() {
            this.eventText='触发了聚焦事件'
        },
        blur() {
            this.eventText='触发了失焦事件'
        }
    }
}

上面例子我们用了之前说的实现v-model的方法。在slot插槽的透传中,我们将append这个原有的具名插槽过滤了,并重新自定义了这个插槽,例子中使用了默认的作用域插槽用来格式化输入建议模板的内容,blur和focus的失焦和聚焦事件。

效果

image.png

三、总结

以上我们就实现二次封装组件能力的透传,不用自己把所有的属性、插槽、事件监听等额外都写一遍了。 可以参考github链接:github.com/qiangguangl…

下期预告: 了解到组件的功能透传之后,我们可以封装el-table组件了,不用一直写el-table-column了(频繁的写实在是太烦了。。。)