source

Vue.js $scopedSlots가 Vue 인스턴스에서 작동하지 않음

manycodes 2023. 1. 19. 21:07
반응형

Vue.js $scopedSlots가 Vue 인스턴스에서 작동하지 않음

Clusterize.js(vue-clusterize 구성 요소가 있지만 v1.x에서만 작동)가 완료되면 게시할 Vue 구성 요소에서 작업하고 있습니다.제가 원하는 것은 Vue를 사용하여 방대한 아이템 목록을 매우 빠르게 렌더링하는 것입니다.식탁에 놓을 때 필요해요.vue-virtual-scroll로 시도했지만 테이블을 지원하지 않고 성능도 좋지 않습니다.그래서 Clusterize.js를 사용해보고 싶었습니다.

이 컴포넌트는 설정성이 높으면 좋기 때문에 아이템 리스트의 각 행에 스코프 슬롯을 제공할 수 있다고 판단했습니다.컴포넌트를 마운트하기 전에 클러스터화 컴포넌트의 스코프 슬롯을 각 행에 할당하려고 하면 동작하지 않습니다.

여기 내 코드의 일부(MVP일 뿐)가 있습니다).

클러스터화하다표시하다

템플릿

<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>

대본

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
    };
  },
};

요소.표시하다

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

문제는 스코프 슬롯을 사용하지 않으면 완벽하게 동작하지만, 꼭 사용해야 합니다.그렇지 않으면 컴포넌트에 감각이 없습니다.

어떤 도움이나 조언이라도 주시면 감사하겠습니다.잘 부탁드립니다.

이 문제는 다른 Vue 인스턴스를 동일한 Vue에 마운트하기 때문에 발생합니다.el여러 번(두 번째 데모를 살펴보십시오. 여러 인스턴스를 동일한 요소에 마운트해서는 안 됩니다. 요소가 첫 번째 인스턴스에 의해 이미 "실행"되었기 때문에 다음 인스턴스는 마운트되지 않습니다).

솔루션: Vue 인스턴스 생성(와 바인딩되지 않음)el공중에서) 그리고 나서vm.$el출력으로 사용합니다.

아래의 간단한 데모를 봐주세요.

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>

아래 데모를 참조하십시오. 동일한 Vue 인스턴스를 여러 개 생성했습니다.el그러나 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>

언급URL : https://stackoverflow.com/questions/51771893/vue-js-scopedslots-dont-work-for-vue-instance

반응형