简体   繁体   English

Vue.js $ scopedSlots不适用于Vue实例

[英]Vue.js $scopedSlots don't work for Vue instance

I'm working in a Vue component that I'll publish when it's finished that wraps Clusterize.js (there is a vue-clusterize component but it only works for v1.x). 我正在使用Vue组件,我将在它完成时发布包装Clusterize.js (有一个vue-clusterize组件但它只适用于v1.x)。 What I want to achieve is to render a huge list of items pretty fast using Vue. 我想要实现的是使用Vue快速渲染大量项目。 I actually need it for a table. 我实际上需要一张桌子。 I tried with vue-virtual-scroll but it doesn't support tables and the performance is not that good. 我尝试使用vue-virtual-scroll但是它不支持表格并且性能不是那么好。 So I wanted to try with Clusterize.js. 所以我想尝试使用Clusterize.js。

Because I want this component to be highly configurable I decided that you will be able to provide a scoped slot for each row of the items list where you will receive the item. 因为我希望这个组件具有高度可配置性,所以我决定您将能够为您将收到该项目的项目列表的每一行提供一个范围的插槽。 The problem is when I try to assign the scoped slot from the clusterize componets to each row before mounting the component it doesn't work. 问题是当我尝试在安装组件之前将clusterize componets中的作用域槽分配给每一行时,它不起作用。

Here you have some snippets of my code (it is just a mvp) 在这里你有我的代码的一些片段(它只是一个mvp)

clusterize.vue clusterize.vue

Template 模板

<div class="clusterize">
<table>
  <thead>
    <tr>
      <th>Headers</th>
    </tr>
  </thead>
</table>
<div
  ref="scroll"
  class="clusterize-scroll">
  <table>
    <tbody
      ref="content"
      class="clusterize-content">
      <tr class="clusterize-no-data">
        <td>Loading...</td>
      </tr>
    </tbody>
  </table>
</div>

Script 脚本

import Vue from 'vue';
import Clusterize from 'clusterize.js';

export default {
  name: 'Clusterize',
  props: {
    items: {
      type: Array,
      required: true,
    },
  },
  data() {
    return {
      clusterize: null,
    };
  },
  computed: {
    rows() {
      return this.items.map(item => '<tr><slot :item="1"/></tr>');
    },
  },
  watch: {
    rows() {
      this.clusterize.update(this.rows);
    },
  },
  mounted() {
    const scrollElem = this.$refs.scroll;
    const contentElem = this.$refs.content;

    this.clusterize = new Clusterize({
      rows: this.rows,
      scrollElem,
      contentElem,
    });

    this.clusterize.html = (template) => {
      contentElem.innerHTML = template;
      const instance = new Vue({ el: contentElem });

      instance.$slots = this.$slots;
      instance.$scopedSlots = this.$scopedSlots;
      instance.$mount();

      console.log(instance.$scopedSlots); // empty
      console.log(instance.$slots) // not empty
    };
  },
};

component.vue component.vue

<clusterize :items="test">
  <template slot-scope="props">
    item
  </template>
</clusterize>

The thing is that if it don't use a scoped slot it works perfectly but I really need to use them otherwise the component doesn't have any sense. 问题是如果它不使用范围的插槽它完美地工作但我真的需要使用它们否则组件没有任何意义。

I'll appreciate any help or advice. 我会感谢任何帮助或建议。 Thank you so much in advance. 非常感谢你提前。

The issue should be caused by mount different Vue instance to same el multiple times (please look into the second demo, you shouldn't mount multiple instances to same element , the following instances will not mount since the element is already “blocked” by first instance ). 该问题应该是由多次将不同的Vue实例挂载到同一个el (请查看第二个演示, 不应该将多个实例挂载到同一个元素以下实例将不会挂载,因为该元素已被“阻塞”实例 )。

My solution : create Vue instance (doesn't bind to el ) in the air then take vm.$el as the output. 我的解决方案 :在空中创建Vue实例(不绑定到el )然后以vm.$el作为输出。

Please look into below simple demo, 请看下面的简单演示,

 Vue.config.productionTip = false Vue.component('clusterize', { template: `<div class="clusterize"> <table> <thead> <tr> <th>Headers</th> </tr> </thead> </table> <div ref="scroll" class="clusterize-scroll"> <table> <tbody ref="content" id="clusterize-id" class="clusterize-content"> <tr class="clusterize-no-data"> <td>Loading...</td> </tr> </tbody> </table> </div></div>`, props: { items: { type: Array, required: true, }, }, data() { return { clusterize: null, clusterVueInstance: null }; }, computed: { rows() { return this.items.map(item => { return '<tr><td><span>' +item+'</span><slot :item="1"/></td></tr>' }); }, }, watch: { rows() { this.clusterize.update(this.rows); }, }, mounted() { const scrollElem = this.$refs.scroll; const contentElem = this.$refs.content; this.clusterize = new Clusterize({ rows: this.rows, scrollElem, contentElem, }); this.clusterize.html = (template) => { this.clusterize.content_elem.innerHTML = template; if(this.clusterVueInstance) { this.clusterVueInstance.$destroy() this.clusterVueInstance = null } this.clusterVueInstance = new Vue({ template: '<tbody>'+template+'</tbody>' }) //or use Vue.extend() this.clusterVueInstance.$slots = this.$slots this.clusterVueInstance.$scopedSlots = this.$scopedSlots this.clusterVueInstance.$mount() this.clusterize.content_elem.innerHTML = this.clusterVueInstance.$el.innerHTML //console.log(this.clusterVueInstance.$scopedSlots); // empty //console.log(this.clusterVueInstance.$slots) // not empty*/ }; } }) app = new Vue({ el: "#app", data() { return { test: ['Puss In Boots', 'test 1', 'test2'], index: 0 } }, mounted: function () { //this.test = ['Puss In Boots', 'test 1', 'test2'] }, methods: { addItem: function () { this.test.push(`test ` + this.index++) } } }) 
 <link href="https://cdn.bootcss.com/clusterize.js/0.18.0/clusterize.min.css" rel="stylesheet"/> <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script> <script src="https://cdn.bootcss.com/clusterize.js/0.18.0/clusterize.min.js"></script> <div id="app"> <button @click="addItem()"> Add Item </button> <clusterize :items="test"> <template slot-scope="props"> item: {{props.item}} </template> </clusterize> </div> 

Please look into below demo: created multiple Vue instance to same el , but Vue always uses first instance to render (I can't find any useful statement at Vue Guide, probably from the source codes from Vue Github we can find out the logic. If someone knows, please feel free to edit my answer or add a comment). 请看下面的演示:为同一个el创建多个Vue实例,但Vue总是使用第一个实例进行渲染(我在Vue Guide找不到任何有用的语句,可能来自Vue Github的源代码,我们可以找到逻辑。如果有人知道,请随时编辑我的答案或添加评论)。

 Vue.config.productionTip = false app1 = new Vue({ el: '#app', data () { return { test: 'test 1' } }, mounted(){ console.log('app1', this.test) } }) app2 = new Vue({ el: '#app', data () { return { test: 'test 2' } }, mounted(){ console.log('app2', this.test) } }) //app1.$data.test = 3 //app1.$mount() //manual mount app2.$data.test = 4 app2.$mount() //manual mount 
 <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script> <script src="https://cdn.bootcss.com/clusterize.js/0.18.0/clusterize.min.js"></script> <div id="app"> <a>{{test}}</a> </div> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM