Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
401 views
in Technique[技术] by (71.8m points)

javascript - In Vue.js can a component detect when the slot content changes

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...