>  기사  >  웹 프론트엔드  >  jQuery-1.9.1 소스 코드 분석 시리즈(11) DOM 작업 계속 복제 Nodes_jquery

jQuery-1.9.1 소스 코드 분석 시리즈(11) DOM 작업 계속 복제 Nodes_jquery

WBOY
WBOY원래의
2016-05-16 15:28:321252검색

복제된 노드는 언제 사용되나요?

DOM 작업 중에 노드를 직접 사용하면 작업에 따라 노드가 변경된다는 것을 알고 있습니다. 예를 들어 노드에서 .after/.before/.append 및 기타 메서드를 사용한 후 노드는 새 위치에 추가되고 원래 위치의 노드는 제거됩니다. 때로는 노드를 원래 위치에 유지해야 하고 해당 위치에 복사본만 추가하면 되는 경우도 있습니다.

jQuery.fn.clone은 현재 일치하는 요소 세트의 복사본을 복제하고 이를 jQuery 객체로 반환합니다.

추가 데이터(data() 함수)와 일치하는 요소(자식 포함)의 바인딩된 이벤트를 복사할지 여부도 지정할 수 있습니다.

jQueyr.fn.clone: ​​​​함수(withDataAndEvents, deepDataAndEvents) 매개변수 설명

a. clone 기능의 기본 구현 단계는 다음과 같습니다(jQuery.clone)

첫 번째 단계는 DOM 노드를 복제하는 것입니다. 올바른 노드 복제를 지원하는(즉, elem.cloneNode를 지원하고 올바른 복제를 보장하는) DOM 노드에 대해 직접 cloneNode(true)를 사용하고, 그렇지 않으면 노드를 구축하여 복제된 데이터를 저장한 다음 노드를 얻습니다.

if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
  clone = elem.cloneNode( true );
// IE<=8 不能正确克隆已分离、未知的节点
//直接新建一个相同的节点,然后获取
} else {
  //fragmentDiv是全局变量
  fragmentDiv.innerHTML = elem.outerHTML;
  fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
}

두 번째 단계에서는 IE 브라우저를 사용하는 경우 fixCloneNodeIssues( node, destElements[i] );를 통해 IE 복제 문제를 하나씩 해결해야 합니다. 모든 IE 복제 솔루션은 fixCloneNodeIssues에 포함되어 있으며 다음 섹션에서 자세히 분석됩니다. 더 많은 jQuery.support 콘텐츠를 보려면 여기를 클릭하세요

//针对ie克隆问题修正
if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
  (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
  //在这里我们不使用Sizzle的原因是: http://jsperf.com/getall-vs-sizzle/2
  destElements = getAll( clone );
  srcElements = getAll( elem );
  //修正所有IE克隆问题
  for ( i = 0; (node = srcElements[i]) != null; ++i ) {
    // Ensure that the destination node is not null; Fixes #9587
    if ( destElements[i] ) {
      fixCloneNodeIssues( node, destElements[i] );
    }
  }
}

세 번째 단계로, 캐시 데이터(일반 데이터 및 바인딩 이벤트 포함)를 복제하려면 복제합니다.

//克隆绑定的事件
if ( dataAndEvents ) {
  if ( deepDataAndEvents ) {
    srcElements = srcElements || getAll( elem );
    destElements = destElements || getAll( clone );
    for ( i = 0; (node = srcElements[i]) != null; i++ ) {
      cloneCopyEvent( node, destElements[i] );
    }
  } else {
    cloneCopyEvent( elem, clone );
  }
}

참고: cloneCopyEvent 함수는 원본 노드의 데이터를 복제 노드에 저장한 다음 원본 노드의 이벤트를 새 복제 노드에 바인딩합니다

function cloneCopyEvent( src, dest ) {
    if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
      return;
    }
    var type, i, l,
    oldData = jQuery._data( src ),
    curData = jQuery._data( dest, oldData ),//dest是克隆对的节点
    events = oldData.events;
    if ( events ) {
      //保证被克隆的节点的事件对象干净,确保没有后面添加的事件没有重复
      delete curData.handle;
      curData.events = {};
      for ( type in events ) {
        for ( i = 0, l = events[ type ].length; i < l; i++ ) {
          jQuery.event.add( dest, type, events[ type ][ i ] );
        }
      }
    }
    // 使克隆的数据对象化
    if ( curData.data ) {
      curData.data = jQuery.extend( {}, curData.data );
    }
  }

네 번째 단계는 스크립트 계산 기록을 보호하고(스크립트 코드 세그먼트가 실행된 것으로 전역적으로 표시), 메모리를 회수하고 복제 노드로 돌아가는 것입니다.

destElements = getAll( clone, "script" );
if ( destElements.length > 0 ) {
  setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
}
destElements = srcElements = node = null;
return clone;

b. IE 복제 문제 요약 fixCloneNodeIssues(src,dest)

src는 원본 노드이고, dest는 src의 복제 노드입니다.

IE 복제 문제 나열(IE8)

1.IE6-8은 cloneNode를 사용할 때 이벤트를 복제합니다(이러한 이벤트는 attachmentEvent를 통해 바인딩됩니다). 균일성을 보장하기 위해서는 복제된 이벤트를 삭제하고 후속 통합 복제 이벤트를 준비해야 합니다

  // IE6-8当使用cloneNode复制事件(这些事件绑定通过attachEvent)时进入该分支
  //清除原来的事件,为克隆事件做准备
  if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
    data = jQuery._data( dest );
    for ( e in data.events ) {
      jQuery.removeEvent( dest, e, data.handle );
    }
    dest.removeAttribute( jQuery.expando );
  }

 2.IE8 - 스크립트 태그 스크립트를 복제하면 복제된 내용이 공백이 됩니다. 이를 다시 할당하고 스크립트 콘텐츠가 실행되지 않도록 해야 합니다.

//IE克隆脚本时内容为空白,并试图执行新设置的文本
  if ( nodeName === "script" && dest.text !== src.text ) {
    disableScript( dest ).text = src.text;
    restoreScript( dest );
    }

 3.IE6-10은 classid를 사용하여 얻은 객체 요소의 하위 노드를 복제할 수 없습니다. IE10에서는 상위 노드가 null이면 NoModificationAllowedError 예외가 발생합니다. 원래 노드의 externalHTML 및 innerHTML을 다시 할당해야 합니다.

 //IE6-10不能克隆使用的classid获取的对象元素的子节点。
  //IE10下,如果父节点为null,则会抛出NoModificationAllowedError异常
  else if ( nodeName === "object" ) {
    if ( dest.parentNode ) {
      dest.outerHTML = src.outerHTML;
    }
    //对于IE9,这个条分支不可避免。
    //IE9中克隆对象元素,上述outerHTML策略是不充分的。
    //如果src具有的innerHTML并且克隆节点却没有,
    //复制src.innerHTML到dest.innerHTML #10324
    if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
      dest.innerHTML = src.innerHTML;
    }
  }

 4.IE6-8은 체크박스나 라디오 버튼의 선택된 상태를 복제할 수 없습니다. 활성 설정이 필요합니다.

 // manipulation_rcheckableType = /^(&#63;:checkbox|radio)$/i
  else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
    //IE6-8无法坚持一个克隆的复选框或单选按钮的选中状态
    //更糟的是,如果defaultChecked值没有设置,则IE6-7无法给克隆元素选中状态的外观
    dest.defaultChecked = dest.checked = src.checked;
    ...
  }

5. 선택 태그를 복제할 때 IE6-8은 선택 기본 선택 상태로 올바르게 돌아갈 수 없습니다. 활성 설정이 필요합니다.

   //当克隆选项时,IE6-8无法正确返回select默认选中状态
   else if ( nodeName === "option" ) {
    dest.defaultSelected = dest.selected = src.defaultSelected;
   }

6. 다른 유형의 입력 및 텍스트 태그를 복제할 때 IE6-8은 defaultValue를 올바른 값으로 올바르게 설정할 수 없습니다. 활성 설정이 필요합니다.

  //当克隆其他类型的input标签时,IE6-8不能正确设置defaultValue为正确的值
  else if ( nodeName === "input" || nodeName === "textarea" ) {
    dest.defaultValue = src.defaultValue;
  }

내부에서는 비활성화스크립트 함수를 사용합니다. 이 기능의 목적은 스크립트에 값을 할당한 후 스크립트로 실행되지 않도록 스크립트의 유형을 변경하는 것입니다. 우리는 이 접근 방식에서 배울 수 있습니다

//为安全DOM操作替换/保存script节点元素type属性
function disableScript( elem ) {
  var attr = elem.getAttributeNode("type");
  elem.type = ( attr && attr.specified ) + "/" + elem.type;
  return elem;
}

위 내용은 jQuery-1.9.1 소스 코드 분석 시리즈(11) 편집자가 소개한 복제 노드의 DOM 작업 연속에 대한 전체 설명입니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.