javascript - 移动到其他数组时 Vue 保持事件组件

标签 javascript vue.js vuejs2 vue-component

在将绑定(bind)项对象移动到不同的数据数组时,我试图让组件保持事件状态。因为它被移动了,所以默认的 keep-alive 标签不起作用。

当我的应用程序中的动态组件使用外部库时,我需要它来缩短加载时间。

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

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:

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' }
        ]
      }
    ]
  }
})

最佳答案

如果问题只是缓存昂贵的 html 构建之一,您可以通过从模板中删除 list-item 组件并在 app.mounted( )

这在您的真实场景中的效果取决于 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>

react 性item.content

要在 item.content 更改时保持响应,您需要更多代码。

  • item.content 的副本添加到缓存
  • 添加一个方法,在内容发生变化时通过刷新获取缓存的 html。

(您可以使用参数化计算属性更优雅地执行此操作)。

为了模拟 item.content 的变化,我在 mounted() 中添加了一个 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>

关于javascript - 移动到其他数组时 Vue 保持事件组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49732777/

相关文章:

javascript - 拖放图片上传并删除 URL(不是文件)

javascript - Webpack 中多个入口点的通用样板

javascript - 如何从 Node.js 中的 base64 字符串发送表单数据中的文件?

vue.js - 使用 Vee-validate 禁用按钮,直到正确填写表单

javascript - Vuejs 如何将数据作为 Prop 传递给子组件

javascript - Vuetify 数据表项槽中的文本字段

javascript - 如何在 jQuery 函数中使用 options var?

vue.js - 导入目录中的所有文件,而不必明确指定每个文件

css - vue-multiselect 下拉列表没有水平滚动条

javascript - 在 Vue 中渲染只读内容的最佳方法