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

两颗树的最小距离 #5

Closed
snowmagic1 opened this issue Jan 1, 2016 · 3 comments
Closed

两颗树的最小距离 #5

snowmagic1 opened this issue Jan 1, 2016 · 3 comments

Comments

@snowmagic1
Copy link

简单测试了一下,两颗树diff出来的结果不是最小距离 -

  var el1 = el('div', {'id': 'container'}, [el('ul'), el('li', ['1'])])
  var el2 = el('div', {'id': 'container'}, [el('ul'), el('li', ['2']), el('li', ['1'])])
  var d = diff(el1, el2)
  console.log(JSON.stringify(d))

结果是两步

{
  "0": [
    {
      "type": 1,
      "moves": [
        {
          "index": 2,
          "item": {
            "tagName": "li",
            "props": {

            },
            "children": [
              "1"
            ],
            "count": 1
          },
          "type": 1
        }
      ]
    }
  ],
  "3": [
    {
      "type": 3,
      "content": "2"
    }
  ]
}

最小的距离应该是只有一步,插入一个li

@livoras
Copy link
Owner

livoras commented Jan 1, 2016

@snowmagic1 对于列表的diff,virtual dom需要提供额外key属性来唯一标识每一个节点,才能正确进行diff(这和Reat的key属性的作用一样)。上面的写法应该为:

  var el1 = el('div', {'id': 'container'}, [el('ul'), el('li', {key: 'uid1'}, ['1'])])
  var el2 = el('div', {'id': 'container'}, [el('ul'), el('li', {key: 'uid2'}, ['2']), el('li', {key: 'uid1'}, ['1'])])
  var d = diff(el1, el2)
  console.log(JSON.stringify(d))

结果:

{
   "0":[
      {
         "type":1,
         "moves":[
            {
               "index":1,
               "item":{
                  "tagName":"li",
                  "props":{
                     "key":"uid2"
                  },
                  "children":[
                     "2"
                  ],
                  "key":"uid2",
                  "count":1
               },
               "type":1
            }
         ]
      }
   ]
}

抱歉没有在文档中写清楚,后续加上。

@livoras livoras closed this as completed in 03f213f Jan 1, 2016
@snowmagic1
Copy link
Author

ok, 我现在不太明白的地方是children reorder是做什么用的, 2种情况
如果children node没有key, 我的例子里完全可以用dsf得到同样2步的结果 - modify text + insert,所以在这种情况下reorder是多余的

所以reorder只有在children node里有key的情况下有用, 我这样理解对不对

BTW - 另外突然想起来call listdiff传了个'key'参数

@livoras
Copy link
Owner

livoras commented Jan 1, 2016

@snowmagic1 对的,只有在有key的情况下才有用,没有key的话就会按顺序对子元素进行diff。有key的话会先进行排序再进行diff。

因为在实际当中可能会对列表进行数据的新增、删除、排序。例如邮箱里面的收件箱列表,可以根据时间重新排序等等。如果没有这个key属性,在进行diff的时候,就会按顺序的进行对比,那么有可能整个列表元素的内容都会被重新构造。如果提供key的话,会找出元素移动到了什么位置,再对内容进行diff,这样就可以尽量复用元素,避免大量的DOM操作。

可以参考:https://github.com/livoras/simple-virtual-dom/blob/master/lib/diff.js#L24-L38

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

2 participants