UNPKG

easy-magix

Version:

view manager framewrok

207 lines (185 loc) 7.46 kB
/* 直接应用节点对比方案,需要解决以下问题 1. view销毁问题,节点是边对比边销毁或新增,期望是view先统一销毁,然后再统一渲染 2. 需要识别view内的节点变化,如 <div mx-viwe="app/view"> <%for(var i=0;i<count;i++){%> <span><%=i%></span> <%}%> </div> 从外层的div看,并没有变化,但是内部的节点发生了变化,该view仍然需要销毁 */ //https://github.com/DylanPiercey/set-dom/blob/master/src/index.js //https://github.com/patrick-steele-idem/morphdom var I_WrapMap = { // Support: IE <=9 only option: [1, '<select multiple="multiple">', '</select>'], // XHTML parsers do not magically insert elements in the // same way that tag soup parsers do. So we cannot shorten // this by omitting <tbody> or other required elements. thead: [1, '<table>', '</table>'], col: [2, '<table><colgroup>', '</colgroup></table>'], tr: [2, '<table><tbody>', '</tbody></table>'], td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], area: [1, '<map>', '</map>'], param: [1, '<object>', '</object>'], all: [0, '', ''] }; var I_RTagName = /<([a-z][^\/\0>\x20\t\r\n\f]+)/i; var I_RXhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi; // Support: IE <=9 only I_WrapMap.optgroup = I_WrapMap.option; I_WrapMap.tbody = I_WrapMap.tfoot = I_WrapMap.colgroup = I_WrapMap.caption = I_WrapMap.thead; I_WrapMap.th = I_WrapMap.td; var I_GetNode = function(html) { var tmp = G_DOCUMENT.createElement('div'); // Deserialize a standard representation var tag = (I_RTagName.exec(html) || [0, ''])[1].toLowerCase(); var wrap = I_WrapMap[tag] || I_WrapMap.all; tmp.innerHTML = wrap[1] + html.replace(I_RXhtmlTag, '<$1></$2>') + wrap[2]; // Descend through wrappers to the right content var j = wrap[0]; while (j--) { tmp = tmp.lastChild; } return tmp; }; var ELEMENT_TYPE = 1; var I_GetKey = function(node) { if (node.nodeType !== ELEMENT_TYPE) return; return node.id; }; //https://github.com/patrick-steele-idem/morphdom/blob/master/src/specialElHandlers.js var I_Specials = ['checked', 'disabled', 'value']; var I_SetAttributes = function(oldNode, newNode) { if (!oldNode.hasAttribute('mx-ua')) return; //没有要更新的属性 var i, a, b, ns, name; var oldAttributes = oldNode.attributes, newAttributes = newNode.attributes, nodeName = oldNode.nodeName; if (nodeName == 'INPUT' || nodeName == 'TEXTAREA') { for (i = I_Specials.length; i--;) { name = I_Specials[i]; if (oldNode[name] !== newNode[name]) { oldNode[name] = newNode[name]; } } } else if (nodeName == 'OPTION') { if (oldNode.selected != newNode.selected) { oldNode.selected = newNode.selected; } } // Remove old attributes. for (i = oldAttributes.length; i--;) { a = oldAttributes[i]; ns = a.namespaceURI; name = a.localName; b = newAttributes.getNamedItemNS(ns, name); if (!b) oldAttributes.removeNamedItemNS(ns, name); } // Set new attributes. for (i = newAttributes.length; i--;) { a = newAttributes[i]; ns = a.namespaceURI; name = a.localName; b = oldAttributes.getNamedItemNS(ns, name); if (!b) { // Add a new attribute. //newAttributes.removeNamedItemNS(ns, name); oldAttributes.setNamedItemNS(a); } else if (b.value !== a.value) { // Update existing attribute. b.value = a.value; } } }; var I_SetChildNodes = function(oldParent, newParent) { var checkOld, oldKey, checkNew, newKey, foundNode, keyedNodes; var oldNode = oldParent.firstChild; var newNode = newParent.firstChild; var extra = 0; // Extract keyed nodes from previous children and keep track of total count. while (oldNode) { extra++; checkOld = oldNode; oldKey = I_GetKey(checkOld); oldNode = oldNode.nextSibling; if (oldKey) { if (!keyedNodes) keyedNodes = {}; keyedNodes[oldKey] = checkOld; } } // Loop over new nodes and perform updates. oldNode = oldParent.firstChild; while (newNode) { extra--; checkNew = newNode; newNode = newNode.nextSibling; if (keyedNodes && (newKey = I_GetKey(checkNew)) && (foundNode = keyedNodes[newKey])) { delete keyedNodes[newKey]; // If we have a key and it existed before we move the previous node to the new position if needed and diff it. if (foundNode !== oldNode) { oldParent.insertBefore(foundNode, oldNode); } else { oldNode = oldNode.nextSibling; } I_SetNode(foundNode, checkNew); } else if (oldNode) { checkOld = oldNode; oldNode = oldNode.nextSibling; if (I_GetKey(checkOld)) { // If the old child had a key we skip over it until the end. oldParent.insertBefore(checkNew, checkOld); } else { // Otherwise we diff the two non-keyed nodes. I_SetNode(checkOld, checkNew); } } else { // Finally if there was no old node we add the new node. oldParent.appendChild(checkNew); } } // Remove old keyed nodes. for (oldKey in keyedNodes) { extra--; oldParent.removeChild(keyedNodes[oldKey]); } // If we have any remaining unkeyed nodes remove them from the end. while (--extra >= 0) { oldParent.removeChild(oldParent.lastChild); } }; var I_SetNode = function(oldNode, newNode) { if (oldNode.nodeType === newNode.nodeType) { // Handle regular element node updates. if (oldNode.nodeType === ELEMENT_TYPE) { // Update all children (and subchildren). I_SetChildNodes(oldNode, newNode); // Update the elements attributes / tagName. if (oldNode.nodeName === newNode.nodeName) { // If we have the same nodename then we can directly update the attributes. I_SetAttributes(oldNode, newNode); } else { // Otherwise clone the new node to use as the existing node. var newPrev = newNode.cloneNode(); // Copy over all existing children from the original node. while (oldNode.firstChild) newPrev.appendChild(oldNode.firstChild); // Replace the original node with the new one with the right tag. oldNode.parentNode.replaceChild(newPrev, oldNode); } } else { // Handle other types of node updates (text/comments/etc). // If both are the same type of node we can update directly. if (oldNode.nodeValue !== newNode.nodeValue) { oldNode.nodeValue = newNode.nodeValue; } } } else { // we have to replace the node. oldNode.parentNode.replaceChild(newNode, oldNode); } }; var Increment = function(oldNode, newHTML) { var newNode = I_GetNode(newHTML); I_SetChildNodes(oldNode, newNode); };