首页 > 解决方案 > Vue 两次导入相同的组件/ Vue 事件从子级只到根,而不是到父级

问题描述

我有的

我两次导入相同的组件。该组件用于显示带有集合的下拉列表。当下拉列表中的项目被选中时,将触发一个事件。该组件被导入到list.js和 中BulkActions.vue

问题

选择下拉列表中的集合时会触发一个事件。然后它使用 触发事件$emit。不知何故,此事件仅在list.blade.php而不是在BulkActions.vue. 对于两个下拉菜单(从同一个组件加载)应该有不同的行为。我不知道为什么会发生这种情况,也不知道为什么该事件只在我的根部被捕获。

我试过的

我试图prop在 HTML 中传递一个额外的“变量事件名称”,但这没有用。我也尝试了各种导入组件的方法。

有谁知道如何解决这个问题?

文件

list.blade.php

    <div class="media-list-navbar mt-3 mb-3">
        <shown-results :text="resultText"></shown-results>

        <search-bar @update-filters="updateFilters"></search-bar>

        <document-types @update-filters="updateFilters"></document-types>

        <collection-dropdown eventname="update-filters"
                             @update-filters="updateFilters"></collection-dropdown>


        <div class="clearfix"></div>
    </div>

    <bulk-actions @select-all="selectAll"
                  @deselect-all="deselectAll"
                  :items="items"
                  :multiselect="multiSelect"></bulk-actions>

BulkActions.vue

<template>
    <div class="multiselect-list-navbar mt-3 mb-3" v-if="multiselect">
        <div class="float-left">
            <button type="button"
                    class="btn btn-outline-secondary"
                    @click="$emit('deselect-all')">
                <i class="fas fa-fw fa-times"></i> {{ Lang.get('media/item.index.list.multi-select.deselect-all') }}
            </button>
            <button type="button"
                    class="btn btn-outline-secondary"
                    @click="$emit('select-all')">
                <i class="fas fa-fw fa-check"></i> {{ Lang.get('media/item.index.list.multi-select.select-all') }}
            </button>
        </div>

        <bulk-collection
            @update-filters="doSomething"></bulk-collection>
        <div class="clearfix"></div>
    </div>
</template>

<script>
    export default {
        name: "Bulk",
        props: {
            multiselect: Boolean,
            items: Array
        },
        components: {
            'bulk-collection': () => import('./Collections')
        },
        methods: {
            doSomething() {
                console.log(this.items)
            }
        }
    }
</script>

<style scoped>

</style>

list.js

import MediaItem from '../components/MediaItem';
import UploadModal from '../components/media/UploadModal';
import ItemDetail from '../components/media/ItemDetail';
import ShownResults from '../components/media/list/ShownResults';
import SearchBar from '../components/media/list/SearchBar';
import DocumentTypes from '../components/media/list/DocumentTypes';
import {default as CollectionDropdown} from '../components/media/list/Collections';
import Order from '../components/media/list/Order';
import BulkActions from '../components/media/list/BulkActions';

if (document.getElementById('media-list')) {
    const mediaList = new Vue({
        el: '#media-list',
        components: {
            MediaItem,
            ShownResults,
            SearchBar,
            UploadModal,
            ItemDetail,
            DocumentTypes,
            CollectionDropdown,
            Order,
            BulkActions
        },
[...]

Collections.vue

<template>
    <div class="dropdown float-left">
        <button class="btn btn-secondary dropdown-toggle"
                type="button"
                data-toggle="dropdown">
            {{ Lang.get('media/item.index.list.filters.collections.title') }}
        </button>
        <div class="dropdown-menu" ref="collectionDropdown">
            <div class="dropdown-item no-pseudo">
                <input type="search"
                       class="form-control"
                       name="search"
                       :placeholder="Lang.get('media/item.index.list.filters.collections.filter')"
                       v-model="query"
                       @keyup="search">
            </div>
            <div class="dropdown-item last-item no-pseudo">
                <alert type="warning">
                    <template v-slot:body>
                        {{ Lang.get('media/item.index.list.filters.collections.none-filter') }}
                    </template>
                </alert>
            </div>
            <div v-for="item in list"
                 class="dropdown-item"
                 v-if="!item.hidden">
                <span class="custom-control custom-checkbox">
                    <input type="checkbox"
                           class="custom-control-input"
                           name="collection[]"
                           :checked="item.checked"
                           :id="item.slug"
                           :value="item.id"
                           @change="selectItem">
                    <label class="custom-control-label" :for="item.slug">
                        {{ item.name }}
                    </label>
                </span>
            </div>
        </div>
    </div>
</template>

<script>
    import Alert from '../../partials/Alert';

    export default {
        name: "Collections",
        components: {
            Alert
        },
        data() {
            return {
                displayAmount: 10, // amount of items displayed without search
                list: [],
                query: ''
            }
        },
        computed: {
            /**
             * Return an array of selected items only
             */
            checked() {
                return this.list.filter(item => {
                    return item.checked === true;
                })
            }
        },
        methods: {
            /**
             * Mark an item as selected
             */
            selectItem(e) {
                let selectedId = e.target.value;

                this.markItem(selectedId);
            },
            /**
             * Mark an item from the list as selected
             *
             * @param {Number} itemId
             */
            markItem(itemId) {
                this.list.forEach(item => {
                    if (item.id === parseInt(itemId)) {
                        item.checked = !item.checked;
                    }
                });

                this.$emit('update-filters', {
                    props: this.checked.map(item => item.id).join(',')
                });
            },
            /**
             * Search in the current URL for collection ids
             */
            markItemsFromUrl() {
                let urlParams = new URLSearchParams(window.location.search);

                if (urlParams.has('collection')) {
                    let urlFilters = urlParams.get('collection').split(','); // split url parameters

                    urlFilters.forEach(itemId => {
                        this.markItem(itemId);
                    });
                }
            },
        },
        mounted() {
            this.fetchList();
            this.markItemsFromUrl();

            /**
             * Prevent Bootstrap dropdown from closing after clicking inside it
             */
            $(this.$refs.collectionDropdown).on('click.bs.dropdown', function (e) {
                e.stopPropagation();
            });
        }
    }
</script>

下面是一个 GIF 动画来演示这个问题。第一个下拉列表(顶部的那个)具有正常行为。第二个(稍后出现)没有。单击第二个时,将发生第一个事件。

https://imgur.com/PvxUVCm

标签: javascriptvue.jsecmascript-6vue-componentlaravel-blade

解决方案


推荐阅读