>웹 프론트엔드 >JS 튜토리얼 >노드 메소드 삽입의 JavaScript 구현 요약

노드 메소드 삽입의 JavaScript 구현 요약

青灯夜游
青灯夜游앞으로
2018-10-15 15:10:455617검색

JavaScript에 노드를 삽입하는 방법은 무엇입니까? 이 문서에서는 JavaScript에 노드를 삽입하는 여러 가지 방법을 요약합니다. 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.

JS 네이티브 API에는 innerHTML, externalHTML,appendChild, insertBefore, insertAdjacentHTML 및 applyElement의 6가지 노드 삽입 방법이 있습니다.

여기서 각각의 사용법을 요약하고 before, prepend,append, after 및 applyElement를 포함한 일련의 기능을 캡슐화합니다.

1. 여섯 가지 사용 방법

innerHTML: 태그 내부에 HTML 콘텐츠를 가져옵니다.

outerHTML: 대상 태그와 내부 HTML을 포함한 콘텐츠를 가져옵니다.

appendChild: 대상 레이블 끝에 하위 노드를 추가하고 매개변수 노드를 반환합니다.

insertBefore: 첫 번째 매개변수를 대상 노드의 두 번째 매개변수 위치에 자식 노드로 추가하고 첫 번째 매개변수를 반환합니다.

insertAdjacentHTML: 대상 노드의 지정된 위치에 노드를 추가합니다. 두 번째 매개변수는 추가할 노드이고, 첫 번째 매개변수는 위치를 지정합니다. beforebegin(previousSibling으로 추가됨), afterbegin(firstChild로 추가됨) , beforeend(lastChild로 추가됨), afterend(nextSibling으로 추가됨). 또한 insertAdjacentElement 및 insertAdjacentText라는 두 가지 형제 함수가 있습니다. 전자는 요소를 추가하고 해당 요소를 반환하며, 후자는 텍스트를 추가합니다.

applyElement: 매개변수 노드를 대상 노드의 외부 또는 내부 주변으로 설정하는 IE의 함수입니다. 첫 번째 매개변수는 매개변수 노드이고, 두 번째 매개변수는 메소드를 지정합니다. , 매개변수 노드는 대상 노드를 둘러쌉니다. 하위 노드는 래핑됩니다. 외부(외부 서라운드, 즉 매개변수 노드는 대상 노드를 래핑합니다.)

위 6가지 메소드 중 처음 2개는 속성이고 나머지 4개는 함수입니다. innerHTML 및 externalHTML에 대해서는 말할 것도 없습니다. insertChild는 단순히 함수 셸을 래핑하여 추가 기능으로 캡슐화할 수 있습니다. insertBefore는 노드 삽입을 매우 유연하게 만듭니다. 문자열 삽입 방법; applyElement 함수는 호환성 후에 JQuery의 Wrap 시리즈 함수가 될 수 있습니다.

2 대상 노드 앞에 매개변수 노드를 삽입하기 전에 before, prepend,append 및 after 함수를 구현합니다. . prepend는 대상 노드의 첫 번째 자식 노드 위치에 매개변수 노드를 삽입하고 대상 노드의 첫 번째 자식 노드를 얻은 다음 insertBefore를 호출합니다.

append 기능은 네이티브 API의 AppendChild 기능과 동일합니다.

대상 노드 뒤에 매개변수 노드를 삽입한 후 대상 노드의 nextSibling을 가져온 다음 insertBefore를 호출하면 됩니다.

구체적인 구현은 다음과 같습니다.

var append = function(node, scope) {    
     if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
        scope.appendChild(node);
    }
};
var prepend = function(node, scope) {    
     if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
        scope.insertBefore(node, scope.firstChild);
    }
};
var before = function(node, scope) {    
     if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
        scope.parentNode.insertBefore(node, scope);
    }
};
var after = function(node, scope) {    
     if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
        scope.parentNode.insertBefore(node, scope.nextSibling);
    }
};

위 함수는 모두 노드 유형인 요소 노드, 문서 노드 및 문서 조각만 삽입할 수 있습니다. 문자열 형식의 삽입 방법을 지원하려면 insertAdjacentHTML을 캡슐화해야 합니다.

여기에서는 전략 패턴을 사용하여 구현하려는 4가지 함수를 전략 개체로 만든 다음 이를 동적으로 생성하여 코드 간소화 효과를 얻습니다.

//E5才有的迭代, 所以迭代要预先兼容
Array.prototype.forEach = [].forEach || function(callback) {    
      for(var i = 0, len = this.length; i < len; i++) {
        callback.call(this[i], this[i], i, this);
    }
};  
/**插入策略集合**/ 
var insertStrategies = {
    before : function(node, scope) {
        scope.parentNode.insertBefore(node, scope);
    },
    prepend : function(node, scope) {
        scope.insertBefore(node, scope.firstChild);
    },
    append : function(node, scope) {
        scope.appendChild(node);
    },
    after : function(node, scope) {
        scope.parentNode.insertBefore(node, scope.nextSibling);
    },    
    /*支持字符串格式的插入, 注意:要兼容不可直接做p子类的元素*/
    /*insertAdjace还有Element和Text,前者只能插元素,后者只能插文本*/
    beforestr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;beforeBegin&#39;, node);
    },
    prependstr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;afterBegin&#39;, node);
    },
    appendstr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;beforeEnd&#39;, node);
    },
    afterstr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;afterEnd&#39;, node);
    }
};
//响应函数
var returnMethod = function(method, node, scope) {    //如果是字符串
    if(typeof node === &#39;string&#39;) {        
        return insertStrategies[method + &#39;str&#39;](node, scope);
    }    
    //1(元素)、9(文档)、11(文档碎片)
    if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {        
          return insertStrategies[method](node, scope);
    }    
    //此处还可添加节点集合的处理逻辑,用于处理选择其引擎获取的节点集合。
};

[&#39;before&#39;, &#39;prepend&#39;, &#39;append&#39;, &#39;after&#39;].forEach(function(method){
    window[method] = function(node, scope) {
        returnMethod(method, node, scope);
    };
});

모든 함수는 창의 속성으로 구현되므로 전역 함수로 직접 호출됩니다. 즉, 이러한 함수는 노드 개체에 속하지 않으므로 범위 매개 변수는 대상 노드를 참조합니다. 다음이 ApplyElement와 호환되면 모든 기능을 HTMLElement의 프로토타입으로 확장하여 범위 매개변수를 생략하여 요소 노드를 직접 호출하는 효과를 얻을 수 있습니다. 물론, 프레임워크의 경우 일반적으로 프레임워크 개체가 생성된 다음 이러한 기능이 해당 프로토타입으로 확장되므로 네이티브 개체의 프로토타입이 수정되지 않습니다.

3. applyElement와 호환 가능

applyElement 함수는 IE의 비공개 구현이므로 다른 브라우저에서 사용하려면 Array의 forEach와 같은 객체 프로토타입과 호환되어야 합니다. 실제로 새 요소에 대상 노드가 포함되거나 대상 요소의 하위 노드가 포함되도록 하려면 innerHTML 및 externalHTML을 사용할 수도 있습니다. 그러나 문제가 있을 수 있습니다. 새 요소가 DOM 트리의 일부이고 일련의 하위 노드도 포함하는 경우 해당 하위 노드를 어떻게 처리해야 합니까? 제자리에 머물거나 대상 요소에 병합하시겠습니까? 대상 요소에 병합되면 대상 요소가 먼저 오나요, 아니면 새 요소가 먼저 오나요?

wrap series 기능의 효과는 새 요소 태그의 내용만 제거하는 것이며, 하위 요소의 효과는 새 요소의 상위 노드의 하위 노드가 되는 것입니다. 이 메서드는 Range 개체를 사용하여 구현할 수도 있으며, 물론 innerHTML 및 externalHTML을 사용하여 구현할 수도 있습니다. 여기서는 Range 개체를 사용하여 구현하겠습니다.

/*兼容IE的applyElement*/
HTMLElement.prototype.removeNode = HTMLElement.prototype.removeNode || function(deep) {    
       if(this.parentNode) {        
            var range = this.ownerDocument.createRange();
        range.selectNodeContents(this);        
        if(!deep) {            
               var fragment = range.extractContents();
            range.setStartBefore(this);
            range.insertNode(fragment);
            range.detach();
        }        
        return this.parentNode.removeChild(this);
    }
}; 

HTMLElement.prototype.applyElement = HTMLElement.prototype.applyElement || function(node, where) {
    node = node.removeNode();
    where = (where || &#39;outside&#39;).toLowerCase();    
    var range = this.ownerDocument.createRange();    
    if(where === &#39;inside&#39;) {
        range.selectNodeContents(this);
        range.surroundContents(node);
        range.detach();
    }else if(where === &#39;outside&#39;) {
        range.selectNode(this);
        range.surroundContents(node);
        range.detach();
    }    
    return node;
};

4. 모든 기능을 HTMLElement의 프로토타입으로 확장

아이디어는 applyElement를 복구하는 것과 동일합니다. window[method]를 HTMLElement.prototype[method]로 바꾸고 전달된 범위만 변경하면 됩니다. 이는 일괄 생성 중에 달성될 수 있습니다.

//E5才有的迭代, 所以迭代要预先兼容
Array.prototype.forEach = [].forEach || function(callback) {    
        for(var i = 0, len = this.length; i < len; i++) {
        callback.call(this[i], this[i], i, this);
    }
};  

/**插入策略集合**/
var insertStrategies = {
    before : function(node, scope) {
        scope.parentNode.insertBefore(node, scope);
    },
    prepend : function(node, scope) {
        scope.insertBefore(node, scope.firstChild);
    },
    append : function(node, scope) {
        scope.appendChild(node);
    },
    after : function(node, scope) {
        scope.parentNode.insertBefore(node, scope.nextSibling);
    },    
    /*支持字符串格式的插入, 注意:要兼容不可直接做p子类的元素*/
    /*insertAdjace还有Element和Text,前者只能插元素,后者只能插文本*/
    /**/
    beforestr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;beforeBegin&#39;, node);
    },
    prependstr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;afterBegin&#39;, node);
    },
    appendstr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;beforeEnd&#39;, node);
    },
    afterstr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;afterEnd&#39;, node);
    }
};
//响应函数
var returnMethod = function(method, node, scope) {    //如果是字符串
    if(typeof node === &#39;string&#39;) {   //低版本浏览器使用机会毕竟少数,每次都要判断很划不来。这段代码舍弃
        /*if(!scope.insertAdjacentHTML){
            throw new Error(&#39;(Firefox8-、IE4-、Opera7-、Safari4-)浏览器不能插入字符串!&#39;);
        }*/
        return insertStrategies[method + &#39;str&#39;](node, scope);
    }    //1(元素)、2(属性)、3(文本)、9(文档)、11(文档碎片)
    if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {        
            return insertStrategies[method](node, scope);
    }    
    //此处还可添加节点集合的处理逻辑(用文档碎片)
};

[&#39;before&#39;, &#39;prepend&#39;, &#39;append&#39;, &#39;after&#39;].forEach(function(method){
    HTMLElement.prototype[method] = function(node) {
        returnMethod(method, node, this);
    };
});/*兼容IE的applyElement*/
HTMLElement.prototype.removeNode = HTMLElement.prototype.removeNode || function(deep) {    
        if(this.parentNode) {        
                var range = this.ownerDocument.createRange();
        range.selectNodeContents(this);        
        if(!deep) {            
                var fragment = range.extractContents();
            range.setStartBefore(this);
            range.insertNode(fragment);
            range.detach();
        }        
        return this.parentNode.removeChild(this);
    }
}; 

HTMLElement.prototype.applyElement = HTMLElement.prototype.applyElement || function(node, where) {
    node = node.removeNode();
    where = (where || &#39;outside&#39;).toLowerCase();    
    var range = this.ownerDocument.createRange();    
    if(where === &#39;inside&#39;) {
        range.selectNodeContents(this);
        range.surroundContents(node);
        range.detach();
    }else if(where === &#39;outside&#39;) {
        range.selectNode(this);
        range.surroundContents(node);
        range.detach();
    }    return node;
};

5. 테스트

테스트 코드는 다음과 같습니다.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>插入节点.html</title>
    <script type="text/javascript" src=&#39;./insertNode.js&#39;></script>
  </head>
  <body>
    <p id=&#39;p&#39; style=&#39;background:#888;border:1px solid #888;padding:10px;&#39;>坐标p</p>
    <p id=&#39;inside&#39; style=&#39;background:#0f0;border:1px solid #888;padding:10px;&#39;>inside</p>
    <p id=&#39;outside&#39; style=&#39;background:#F00;border:1px solid #888;padding:10px;&#39;>outside</p>
    
    <script type="text/javascript">        
            var p = document.getElementById('p');        
        var beforep = document.createElement('p');
        beforep.innerHTML = 'beforep';
        beforep.style.background = '#eee';        
        var prepEndp = document.createElement('p');
        prepEndp.innerHTML = 'prepEndp';
        prepEndp.style.background = '#ff0';        
        var appendp = document.createElement('p');
        appendp.innerHTML = 'appendp';
        appendp.style.background = '#0ff';        
        var afterp = document.createElement('p');
        afterp.innerHTML = 'afterp';
        afterp.style.background = '#f0f';
        
        p.before(beforep);
        p.prepend(prepEndp);
        p.append(appendp);
        p.after(afterp);        
        //测试文本插入
        p.append('[我是乐小天,我来测试直接插入文本]');        
        //测试外包含和内包含
        var outside = document.getElementById('outside');        
        var inside = document.getElementById('inside');
        outside.applyElement(inside, 'inside');    
     </script>
  </body>
</html>
결과 사진:

참고문헌: "Javascript Framework Design", "Javascript Advanced Programing", "JavaScript Design Patterns and Development Practices"

요약: 위 내용은 이 글의 전체 내용입니다. 모든 분들의 학습에 도움이 되기를 바랍니다. 더 많은 관련 튜토리얼을 보려면 JavaScript 비디오 튜토리얼, jQuery 비디오 튜토리얼, bootstrap 튜토리얼을 방문하세요!

위 내용은 노드 메소드 삽입의 JavaScript 구현 요약의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 cnblogs.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제