对于节点的创建innerHTML是一个很高效的接口。jQuery在节点操作上使用了innerHTML,创建效率上来说至少比createElement快了2-10倍不等,而且还能一次性生成一堆的节点,但是随之而来就有一些兼容性问题,
我总结了有以下几点,当然兼容上也结合了jQuery的解决方案。
jQuery的节点操作最终是需要转化成文档碎片也就是要通过buildFragment()方法处理的,所以innerHTML兼容的修复也自然在buildFragment方法中。
我们弄清了缘由再去分析,其实整个修正的代码就很简单了。
1:首先无作用域的问题,通过文档碎片创建一个div的包含容器,让所有的元素都被div元素给包含起来,包括script,style等无作用域的元素,很好的解决了
tmp = tmp || fragment.appendChild(context.createElement("div"));
tmp.innerHTML = elem
2:针对不支持innerHTML属性的元素,给单独提出来,通过正则抽出来这个节点名字去处理
wrapMap = {
tr: [2, "<table><tbody>", "</tbody></table>"],
}
tag = /<([\w:]+)/.exec(‘<tr>慕课网</tr>’)
wrap = wrapMap[tag] || wrapMap._default;
tmp.innerHTML = wrap[1] + elem.replace(rxhtmlTag, "<$1></$2>") + wrap[2];
如果遇到wrapMap[‘tr’]的标签就会自动包装一层节点,这样达到支持。
<!doctype html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"/> <script src="http://code.jquery.com/jquery-latest.js"></script> <title>innerHTML</title> </head> <body> <button id="test">innerHTML的兼容处理</button> <script type="text/javascript"> var $newdiv1 = $('<div id="object1"/>'), newdiv2 = document.createElement('div'), existingdiv1 = document.getElementById('foo'); var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi; var wrapMap = { // Support: IE 9 option: [1, "<select multiple='multiple'>", "</select>"], thead: [1, "<table>", "</table>"], col: [2, "<table><colgroup>", "</colgroup></table>"], tr: [2, "<table><tbody>", "</tbody></table>"], td: [3, "<table><tbody><tr>", "</tr></tbody></table>"], _default: [0, "", ""] }; // Support: IE 9 wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; /** * 修正innerHTML的缺陷 * @return {[type]} [description] */ function buildFragment(elem) { var nodes = []; var fragment = document.createDocumentFragment(); var tmp = tmp || fragment.appendChild(document.createElement("div")); tag = (/<([\w:]+)/.exec(elem) || ["", ""])[1].toLowerCase(); wrap = wrapMap[tag] || wrapMap._default; tmp.innerHTML = wrap[1] + elem.replace(rxhtmlTag, "<$1></$2>") + wrap[2]; j = wrap[0]; while (j--) { tmp = tmp.lastChild; } jQuery.merge(nodes, tmp.childNodes); document.body.appendChild(tmp) } $('#test').click(function() { buildFragment('<td>慕课网</td>') }) </script> </body> </html>