【问题标题】:Custom event not captured by component in Vue.jsVue.js 中的组件未捕获自定义事件
【发布时间】:2019-01-27 04:10:01
【问题描述】:

这是我的组件架构

组件<ListButtonMenu> 发出一个自定义事件display-error,如下所示。发射工作正常,因为我可以在 VueDevtools 中看到该事件:

<template>
    <div>
        <button type="button" class="btn btn-success" v-on:click="saveList()">
            Save
        </button>
    </div>
</template>

<script>
export default {
    props: {
        list: Object
    },
    methods: {
        saveList() {
            this.$emit('display-error');
        }
    }
}
</script>

组件&lt;ErrorMessage&gt; 包含一个div 元素,它侦听自定义事件并调用方法display()。该方法更改组件 CSS 类以显示自己:v-on:display-error="display"。不幸的是,这不起作用,CSS 类没有改​​变。我错过了什么?

<template>
    <div id="errorMessage" v-bind:class="cssClass" v-on:display-error="display()">
        <div class="row justify-content-center alert alert-danger alert-dismissable text-danger">
            Error: {{ errorMessage }}
            <button type="button" class="close" data-dismiss="alert" aria-hidden="true">
                &times;
            </button>
        </div>
    </div>
</template>

<script>
export default {
    data: function () {
        return {
            'cssClass': 'd-none',
            'errorMessage': 'Hello'
        }
    },
    methods: {
        display() {
            this.cssClass = 'show';
            this.errorMessage='Goodbye';
        }
    }
}
</script>

【问题讨论】:

    标签: javascript events vue.js custom-events


    【解决方案1】:

    错误侦听器必须附加到发出事件的元素。当您有&lt;div id="errorMessage" v-bind:class="cssClass" v-on:display-error="display()"&gt; 时,这会添加一个侦听器,用于该div 何时发出事件,但事件不是来自div,它来自您的ListButtonMenu。您需要将 v-on 指令添加到该元素,如下所示:

    <ListButtonMenu v-on="display()" other="attributes"></ListButtonMenu>
    

    编辑:

    您的 ErrorMessage 元素需要像这样接受来自父级的错误(注意为关闭按钮添加的$emit):

    <template>
      <div id="errorMessage" v-bind:class="cssClass" v-on:display-error="display()">
        <div class="row justify-content-center alert alert-danger alert-dismissable text-danger">
          Error: {{ errorMessage }}
          <button v-on:click="$emit('input', false)" type="button" class="close" data-dismiss="alert" aria-hidden="true">
          &times;
          </button>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      props: [
        'errorMessage',
        'value', // Generally value is used to toggle things so that v-model works
      ],
      computed: {
        cssClass() {
          return this.value ? 'show' : 'd-none';
        }
      }
      methods: {
        display() {
          this.cssClass = 'show';
          this.errorMessage='Goodbye';
        }
      }
    }
    </script>
    

    然后你的父母可能看起来像这样:

    <template>
      <error-message v-model="showError" v-bind:errorMessage="errorMessage">
      <list-button-menu v-on:display-error="displayError()"></list-button-menu>
    </template>
    
    <script>
    export default {
      data: function() {
        return {
          errorMessage: 'Hello',
          showError: false,
        }
      },
      methods: {
        displayError() {
          this.showError = true;
          this.errorMessage: 'Goodbye';
        }
      }
    }
    </script>
    

    【讨论】:

    • 谢谢,我已经添加了v-on="display()" 这样的&lt;list-button-menu v-on="display()"&gt;&lt;/list-button-menu&gt;,它实际上在&lt;ListForm&gt; 组件中。它不起作用,因为&lt;ListForm&gt; 没有任何display() 方法。我还更新了上面的&lt;ListButtonMenu&gt; 以显示完整的代码。你介意看看它并告诉我是否应该在那里改变它吗?
    • 在我发布更新之前,请考虑如何将值从父级传递到该错误元素
    • 对不起,我没明白你的意思。当您说“那个错误元素”时,您指的是哪个元素?实际上&lt;ErrorMessage&gt; 组件并不是&lt;ListButtonAttribute&gt; 的父级。它只是在层次结构中更高。这是问题所在吗?只有组件的父组件才能从子组件捕获事件?此外,祖父母可以捕捉孙子的事件还是只捕捉他们的直系子女?
    • 你有两个兄弟姐妹,所以你的父母需要方便沟通。我所说的“那个错误元素”是指你的错误组件。每次我说元素时,我的意思是组件。
    • 我明白了,谢谢你的详细回答。基本上,根据我上面描述的组件架构,错误信息必须来自ListButtonMenu > ListForm > List > App > ErrorMessage。我想我会重新设计架构以使其更直接
    【解决方案2】:

    因为我的ErrorMessageListButtonMenu 组件没有父子关系,所以我选择了与使用自定义事件不同的解决方案。

    相反,我使用我的应用程序状态(使用 Vuex 存储构建)作为事件总线来更新 errorObjectErrorMessage 组件使用计算属性来捕获 errorObject 并显示自己。

    我的组件架构与问题中的相同。 这是文件store.js

    import Vue from 'vue';
    import Vuex from 'vuex';
    
    Vue.use(Vuex);
    
    export const store = new Vuex.Store({
        state: {
            errorObject: {
                flag: false,
                message: ''
            }
        }
    });
    

    这是 ListButtonMenu 组件:

    <template>
        <div>
            <button type="button" class="btn btn-success" v-on:click="saveList()">
                Save
            </button>
        </div>
    </template>
    
    <script>
    export default {
        props: {
            list: Object
        },
        methods: {
            saveList() {
                this.$store.state.errorObject.flag = true;
                this.$store.state.errorObject.message = 'My error mesage';
            }
        }
    }
    </script>
    

    这里是 ErrorMessage 组件;

    <template>
        <div id="errorMessage" v-bind:class="cssClass">
            <div class="row justify-content-center alert alert-danger alert-dismissable text-danger">
                Error: {{ errorMessage }}
                <button type="button" class="close" v-on:click="close()">
                    &times;
                </button>
            </div>
        </div>
    </template>
    
    <script>
    export default {
        data: function () {
            return {
            }
        },
        computed: {
            cssClass() {
                if (this.$store.state.errorObject.flag) { return 'display' }
                else { return 'd-none' }
            },
            errorMessage() {
                return this.$store.state.errorObject.message;
            }
        },
        methods: {
            close() {
                this.$store.state.errorObject.flag = false;
                this.$store.state.errorObject.message= '';
            }
        }
    }
    </script>
    

    【讨论】:

      猜你喜欢
      • 2021-04-22
      • 2019-03-21
      • 2018-05-11
      • 1970-01-01
      • 2018-07-07
      • 2021-03-13
      • 1970-01-01
      • 2020-05-15
      • 2017-01-25
      相关资源
      最近更新 更多