Vue 3 - 从插槽内的子组件发出事件

Posted

技术标签:

【中文标题】Vue 3 - 从插槽内的子组件发出事件【英文标题】:Vue 3 - Emit event from child component within a slot 【发布时间】:2021-01-14 06:26:50 【问题描述】:

我正在考虑升级到 v3,但看到 inline-template 已被删除感到很失望。因此,我正在尝试转换为使用作用域插槽。

我已经定义了以下列表组件:

<template>
    <slot :items="filteredItems" :page="page" :totalPages="totalPages" :onPageChanged="onPageChanged"></slot>
</template>

<script>
    export default 
        props: 
            items: 
                type: Array
            ,
            initialPage: 
                type: Number,
                default: 1,
            ,
            pageSize: 
                type: Number,
                default: 10
            
        ,
        beforeCreate() 
            this.page = this.initialPage;
        ,
        computed: 
            filteredItems() 
                return this.items.slice((this.page - 1) * this.pageSize, this.page * this.pageSize);
            ,
            totalPages() 
                return Math.ceil(this.items.length / this.pageSize);
            
        ,
        methods: 
            onPageChanged(page) 
                console.log('Page changed!!!');

                this.page = page;
            
        
    ;
</script>

这样称呼:

<list :items="[  foo: 'A' ,  foo: 'B' ,  foo: 'C'  ]" :page-size="2" #=" items, page, totalPages, onPageChanged ">
    <ul class="list-group">
        <li class="list-group-item" v-for="item in items"> item.foo </li>
    </ul>
    <pager :page="page" :total-pages="totalPages" @pageChanged="onPageChanged"></pager>
</list>

这是寻呼机组件:

<template>
    <ul class="pagination">
        <li class="page-item" v-if="hasPreviousPage"><a href="#" @click="changePage(1)" class="page-link">&laquo;</a></li>
        <li class="page-item" v-if="hasPreviousPage"><a href="#" @click="changePage(page - 1)" class="page-link">&#8249;</a></li>
        <li v-for="page in pages" :class="['page-item',  active: page.isActive ]"><a href="#" @click="changePage(page.name)" class="page-link"> page.name </a></li>
        <li class="page-item disabled" v-if="page < totalPages - 2"><span class="page-link"> ... </span></li>
        <li class="page-item" v-if="page < totalPages - 2"><a href="#" @click="changePage(totalPages)" class="page-link"> totalPages </a></li>
        <li class="page-item" v-if="hasNextPage"><a href="#" @click="changePage(page + 1)" class="page-link">&#8250;</a></li>
        <li class="page-item" v-if="hasNextPage"><a href="#" @click="changePage(totalPages)" class="page-link">&raquo;</a></li>
    </ul>
</template>

<script>
    export default 
        props: 
            page: 
                type: Number,
                required: true
            ,
            totalPages: 
                type: Number,
                required: true
            
        ,
        computed: 
            hasPreviousPage() 
                return this.page > 1;
            ,
            hasNextPage() 
                return this.page < this.totalPages;
            ,
            pages() 
                const range = [];

                for (let i = this.page <= 2 ? 1 : this.page - 2; i <= (this.page >= this.totalPages - 2 ? this.totalPages : this.page + 2); i++) 
                    range.push(
                        name: i,
                        isActive: this.page == i
                    );
                

                return range;
            
        ,
        methods: 
            changePage(page, e = event) 
                e.preventDefault();

                // Trigger the page changed event.
                this.$emit('pageChanged', page);
            
        
    ;
</script>

但是,每当我尝试更改页面时,都会调用changePage 方法,该方法会发出pageChanged 事件,但它不会调用列表组件中的onPageChanged 方法。

如果有人能告诉我我做错了什么,我将不胜感激。谢谢

【问题讨论】:

v3.vuejs.org/guide/component-custom-events.html#event-names "DOM 模板中的 v-on 事件监听器将自动转换为小写(由于 HTML 不区分大小写),因此 @myEvent 将变为 @myevent -- 使myEvent 无法收听。” 【参考方案1】:

事件名称应写成kebab-case格式如下:

this.$emit('page-changed', page);

并像@page-changed="onPageChanged一样使用它

【讨论】:

谢谢,我知道这很明显。

以上是关于Vue 3 - 从插槽内的子组件发出事件的主要内容,如果未能解决你的问题,请参考以下文章

vue 3.0组件(下)

无法从Vuejs中的子组件向父组件发出事件

Vue3 监听来自动态创建的子组件的事件,$on 替换

vue的插槽slot

Vue TodoList案例组件通信方式webStorage插槽(3种)

Vue TodoList案例组件通信方式webStorage插槽(3种)