我们在Vue中有一个组件,它是一个按窗口大小zoom 的框架,其中包含(在<slot>中)一个元素(通常是<img><canvas>),它可以zoom 该元素以适应框架,并可以对该元素进行平移和zoom .

当元素发生变化时,组件需要做出react .我们能看到的唯一方法是,当这种情况发生时,父级可以刺激组件,但是如果组件能够自动检测<slot>个元素的变化并做出相应的react ,那就更好了.有办法做到这一点吗?

推荐答案

据我所知,Vue并没有提供这样做的方法.然而,有两种方法值得考虑.

Watching the Slot's DOM for Changes

使用MutationObserver来检测<slot>中的DOM何时更改.这不需要组件之间的通信.只需在组件的mounted回调期间设置观察者.

下面是一个片段,展示了这种方法的实际应用:

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

如果Vue组件负责更改插槽,则最好在发生更改时更改emit an event.这允许任何其他组件在需要时响应发出的事件.

为此,请将空的Vue实例用作全局事件总线.任何组件都可以在事件总线上发出/侦听事件.在您的情况下,父组件可能会发出"更新的内容"事件,子组件可能会对此做出react .

下面是一个简单的例子:

// 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相关问答推荐

将Vite Vuejs应用部署到Apache服务器

在Vue 2中,是否可能在不创建组件的情况下注入代码块?

v-slot: activator 中 {attrs} 参数的作用是什么?

Vuetify 复选框:如何停止点击事件?

Vuex store 在 Nuxt 的什么地方

VuetifyJS,outer-link 未显示为光标

Vue:限制文本区域输入中的字符,截断过滤器?

如何将Vue的主应用程序渲染到body元素?

在 vue-router 中带有路由的 Vuejs2 模态

在 vuejs 中将旧代码修改为 vue router 4

将自定义部分添加到 v-autocomplete 下拉列表

如何在 Vue 3 中使用 SSR

vuetify:以编程方式显示对话框

我可以避免使用 Vue.js 组件的重复样式吗?

如何更改 Vuetify 日历日期格式

Nuxt 应用程序在刷新动态路由时返回 404(Tomcat 服务器)

v-if inside v-for - 在两列中显示项目列表

Vue - 如何在 v-if 或组件中使用窗口对象

NPM:403 禁止 - PUT http://registry.npmjs.org/[package-name] - 禁止

将鼠标悬停在 TailwindCSS 中的 div 上时显示按钮