【问题标题】:$emit an event from child to parent in vue.js, es6 syntax$emit an event from child to parent in vue.js, es6 语法
【发布时间】:2017-03-11 02:00:41
【问题描述】:

我是 Vue.js 的新手,我使用 ES6 语法和 vue-class-component。我在尝试从孩子向其父母发出事件时遇到问题。

我遵循了默认 Vue.js 语法的逻辑,但我的父母似乎无法捕捉到孩子发出的事件。代码:

子组件

我在每个<li> 上附加了一个单击事件侦听器,它调用了一个发出事件的函数。事件监听器是在父级上定义的。

 export default class HorizontalNavigation {

  handleClick (e) {
    e.preventDefault();
    // console.log(e.target.dataset.section);
    this.$emit('ChangeView', e.target.dataset.section);
  }

  render (h) {
    return (
      <div class={ style.horizontalNavigation } >
        <div class='sections-wrapper'>
          <div class={ style.sections }>
            <ol>
              <li><a on-click={ this.handleClick } href='#1' data-section='1' class='selected'>We are</a></li>
              <li><a on-click={ this.handleClick } href='#2' data-section='2'>Services</a></li>
              <li><a on-click={ this.handleClick } href='#3' data-section='3'>Cases</a></li>
              <li><a on-click={ this.handleClick } href='#4' data-section='4'>Studio</a></li>
              <li><a on-click={ this.handleClick } href='#5' data-section='5'>Career</a></li>
              <li><a on-click={ this.handleClick } href='#6' data-section='6'>Contact</a></li>
            </ol>

            <span class='filling-line' aria-hidden='true'></span>
          </div>
        </div>
      </div>
    );
  }
}

父组件

export default class ViewsContainer {

  ChangeView (data) {
    console.log(data);
  }

  render (h) {
      return (
        <div class={ style.restrictOverflow } >
          <HorizontalNavigation />
          <main class={ style.viewsContainer } on-ChangeView={ this.ChangeView     } >
            <SingleView dataSection='weare' id='1' class='selected' />
            <SingleView dataSection='services' id='2' />
            <SingleView dataSection='cases' id='3' />
            <SingleView dataSection='studio' id='4' />
            <SingleView dataSection='career' id='5' />
            <SingleView dataSection='contact' id='6' />
          </main>
        </div>
      );
    }
}

按照 vue.js 语法,我应该能够通过从元素发出事件来监听来自父级的子事件,但父级似乎没有捕获该事件。

我哪里错了?

【问题讨论】:

    标签: javascript ecmascript-6 vue.js


    【解决方案1】:

    您需要在要接收$emit 的视图模型上使用$emit,使用bus 或使用https://vuex.vuejs.org/

    直接发送给父级

    最简单的方法,就是简单的$emit从子组件直接到父组件:

    this.$parent.$emit('ChangeView', e.target.dataset.section);
    

    这是好的,但是如果您有一个长链组件,您需要将$emit 连接到链中的每个$parent

    通过事件总线发射

    您可以使用 Vue 非常简单地创建全局事件总线。您在主组件中创建一个 Vue 实例,然后应用程序中的所有其他组件可以emit 向它发送事件,并使用on 对这些事件做出反应。

    var bus = new Vue({});
    var vm = new Vue({
      methods: {
        changeView() {
          bus.$emit('ChangeView', e.target.dataset.section);
        }
      });
    

    也可以发送到$root,但不建议这样做。但是,如果您的 app 确实变得非常复杂,您可能需要考虑使用 Vues 自己的状态管理系统 vuex

    监听事件

    您可以使用$on 在视图模型中侦听$emit 并侦听特定事件:

        var vm = new Vue({
          created() {
             this.$on('ChangeView', section => {
                console.log(section);
              });
          }
        );
    

    如果您使用的是总线,这也类似,但您只需引用总线:

    bus.$on('ChangeView', ...);
    

    您也可以使用v-on直接在您的html中使用它:

    <div v-on:ChangeView="doSomething"></div>
    

    【讨论】:

    • 谢谢克雷格!但是你怎么听父母的,我什么都听不懂……
    • 非常感谢克雷格!我也犯了一个错误,将 on-ChangeView 侦听器放在父级而不是实例本身上。所以解决我的问题的方法是: 在 ViewsContainer 中。再次感谢您的宝贵时间!
    • 这里的ChangeView 是什么?
    • 这是救生员。感谢您的信息。
    【解决方案2】:

    Vue 中,您可以通过发出事件从子组件到父组件进行通信。 子组件 “发出”一个带有 $emit父组件 “监听”的事件 像这样:

    子组件:

    <template>
      <div>
        <button @click="this.handleClick">Click me!</button>
      </div>
    </template>
    
    <script>
    export default {
      name: "BaseButton",
      methods: {
        handleClick: function() {
          this.$emit("clickFromChildComponent");
        }
      }
    };
    </script>
    
    <style scoped>
    
    </style>
    

    父组件:

    <template>
      <div class="home">
        <h1>Passing a event from child up to parent!</h1>
        <BaseButton @clickFromChildComponent="handleClickInParent"/>
      </div>
    </template>
    
    <script>
    import BaseButton from "./BaseButton";
    
    export default {
      components: {
        BaseButton
      },
      name: "Home",
      methods: {
        handleClickInParent: function() {
          alert('Event accessed from parent!');
        }
      }
    };
    </script>
    
    <style scoped>
    
    </style>
    

    您可以找到一个工作示例代码实现 here并在您自己的上下文中使用它。

    【讨论】:

      【解决方案3】:

      除非我遗漏了某些东西(很可能),否则在像这样的简单示例中,您只需要在组件中侦听 emitted 事件即可。例如,在您的父元素中,您将拥有:

      <HorizontalNavigation v-on:ChangeView={this.ChangeView} />
      

      然后在您的子 (HorizontalNavigation) 组件中,您将 emit 'ChangeView' 事件:

      this.$emit('ChangeView', e.target.dataset.section);
      

      根据您对@craig_h 的回答所做的评论,我自己在类似的代码中尝试了这个,这正是我所需要的。我不需要 emit 给父母,也不需要使用公共汽车或 vuex。

      【讨论】:

      • 花括号在我的代码中产生问题。 没有花括号并在组件的方法中实现 ChangeView 对我有用。
      【解决方案4】:

      如果你最终在这里寻找 Vue 3 脚本设置

      使用defineEmits 声明发射然后使用返回的函数发射是一种很好的可读性做法

      子组件:

      <template>
        <div>
          <button @click="handleClick">Increment</button>
        </div>
      </template>
      
      <script setup>
      const emit = defineEmits(['custom'])
      
      const handleClick = () => {
        emit('custom')
      }
      </script>
      
      

      父组件:

      <template>
        <h1>{{ counter }}</h1>
        <Button @custom="handleCustom"/>
      </template>
      
      <script setup>
      import { ref } from 'vue'
      import Button from './components/Button.vue'
      
      const counter = ref(0)
      
      const handleCustom = () => {
        counter.value++
      }
      </script>
      

      Here is 工作实现

      【讨论】:

        猜你喜欢
        • 2022-12-27
        • 2018-09-22
        • 2019-08-29
        • 2016-03-22
        • 2012-12-01
        • 2022-01-22
        • 2022-12-01
        • 2019-01-09
        • 2022-12-28
        相关资源
        最近更新 更多