Alfred-Skyblue / vue-draggable-plus

Universal Drag-and-Drop Component Supporting both Vue 3 and Vue 2
https://vue-draggable-plus.pages.dev/en/
MIT License
2.72k stars 106 forks source link

拖拽克隆、使用拖拽克隆组件时,列表2中无法使用动态组件渲染 #74

Closed LMchensir closed 6 months ago

LMchensir commented 6 months ago

node版本:18.16.0 vue版本:^3.3.4 vite版本:^4.4.5 1703226917579(1)

我新建了一个项目,用来试用 vue-draggable-plus 的功能,我现在发现一个问题(我录制了一个视频,但是预览播放时,发现没有画面,如果你也遇到,可以下载下来观看,谢谢) list1克隆到list2的时候, myComponentList2 中已经有数据了,但是在右侧列表中却没有渲染出组件

https://github.com/Alfred-Skyblue/vue-draggable-plus/assets/51938074/6256895c-0fbb-4127-b69c-c38c3708a6b9

<VueDraggable
  class="drag_list_left"
  v-model="myComponentList"
  animation="150"
  :group="{ name: 'doubleListDrag', pull: 'clone', put: true }"
  @end="onEnd"
>
  <template v-for="item in myComponentList" :key="item.name">
    <component :is="item.component"></component>
  </template>
</VueDraggable>
<VueDraggable class="drag_list_right" v-model="myComponentList2" animation="150" group="doubleListDrag">
  <template v-for="item in myComponentList2" :key="item.name">
    <component :is="item.component"></component>
  </template>
</VueDraggable>
<div>
  <template v-for="item in myComponentList2" :key="item.name">
    <div>{{ item.name }}</div>
  </template>
</div>
import { ref } from 'vue';
import { VueDraggable } from 'vue-draggable-plus';
import myCom_1 from '@/components/myCom_1.vue';
import myCom_2 from '@/components/myCom_2.vue';
import myCom_3 from '@/components/myCom_3.vue';
import myCom_4 from '@/components/myCom_4.vue';
import myCom_5 from '@/components/myCom_5.vue';
// 组件列表1
const myComponentList = ref([
  { component: myCom_1, name: 'myCom_1' },
  { component: myCom_2, name: 'myCom_2' },
  { component: myCom_3, name: 'myCom_3' },
  { component: myCom_4, name: 'myCom_4' },
  { component: myCom_5, name: 'myCom_5' },
]);
// 组件列表2
const myComponentList2 = ref([]);
// 拖拽克隆函数
const onEnd = (event) => {
  console.log('onEnd_event', event);
  console.log('myComponentList2', myComponentList2.value);
  console.log('myComponentList', myComponentList.value);
};
.doubleListDrag {
  display: flex;
  background-color: #eceff7;
  padding: 30px;
  .preview_wrap {
    .preview_item {
      padding: 10px;
    }
  }
  .drag_list_left {
    border: 2px dashed #ccc;
    padding: 10px;
  }
  .drag_list_right {
    min-width: 260px;
    border: 2px solid #ccc;
    padding: 10px;
    margin-left: 30px;
  }
}

image

myCom_1 到 myCom_5,都是一个带样式的div,没有特殊功能在里面 image

JaguarJack commented 6 months ago

遇到同样的问题。目前好像只能把组件做成一个 key:value 对象,拖拽的对象的 component 使用字符串,然后根据对象 key 获取组件渲染 目前正常工作。 但是不知道为啥 clone 的时候不行

JaguarJack commented 6 months ago

遇到同样的问题。目前好像只能把组件做成一个 key:value 对象,拖拽的对象的 component 使用字符串,然后根据对象 key 获取组件渲染 目前正常工作。 但是不知道为啥 clone 的时候不行

看了下源码,可能是拷贝的时候使用 JSON.stringify()导致的?还是自己修改 clone 方法吧

LMchensir commented 6 months ago

遇到同样的问题。目前好像只能把组件做成一个 key:value 对象,拖拽的对象的 component 使用字符串,然后根据对象 key 获取组件渲染 目前正常工作。 但是不知道为啥 clone 的时候不行

看了下源码,可能是拷贝的时候使用 JSON.stringify()导致的?还是自己修改 clone 方法吧

@JaguarJack

我看他这个库提供了一个自定义克隆的属性 :clone 这个属性和 @clone 方法不太一样

image

image

我打印了两个函数的 event 形参(两个参数不一样,handleCustomClone 输出了组件实例)

image

当我使用 :clone 属性定义一个 handleCustomClone 函数,并将 event 形参返回出去后

const handleCustomClone = (event) => { console.log('handleCustomClone_event', event); return event; };

list2就可以使用vue中的动态组件 <component :is="item.component"></component> 来渲染了

image

源码我没有细看,我觉得还是因为 JSON 深拷贝导致的问题,JSON 深拷贝之后的组件是无法渲染出来的

image image

Alfred-Skyblue commented 6 months ago

Please note that when cloning, the essence is to create a deep copy of the data, and internally, JSON is used for deep copying. This method may result in the loss of certain properties. Additionally, Vue does not recommend placing the constructor of a component into reactive data. Instead, you should construct a map to control the display of a specific component, rather than adding the component's constructor to a ref. If you must use this approach, please pass the "clone" parameter, which accepts a function for you to manually copy it.

JaguarJack commented 6 months ago

所以还是建议使用 MAP 映射,{'component': component } 映射, import 到页面中吧,clone 是没办法实现这个的。我目前做了一些尝试,都没有成功。我个人能力有限,放弃了使用 clone,转到 map 映射的方式了