在 Vue.js 中,组件可以检测槽内容何时发生变化 [英] In Vue.js can a component detect when the slot content changes

查看:18
本文介绍了在 Vue.js 中,组件可以检测槽内容何时发生变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们在 Vue 中有一个组件,它是一个框架,缩放到窗口大小,其中包含(在 中)一个元素(通常是 code> 或 ),它会缩放以适应框架,并在该元素上启用平移和缩放.

组件需要在元素发生变化时做出反应.我们可以看到这样做的唯一方法是让父级在发生这种情况时刺激组件,但是如果组件可以自动检测 元素何时发生变化并做出反应,那就更好了因此.有没有办法做到这一点?

解决方案

据我所知,Vue 没有提供解决方案.不过这里有两种方法值得考虑.

查看 Slot 的 DOM 是否有变化

使用 MutationObserver 来检测 变化.这不需要组件之间的通信.只需在组件的 mounted 回调期间设置观察者.

下面的代码片段展示了这种方法的实际效果:

Vue.component('container', {模板:'#container',数据:函数(){返回{数量:0,观察者:空}},安装:功能(){//创建观察者(以及如何处理更改...)this.observer = new MutationObserver(function(mutations) {this.number++;}.bind(this));//设置观察者this.observer.observe($(this.$el).find('.content')[0],{ 属性:true,childList:true,characterData:true,子树:true });},beforeDestroy:函数(){//清理this.observer.disconnect();}});var app = new Vue({el: '#app',数据:{数量:0},安装:功能(){//每秒更新slot中的元素setInterval(function(){ this.number++; }.bind(this), 1000);}});

.content, .container {边距:5px;边框:1px纯黑色;}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script><模板 id="容器"><div class="容器">我是容器,我检测到 {{ number }} 更新.<div class="content"><slot></slot></div>

<div id="应用程序"><容器>我就是内容,我已经更新了{{ number }}次.</容器>

使用发射

如果 Vue 组件负责更改槽位,那么最好 emit发生这种变化时的事件.这允许任何其他组件在需要时响应发出的事件.

为此,请使用一个空的 Vue 实例作为全局事件总线.任何组件都可以在事件总线上发出/监听事件.在您的情况下,父组件可以发出更新内容"事件,子组件可以对其做出反应.

这是一个简单的例子:

//使用一个空的 Vue 实例作为事件总线var bus = new Vue()Vue.component('容器', {模板:'#container',数据:函数(){返回{数量:0}},方法: {增量:function() { this.number++;}},创建:函数(){//监听 'updated-content' 事件并做出相应的反应bus.$on('更新内容', this.increment);},beforeDestroy:函数(){//清理bus.$off('更新内容', this.increment);}});var app = new Vue({el: '#app',数据:{数量:0},安装:功能(){//每秒更新槽中的元素,//并发出更新内容"事件设置间隔(函数(){this.number++;bus.$emit('更新内容');}.bind(this), 1000);}});

.content, .container {边距:5px;边框:1px纯黑色;}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script><模板 id="容器"><div class="容器">我是容器,我检测到 {{ number }} 更新.<div class="内容"><插槽></插槽>

<div id="应用程序"><容器>我就是内容,我已经更新了{{ number }}次.</容器>

We have a component in Vue which is a frame, scaled to the window size, which contains (in a <slot>) an element (typically <img> or <canvas>) which it scales to fit the frame and enables pan and zoom on that element.

The component needs to react when the element changes. The only way we can see to do it is for the parent to prod the component when that happens, however it would be much nicer if the component could automatically detect when the <slot> element changes and react accordingly. Is there a way to do this?

解决方案

To my knowledge, Vue does not provide a way to do this. However here are two approaches worth considering.

Watching the Slot's DOM for Changes

Use a MutationObserver to detect when the DOM in the <slot> changes. This requires no communication between components. Simply set up the observer during the mounted callback of your component.

Here's a snippet showing this approach in action:

Vue.component('container', {
  template: '#container',
  
  data: function() {
  	return { number: 0, observer: null }
  },
  
  mounted: function() {
    // Create the observer (and what to do on changes...)
    this.observer = new MutationObserver(function(mutations) {
      this.number++;
    }.bind(this));
    
    // Setup the observer
    this.observer.observe(
      $(this.$el).find('.content')[0],
      { attributes: true, childList: true, characterData: true, subtree: true }
    );
  },
  
  beforeDestroy: function() {
    // Clean up
    this.observer.disconnect();
  }
});

var app = new Vue({
  el: '#app',

  data: { number: 0 },
  
  mounted: function() {
    //Update the element in the slot every second
    setInterval(function(){ this.number++; }.bind(this), 1000);
  }
});

.content, .container {
  margin: 5px;
  border: 1px solid black;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>

<template id="container">
  <div class="container">
    I am the container, and I have detected {{ number }} updates.
    <div class="content"><slot></slot></div>
  </div>
</template>

<div id="app">
  
  <container>
    I am the content, and I have been updated {{ number }} times.
  </container>
  
</div>

Using Emit

If a Vue component is responsible for changing the slot, then it is best to emit an event when that change occurs. This allows any other component to respond to the emitted event if needed.

To do this, use an empty Vue instance as a global event bus. Any component can emit/listen to events on the event bus. In your case, the parent component could emit an "updated-content" event, and the child component could react to it.

Here is a simple example:

// Use an empty Vue instance as an event bus
var bus = new Vue()

Vue.component('container', {
  template: '#container',

  data: function() {
    return { number: 0 }
  },

  methods: {
    increment: function() { this.number++; }
  },
  
  created: function() {
    // listen for the 'updated-content' event and react accordingly
    bus.$on('updated-content', this.increment);
  },
  
  beforeDestroy: function() {
    // Clean up
    bus.$off('updated-content', this.increment);
  }
});

var app = new Vue({
  el: '#app',

  data: { number: 0 },

  mounted: function() {
    //Update the element in the slot every second, 
    //  and emit an "updated-content" event
    setInterval(function(){ 
      this.number++;
      bus.$emit('updated-content');
    }.bind(this), 1000);
  }
});

.content, .container {
  margin: 5px;
  border: 1px solid black;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>

<template id="container">
  <div class="container">
    I am the container, and I have detected {{ number }} updates.
    <div class="content">
      <slot></slot>
    </div>
  </div>
</template>

<div id="app">

  <container>
    I am the content, and I have been updated {{ number }} times.
  </container>
  
</div>

这篇关于在 Vue.js 中,组件可以检测槽内容何时发生变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆