从插槽中的内容向父级发送事件

Fra*_*ost 7 vue.js vue-component vuejs2

我正在尝试构建一个灵活的轮播控件,允许内部元素强制更改幻灯片,以及轮播控制自身更改幻灯片

我页面中的示例结构如下所示

<my-carousel>
  <div class="slide">
    <button @click="$emit('next')">Next</button>
  </div>

  <div class="slide">
    <button @click="$emit('close')">Close</button>
  </div>
</my-carousel>
Run Code Online (Sandbox Code Playgroud)

我的旋转木马的模板就像

<div class="carousel">
  <div class="slides" ref="slides">
    <slot></slot>
  </div> 
  <footer>
   <!-- other carousel controls like arrows, indicators etc go here -->
  </footer>
</div>
Run Code Online (Sandbox Code Playgroud)

和脚本一样

...
created() {
 this.$on('next', this.next)
}
...
Run Code Online (Sandbox Code Playgroud)

访问幻灯片等没有问题,但使用$ emit将无法工作,我似乎无法找到解决此问题的简单方法.

我希望组件可以轻松重用,而不必使用

  • 中央活动巴士
  • 旋转木马内的硬编码幻灯片
  • 在页面级别实现下一个幻灯片方法并将当前索引传递给控件(因为每次使用轮播时我都必须这样做)

Dec*_*oon 13

插槽是针对父组件范围编译的,因此从插槽发出的事件将仅由模板所属的组件接收.

如果您想要轮播和幻灯片之间的交互,您可以使用范围的插槽,而这允许您将数据和方法从轮播展示到插槽.

假设你的旋转木马组件已nextclose方法:

轮播模板:

<div class="carousel">
  <div class="slides" ref="slides">
    <slot :next="next" :close="close"></slot>
  </div> 
  <footer>
    <!-- other carousel controls like arrows, indicators etc go here -->
  </footer>
</div>
Run Code Online (Sandbox Code Playgroud)

轮播示例用法:

<my-carousel>
  <template slot-scope="scope">
    <div class="slide">
      <button @click="scope.next">Next</button>
    </div>

    </div class="slide">
      <button @click="scope.close">Close</button>
    </div>
  </template>
</my-carousel>
Run Code Online (Sandbox Code Playgroud)


小智 8

我的解决方案

只需创建一个事件侦听器组件(例如“EventListener”),它所做的就是渲染默认插槽,如下所示:

事件监听器.vue

export default {
    name: 'EventListener'
    render() {
        return this.$slots.default;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在使用此<event-listener>组件并将其包装在您的<slot>. 插槽内的子组件应发出事件父像这样:this.$parent.$emit('myevent')

将您的自定义事件附加到<event-listener @myevent="handleEvent">组件。

轮播模板:

<div class="carousel">
  <event-listener @next="handleNext" @close="handleClose">
     <div class="slides" ref="slides">
       <slot></slot>
     </div> 
  </event-listener>
  <footer>
   <!-- other carousel controls like arrows, indicators etc go here -->
  </footer>
</div>
Run Code Online (Sandbox Code Playgroud)

轮播示例:

<my-carousel>
  <div class="slide">
    <button @click="$parent.$emit('next')">Next</button>
  </div>

  </div class="slide">
    <button @click="$parent.$emit('close')">Close</button>
  </div>
</my-carousel>
Run Code Online (Sandbox Code Playgroud)

注:<event-listener>组件必须只能有一个孩子的vnode。它不能是<slot>,所以我们只是将它包裹在 上div


yuk*_*say 6

只需替换$emit('next')$parent.$emit('next').

  • 可能是因为调用 $parent 是一种反模式。 (5认同)

Sye*_*yed 6

检查范围插槽。假设您的轮播组件具有fnNext以下fnClose方法:

轮播模板:

<div class="carousel">
  <div class="slides" ref="slides">
    <slot name="slide-ctrls" :events="{ fnNext, fnClose }"></slot>
  </div> 
  <footer>
    <!-- Other carousel controls like arrows, indicators etc go here -->
  </footer>
</div>
Run Code Online (Sandbox Code Playgroud)

轮播示例用法:

<my-carousel>
  <template slot="slide-ctrls" slot-scope="{ events: { fnNext, fnClose } }">
    <div class="slide">
      <button @click="fnNext">Next</button>
    </div>

    <div class="slide">
      <button @click="fnClose">Close</button>
    </div>
  </template>
</my-carousel>
Run Code Online (Sandbox Code Playgroud)

或者,使用v-slot(更干净和最新的做事方式):

<my-carousel>
  <template v-slot:slide-ctrls="{ events: { fnNext, fnClose } }">
    <div class="slide">
      <button @click="fnNext">Next</button>
    </div>

    <div class="slide">
      <button @click="fnClose">Close</button>
    </div>
  </template>
</my-carousel>
Run Code Online (Sandbox Code Playgroud)

以防万一,如果您希望看到更多扩展形式的代码而不是es6,尽管这看起来有点令人困惑,但这会向您展示事物在何处以及如何传递/使用。

<div class="carousel">
  <div class="slides" ref="slides">
    <slot name="slide-ctrls" :events="{ atClickNext: fnNext, atClickClose: fnClose }"></slot>
  </div> 
  <footer>
    <!-- Other carousel controls like arrows, indicators etc go here -->
  </footer>
</div>
Run Code Online (Sandbox Code Playgroud)

轮播示例用法:

<my-carousel>
  <template v-slot:slide-ctrls="{ events: { atClickNext: handleClickNext, atClickClose: handleClickClose } }">
    <div class="slide">
      <button @click="handleClickNext">Next</button>
    </div>

    <div class="slide">
      <button @click="handleClickClose">Close</button>
    </div>
  </template>
</my-carousel>
Run Code Online (Sandbox Code Playgroud)