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

and*_*esz 5 javascript vue.js clusterize vuejs2

我正在开发一个 Vue 组件,该组件完成后将发布,该组件包装了Clusterize.js(有一个 vue-clusterize 组件,但它仅适用于 v1.x)。我想要实现的是使用 Vue 快速渲染大量项目。我实际上需要它来一张桌子。我尝试使用vue-virtual-scroll但它不支持表格并且性能不是很好。所以我想尝试使用 Clusterize.js。

因为我希望这个组件具有高度可配置性,所以我决定您将能够为您将在其中接收项目的项目列表的每一行提供一个作用域插槽。问题是,当我尝试在安装组件之前将集群组件中的范围插槽分配给每一行时,它不起作用。

这里有我的一些代码片段(它只是一个 mvp)

集群化.vue

模板

<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>
Run Code Online (Sandbox Code Playgroud)

脚本

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
    };
  },
};
Run Code Online (Sandbox Code Playgroud)

组件.vue

<clusterize :items="test">
  <template slot-scope="props">
    item
  </template>
</clusterize>
Run Code Online (Sandbox Code Playgroud)

问题是,如果它不使用范围插槽,它可以完美工作,但我确实需要使用它们,否则该组件没有任何意义。

我将不胜感激任何帮助或建议。预先非常感谢您。

Sph*_*inx 2

该问题应该是由于el多次将不同的 Vue 实例挂载到相同的实例引起的(请查看第二个演示,您不应该将多个实例挂载到同一元素以下实例将不会挂载,因为该元素已经是 \xe2\x80\ x9c被第一个实例阻止\xe2\x80\x9d)。

\n\n

我的解决方案el:在空中创建 Vue 实例(不绑定),然后vm.$el作为输出。

\n\n

请看下面的简单演示,

\n\n

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

\n\n

请看下面的演示:创建了多个 Vue 实例到 same el,但是 Vue 总是使用第一个实例来渲染(我在 Vue Guide 中找不到任何有用的语句,可能从 Vue Github 的源代码中我们可以找到逻辑。如果有人知道,请随时编辑我的答案或添加评论)。

\n\n

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

\n