Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

解决key键重复 fix Duplicate keys detected #27

Open
yyman001 opened this issue Dec 22, 2017 · 10 comments
Open

解决key键重复 fix Duplicate keys detected #27

yyman001 opened this issue Dec 22, 2017 · 10 comments

Comments

@yyman001
Copy link

下载你的包,本地安装完毕,web运行正常,把demo例子拷贝到electron写的容器会报以下错误

Duplicate keys detected: 'Item A1'. This may cause an update error.

很奇怪。。。不知道如果修改组建才不会有这个提示呢?

@yyman001 yyman001 changed the title electron-vue框架里面调用会报错Duplicate keys detected 解决key键重复 fix Duplicate keys detected Dec 23, 2017
@yyman001
Copy link
Author

yyman001 commented Dec 23, 2017

又经过一次调试发现

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

@hejianxian
Copy link
Owner

@yyman001 抱歉,最近有点忙,我现在看一下。

@hejianxian
Copy link
Owner

这应该是用了最新版的Vue2而产生的问题,原本设计就是drop会比moved先触发,错误的提示是来自drop执行的时候,插入了一个和被拖动一样的元素。这个目前应该不会影响功能,或者先把Vue版本降一下。我暂时没有很好的解决方案,让我再想想。

@yyman001
Copy link
Author

@hejianxian 其他demo一样会触发这个错误的,但我看源码(修改module里面的源文件),也没法定位是哪个方法删除插入,项目需要用到这个nested.vue,这种嵌套性,就更难修正这个bug,现在我想看看能不能暂时修复下。

@hejianxian
Copy link
Owner

@yyman001 主要原因是因为在列表触发 drop 事件的时候,需要进行列表数据的插入操作,而插入的数据就是被拖动起来的那个,而这个数据此时还没有被删除,这样新插入的数据在key值上的确是重复的。这个感觉是 Vue 换成 Prxoy之后才出现的问题。

@yyman001
Copy link
Author

@hejianxian 确实是这样的,就是那个嵌套的例子和源码有些功能有点复杂,例如我写了个自定义的drop事件,会把拖拉的元素删除,并没有添加成功,这个要用到vuex,如果可以把删除和添加方法暴露的更清晰点就好了,可以让自己控制,但现在我改源码调试也没有办法调试得出具体在哪里写这个操作,想配合vuex,现在不懂怎么处理,好尴尬,能力太弱。

@yyman001
Copy link
Author

@hejianxian 先删再添加,又引发一个bug,就是拖拽,如果由下往上,插入的位置是正确的,如果从上向下拖,位置会+1,位置不正确。。。真是头疼

@yyman001
Copy link
Author

@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 这个不是响应的,试图不会更新
    }

@yyman001
Copy link
Author

yyman001 commented Jan 1, 2018

发现占位符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)

  }

@boutell
Copy link

boutell commented Nov 16, 2018

+1. We get this warning, it's transitory I think, a moment later there are no duplicate keys anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants