扩大原生appendChild要领

Node.prototype.appendChildPlus()

写于:2017-1-2 | 更新于:2017-1-3

概述

appendChild要领的瑕玷有两个:

  • 不能传多个参数

  • 参数只能是节点对象

这里给Node.prototype增加一个要领,名称为:appendChildPlus,能够认为是appendChild的加强版,特性以下:

  • 参数能够是html字符串和节点对象

  • 能够传多个参数

  • script标签字符串和新建的script节点对象插进去文档今后能够一般运转

  • 一切参数是一同插进去指定节点的,而不是一个一个插进去。

源代码

// appendChildPlus.js
/**
 * Created by jszhou on 2017/1/2.
 * updated by jszhou on 2017/1/3.
 */
(function () {
    /**
     * 把类数组对象转换为数组。
     */
    var toArray = Array.from || function (arg) {
            return Array.prototype.slice.call(arg);
        };

    /**
     * 推断参数是不是为节点对象。
     * @param {?} arg
     * @return {boolean}
     */
    function isNode(arg) {
        return arg instanceof Node;
    }

    /**
     * 推断参数是不是为script节点对象。
     * @param {?} arg
     * @return {boolean}
     */
    function isScript(arg) {
        return isNode(arg) && arg.nodeName.toLowerCase() === 'script';
    }

    /**
     * 复制script节点对象,复制今后script标签的内容能够运转。
     * @param {object} script script节点对象
     * @return {object} 返回新的script节点对象
     */
    function copyScript(script) {
        var newScript = document.createElement('script');

        // 复制属性
        toArray(script.attributes).forEach(function (item) {
            newScript.setAttribute(item.nodeName, item.nodeValue);
        });

        newScript.innerHTML = script.innerHTML;

        return newScript;
    }

    /**
     * 替换script节点对象,替换今后script标签的内容能够运转。
     * @param {object} node 节点对象
     * @return {object} 返回script被替换的节点对象(script节点对象被替换成能够运转的)
     */
    function replaceAllScript(node) {
        Array.prototype.forEach.call(node.childNodes, function (item) {
            // 假如是script节点对象,则替换为可运转的script节点对象
            if(isScript(item)) {
                item.parentNode.replaceChild(copyScript(item), item);
                return;
            }
            // 递归
            if(item.childNodes.length > 0){
                replaceAllScript(item);
            }
        });

        return node;
    }

    /**
     * 字符串转成文档片断节点对象。
     * @param {String} str 字符串,能够包括script标签,转换完插进去文档今后能够运转。
     * @return {Object} 返回文档片断节点对象
     */
    function strToNode(str) {
        var docFrag = document.createDocumentFragment(),
            div = document.createElement('div');

        div.innerHTML = str;

        toArray(replaceAllScript(div).childNodes).forEach(function (item) {
            docFrag.appendChild(item);
        });

        return docFrag;
    }

    /**
     * 用于扩大appendChild要领。能够传入html字符串和节点对象,能够传多个参数。
     * 假如html字符串中有script标签,插进去今后能够一般运转。
     * 注重,一切参数是一同插进去指定节点的,而不是一个一个插进去。
     */
    Node.prototype.appendChildPlus = function () {
        var docFrag = document.createDocumentFragment();

        toArray(arguments).forEach(function (arg) {
            docFrag.appendChild(isNode(arg) ? arg : strToNode(String(arg)));
        });

        this.appendChild(docFrag);
    };
})();

示例代码

// extend.js
var wrap = document.querySelector('.js-wrap'),
    deepScript = '<div><script>wrap.append("deepScript");</script></div>',
    newScriptNode = document.createElement('script'),
    outerScript = '<script src="./outerScript.js"></script>';

newScriptNode.textContent = 'wrap.append("newScriptNode");';

wrap.appendChildPlus(deepScript, newScriptNode, outerScript, '<div>nihao</div>');

// outerScript.js
wrap.append('outerScript');
<!--extend.html-->
<!--运转前-->
<div class="js-wrap"></div>
<script src="../appendChildPlus.js"></script>
<script src="./extend.js"></script>

<!--运转后-->
<div class="js-wrap">
    <div><script>wrap.append("deepScript");</script></div>
    <script>wrap.append("newScriptNode");</script>
    <script src="./outerScript.js"></script>
    <div>nihao</div>
    deepScript
    newScriptNode
    outerScript
</div>
<script src="../appendChildPlus.js"></script>
<script src="./extend.js"></script>

更多

本扩大的markdown和demo源文件在github上,点击这里检察

    原文作者:jszhou
    原文地址: https://segmentfault.com/a/1190000007986414
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞