简体   繁体   English

当移动到其他阵列时,Vue保持活动组件

[英]Vue keep alive component when moving to other array

I'm trying to keep a component alive when moving the bound item object to a different data array. 我正在尝试在将绑定的项目对象移动到不同的数据数组时保持组件处于活动状态。 Because it gets moved, the default keep-alive tag doesn't work. 因为它被移动,默认的keep-alive标签不起作用。

I need this to improve loading time when dynamic components in my app use external libraries. 当我的应用程序中的动态组件使用外部库时,我需要这个来改善加载时间。

Simplified example: ( https://jsfiddle.net/eywraw8t/24419/ ) 简化示例:https://jsfiddle.net/eywraw8t/24419/

HTML: HTML:

<div id="app">
  <div v-for="list in lists">
    <h1>{{ list.title }}</h1>
    <ul>
      <draggable v-model="list.items" :options="{group: 'list-items'}">
        <list-item 
           v-for="item in list.items" 
           :key="item.key" 
           :content="item.content">
        </list-item>
      </draggable>
    </ul>
  </div>
</div>

JS: JS:

Vue.component('list-item', {
  props: {
    content: {
        required: true
    }
  },
  mounted () {
    document.body.insertAdjacentHTML('beforeend', 'Mounted! ');
  },
  template: '<li>{{ content }}</li>'
})

new Vue({
  el: "#app",
  data: {
    lists: [
        {
        title: 'List 1',
        items: [
            { key: 'item1', content: 'Item 1' },
          { key: 'item2', content: 'Item 2' },
          { key: 'item3', content: 'Item 3' }
        ]
      },
      {
        title: 'List 2',
        items: [
            { key: 'item4', content: 'Item 4' },
          { key: 'item5', content: 'Item 5' },
          { key: 'item6', content: 'Item 6' }
        ]
      }
    ]
  }
})

i looked into your problem and i think i might found a solution, i cannot do it in js fiddle but i'll try and explain it: 我调查了你的问题,我想我可能会找到一个解决方案,我不能在js小提琴中做,但我会尝试解释它:

in your js fiddle the mounted is hooked in your list-item component, so indeed every time that state changed (when dragging), the event is triggered. 在你的js小提琴中,mount被挂钩在你的list-item组件中,所以每次状态改变时(拖动时)都会触发事件。

i create a setup with a main templated component (componentX), with a mounted function, and then created a seperated list-item component 我使用主模板组件(componentX)创建一个安装程序,使用已安装的函数,然后创建一个单独的列表项组件

in my sample you will see the mounted twice at the start, that is normal since we have 2 lists! 在我的示例中,您将看到在开始时安装两次,这是正常的,因为我们有2个列表! but then when you start to drag and drop you will not get additional mounted events 但是当你开始拖放时,你不会得到额外的挂载事件

you can download the solution in a zip from: 您可以从以下位置下载解压缩解决方案:

http://www.bc3.eu/download/test-vue.zip http://www.bc3.eu/download/test-vue.zip

it is a vue cli project, so you can just npm run dev to start a local server 它是一个vue cli项目,所以你可以npm run dev来启动本地服务器

If the problem is just one of caching expensive html build, you can do it by removing the list-item component from the template and building them ahead of time in app.mounted() . 如果问题只是缓存昂贵的html构建问题,你可以通过从模板中删除list-item组件并在app.mounted()提前构建它们来app.mounted()

How well this works in your real-world scenario depends on the nature of item.content and it's lifecycle. 它在现实世界中的效果如何,取决于item.content的性质和它的生命周期。

 console.clear() const ListItem = Vue.component('list-item', { props: { content: { required: true } }, mounted () { document.body.insertAdjacentHTML('beforeend', 'Mounted! '); }, template: '<li>{{ content }}</li>' }) new Vue({ el: "#app", methods: { getHtml(content) { const li = new ListItem({propsData: {content}}); li.$mount() return li.$el.outerHTML } }, mounted () { this.lists.forEach(list => { list.items.forEach(item => { const cacheHtml = this.getHtml(item.content) Vue.set( item, 'cacheHtml', cacheHtml ) }) }) }, data: { lists: [ { title: 'List 1', items: [ { key: 'item1', content: 'Item 1' }, { key: 'item2', content: 'Item 2' }, { key: 'item3', content: 'Item 3' } ] }, { title: 'List 2', items: [ { key: 'item4', content: 'Item 4' }, { key: 'item5', content: 'Item 5' }, { key: 'item6', content: 'Item 6' } ] } ] } }) 
 ul { margin-bottom: 20px; } li:hover { color: blue; cursor: move; } h1 { font-size: 20px; font-weight: bold; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.6.0/Sortable.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/15.0.0/vuedraggable.min.js"></script> <div id="app"> <div v-for="list in lists"> <h1>{{ list.title }}</h1> <ul> <draggable v-model="list.items" :options="{group: 'list-items'}"> <div v-for="item in list.items" :key="item.key"> <li v-html="item.cacheHtml"></li> </div> </draggable> </ul> </div> </div> 

Reactive item.content 反应性item.content

To keep reactivity when item.content changes, you will need a little more code. 要在item.content更改时保持反应性,您需要更多代码。

  • add a copy of the item.content to the cache item.content的副本添加到缓存中
  • add a method to fetch the cached html with refresh if content has changed. 如果内容已更改,请添加一个方法来获取缓存的html并刷新。

(You may be able to do this a little more elegantly with a parameterized computed property). (您可以使用参数化计算属性更优雅地执行此操作)。

To simulate an item.content change, I've added a setTimeout to mounted(). 为了模拟item.content更改,我在mount()中添加了一个setTimeout。

 console.clear() const ListItem = Vue.component('list-item', { props: { content: { required: true } }, mounted () { document.body.insertAdjacentHTML('beforeend', 'Mounted! '); }, template: '<li>{{ content }}</li>' }) new Vue({ el: "#app", methods: { getHtml(content) { const li = new ListItem({ propsData: { content } }); li.$mount() return li.$el.outerHTML }, cacheHtml(item) { if (item.cache && item.cache.content === item.content) { return item.cache.html } else { const html = this.getHtml(item.content) const cache = {content: item.content, html} Vue.set(item, 'cache', cache) } } }, mounted () { this.lists.forEach(list => { list.items.forEach(item => { this.cacheHtml(item) }) }) setTimeout(() => Vue.set( this.lists[0].items[0], 'content', 'changed' ) ,2000) }, data: { lists: [ { title: 'List 1', items: [ { key: 'item1', content: 'Item 1' }, { key: 'item2', content: 'Item 2' }, { key: 'item3', content: 'Item 3' } ] }, { title: 'List 2', items: [ { key: 'item4', content: 'Item 4' }, { key: 'item5', content: 'Item 5' }, { key: 'item6', content: 'Item 6' } ] } ] } }) 
 ul { margin-bottom: 20px; } li:hover { color: blue; cursor: move; } h1 { font-size: 20px; font-weight: bold; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.6.0/Sortable.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/15.0.0/vuedraggable.min.js"></script> <div id="app"> <div v-for="list in lists"> <h1>{{ list.title }}</h1> <ul> <draggable v-model="list.items" :options="{group: 'list-items'}"> <div v-for="item in list.items" :key="item.key"> <li v-html="cacheHtml(item)"></li> </div> </draggable> </ul> </div> </div> 

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

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