vddl
vddl copied to clipboard
解决key键重复 fix Duplicate keys detected
下载你的包,本地安装完毕,web运行正常,把demo例子拷贝到electron写的容器会报以下错误
Duplicate keys detected: 'Item A1'. This may cause an update error.
很奇怪。。。不知道如果修改组建才不会有这个提示呢?
又经过一次调试发现
handleMoved ({ index }) {
this.lists.splice(index, 1)
console.warn('1',new Date())
},
handleDrop (draggable) {
console.warn('2',new Date())
this.lists.splice(draggable.index, 0, draggable.item)
}
原因,应该是插件设计的问题,
插入方法比删除方法执行还要早出发,所以导致了有重复键的出现(也有可能不同浏览器的渲染差异造成)
解决办法hack:
给handleDrop
延迟执行,避免把copy元素先插入,这样2个重复的元素是导致我们出bug的主要原因
//但如果拖拉动作过快,也会可能产生以上的bug,原因已经说了
handleDrop (draggable) {
setTimeout(()=>{
// '延迟操作'
this.lists.splice(draggable.index, 0, draggable.item)
})
//或者 使用 this.$nextTick
}
最终比较完美的解决办法 1.把handleDrop 传入的对象 缓存起来 2.直接在 handleMoved 函数里面 把 删除操作完成
handleMoved (targetDraggable) {
//删除元素操作
this.lists.splice(targetDraggable.index, 1)
//插入之前的旧元素,为了安全使用了$nextTick,当然你可以不要也没什么问题
this.$nextTick(()=>{
this.lists.splice(this.delDraggable.index, 0, this.delDraggable.item)
})
},
handleDrop (draggable) {
//缓存起来
this.delDraggable = draggable;
}
@yyman001 抱歉,最近有点忙,我现在看一下。
这应该是用了最新版的Vue2而产生的问题,原本设计就是drop会比moved先触发,错误的提示是来自drop执行的时候,插入了一个和被拖动一样的元素。这个目前应该不会影响功能,或者先把Vue版本降一下。我暂时没有很好的解决方案,让我再想想。
@hejianxian 其他demo一样会触发这个错误的,但我看源码(修改module里面的源文件),也没法定位是哪个方法删除
和插入
,项目需要用到这个nested.vue
,这种嵌套性,就更难修正这个bug,现在我想看看能不能暂时修复下。
@yyman001 主要原因是因为在列表触发 drop 事件的时候,需要进行列表数据的插入操作,而插入的数据就是被拖动起来的那个,而这个数据此时还没有被删除,这样新插入的数据在key值上的确是重复的。这个感觉是 Vue 换成 Prxoy之后才出现的问题。
@hejianxian 确实是这样的,就是那个嵌套的例子和源码有些功能有点复杂,例如我写了个自定义的drop事件,会把拖拉的元素删除,并没有添加成功,这个要用到vuex,如果可以把删除和添加方法暴露的更清晰点就好了,可以让自己控制,但现在我改源码调试也没有办法调试得出具体在哪里写这个操作,想配合vuex,现在不懂怎么处理,好尴尬,能力太弱。
@hejianxian 先删再添加,又引发一个bug,就是拖拽,如果由下往上,插入的位置是正确的,如果从上向下拖,位置会+1,位置不正确。。。真是头疼
@hejianxian @AWulkan 我又想到了另外一个方法,是这样的 1.在插入的数据的时候,用一个别的对象(B占位符对象)来替换这个一样的元素A副本,当然这个对象跟之前那些一样,除了key值外,防止报错 2.然后接着删除旧的复制元素A的本体 3.把占位符替换为原来的那个拖拽元素A副本 另外,我是想了另外一个办法,是拷贝那个list数组为fix-list,然后完成上面的fix操作,最后替换原来的那个list,但这个有个问题,就是没办法把整个数组替换?我翻阅了官网和网上一些资料都没找到。 具体代码
this.temp = null
this.placeholderObject = {'label':'placeholderObject'}
handleDrop(data) {
console.log(':v-list: drop');
const { index, list, item } = data;
this.temp = data
//1. 使用占位符对象
list.splice(index, 0, this.placeholderObject);
},
handleMoved(item) {
console.log(':v-draggable: moved');
let vm = this
const { index, list } = item;
//拷贝数组
const fix_list = list.concat()
//key,用来查找占位符对象,如果找不到-1会把最后一个元素删了
let _key = -1;
//修复前的数组
console.warn('1-fix_list:', JSON.stringify(fix_list));
//删除本
list.splice(index, 1)
fix_list.splice(index, 1)
fix_list.forEach(function (item, key) {
console.log(key,JSON.stringify(item) ,JSON.stringify(item) === JSON.stringify(vm.placeholderObject));
//如果找到占位符对象记录key
if(JSON.stringify(item) === JSON.stringify(vm.placeholderObject)){
_key = key
//不在这里替换,会报错,具体原因不知道
}
});
fix_list[_key] = this.temp.item
//替换占位符对象
this.$set(item.list,_key,this.temp.item)
//修复后的数组
console.warn('2-fix_list:', JSON.stringify(fix_list));
// item.list = fix_list 这个不是响应的,试图不会更新
}
发现占位符getPlaceholderIndex()方法获取index好像不太正确。 最后更新方法:不清楚有时候拖拽会报key 1重复。。。
[SAVE_DATA] (state, destinationData) {
console.log('目标index:', destinationData.index);
state.destinationData.index = destinationData.index
state.destinationData.item = destinationData.item
state.destinationData.list = destinationData.list
destinationData.list.splice(destinationData.index, 0, state.placeholderObject);
},
[UPDATE_ITEM] (state, originItem){
//1. 删除原数据
originItem.list.splice(originItem.index, 1)
//fix 计算占位符索引,同级拖拽由上往下,无法正确找到正确的索引(具体原因不清楚)
let fixDestinationDataIndex = -1; //默认是未找到
let placeholderObjectString = JSON.stringify(state.placeholderObject)
state.destinationData.list.forEach(function (_item, key) {
console.log(key, JSON.stringify(_item), JSON.stringify(_item) === placeholderObjectString);
if (JSON.stringify(_item).indexOf(placeholderObjectString) > -1) {
fixDestinationDataIndex = key
}
});
console.log('修正查找目标的索引:', fixDestinationDataIndex);
//2.删除占位符
state.destinationData.list.splice(fixDestinationDataIndex, 1)
//3.插入原数据
state.destinationData.list.splice(fixDestinationDataIndex, 0, state.destinationData.item)
}
+1. We get this warning, it's transitory I think, a moment later there are no duplicate keys anymore.