在前端开发的过程中,javascript极为重要的一个功能就是对DOM对象的操作,而对其封装就是为了更好地进行DOM操作,提高浏览器的支持效率
-
现在给出一个案例:页面创建三个div,然后给其添加样式
1、第一种方法
//第一种方法 var i, node; for ( i = 0; i < 3; i++ ) { node = document.createElement( 'div' ); node.setAttribute( 'class', 'c' ); //node.className = 'c'; document.body.appendChild( node ); }
上面方法缺点:由于每次循环都使用 document.body.appenChild 因此会导致每次 for 都要刷新页面结构,影响浏览器性能,应该采用一个临时的数据
存储这些 dom 对象, 在全部创建完成以后再加入
2、第二种方法
var i, node, container = document.createElement( 'div' ); for ( i = 0; i < 3; i++ ) { node = document.createElement( 'div' ); // node.setAttribute( 'class', 'c' ); node.className = 'c'; container.appendChild( node ); } document.body.appendChild( container );
这种方法同样能实现,但是改变了页面结构
3、第三种方法
//这里的DocumentFragment是文档片段(nodeType 11) 用于缓存的DOM对象,页面结构不会影响 /*var i, node, container = document.createDocumentFragment(); for ( i = 0; i < 3; i++ ) { node = document.createElement( 'div' ); node.setAttribute( 'class', 'c' ); //node.className = 'c'; container.appendChild( node ); } document.body.appendChild( container );
4、第四种方法
var i, s = ""; for ( i = 0; i < 3; i++ ) { s += '<div> ' + ' </div>'; } document.body.innerHTML = s; //在这只实现了添加标签
5、在实际框架中创建html中的方法
//在实际框架中创建html中的方法 var parseDom = function (html){ var docfrag = document.createDocumentFragment(); var div = document.createElement('div');//必须创建一个真正的div div.innerHTML = html; // 在 DOM 元素中默认有一个特征, 即元素只允许有一个 父节点 // 如果添加元素到另一个节点中, 该元素会自动的离开原来的父节点 while(div.firstChild){ docfrag.appendChild(div.firstChild); } return docfrag; }; var dom = parseDom( '<span>hello word</span></br>' +'<span>hello word</span>' ); document.body.appendChild( dom );
6、 假如传入的是dom对象,要给其添加一个appenTo方法,现在问题来了,在哪个原型中添加该方法,并且不能影响其他内置对象成员。
思路:给dom对象提供一个包装对象,在这个返回的包装对象中提供一个自定义appendTo方法
var parseDom = function (html){ var docfrag = document.createDocumentFragment(); var div = document.createElement('div'); div.innerHTML = html; while(div.firstChild){ docfrag.appendChild(div.firstChild); } return { element: docfrag, appendTo: function(dom){ dom.appendChild(this.element); } }; };
-
DOM框架的基本实现
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 <script> 7 // 构造函数 8 var YY = function ( selector ) { 9 return new YY.fn.init( selector );//返回init方法的一个实例对象,一个构造函数的原型属性上的函数init的原型链和YY原型链是不同的 10 }; 11 //原型继承分别为 12 //YY->YY.prototype->object.prototype->null 13 //init->init.prototype->object.prototype->null 14 // 核心原型 15 YY.fn = YY.prototype = { 16 constructor: YY, 17 selector: null, 18 init: function ( selector ) { 19 // 字符串: 选择器, html 20 if ( typeof selector == 'string' ) { 21 if ( selector.charAt( 0 ) === '<' ) { 22 this.elements = parseHTML( selector ); 23 } else { 24 this.elements = select( selector ); 25 } 26 } 27 this.selector = selector;//可以判断出,只要有这个属性的对象,就是YY对象 28 } 29 }; 30 YY.fn.init.prototype = YY.prototype; 31 32 // 可扩展 33 YY.extend = YY.fn.extend = function ( obj ) { 34 // 将 obj 的成员加到 this 上 35 var k; 36 for ( k in obj ) { 37 this[ k ] = obj[ k ]; 38 } 39 }; 40 41 //选择器方法,暂时只考虑基本选择器 42 var select = function ( selector ) { 43 var first = selector.charAt( 0 ), arr = []; 44 if ( first === '#' ) { 45 arr.push.call( arr, document.getElementById( selector.slice( 1 ) ) ) 46 } else if ( first === '.' ) { 47 arr.push.apply( arr, document.getElementsByClassName( selector.slice( 1 ) ) ) 48 } else { 49 arr.push.apply( arr, document.getElementsByTagName( selector ) ); 50 } 51 return arr; 52 }; 53 54 var parseHTML = function ( html ) { 55 var div = document.createElement( 'div' ), 56 arr = [], i; 57 div.innerHTML = html; 58 for ( i = 0; i < div.childNodes.length; i++ ) { 59 arr.push( div.childNodes[ i ] ); 60 } 61 return arr; 62 }; 63 64 // 基本的工具方法 65 YY.extend({ 66 each: function ( arr, fn ) { 67 var i, l = arr.length, 68 isArray = YY.isLikeArray( arr );//先判断是否为数组 69 if ( isArray ) { 70 // 数组 71 for ( i = 0; i < l; i++ ) { 72 if ( fn.call( arr[ i ], i, arr[ i ] ) === false ) { 73 break; 74 } 75 } 76 } else { 77 // 对象 78 for ( i in arr ) { 79 if ( fn.call( arr[ i ], i, arr[ i ] ) === false ) { 80 break; 81 } 82 } 83 } 84 return arr; 85 } 86 }); 87 88 // 判断类型的方法 89 YY.extend({ 90 isFunction: function ( obj ) { 91 return typeof obj === 'function';//判断是否为function 92 }, 93 isString: function ( obj ) { 94 return typeof obj === 'string';//判断是否为字符串 95 }, 96 isLikeArray: function ( obj ) { 97 return obj && obj.length && obj.length >= 0;//判断是否为数组 98 }, 99 isYY: function ( obj ) { 100 return !!obj.selector;//判断是否为YY,给其原型属性加个属性,默认为空 101 }, 102 isDOM: function ( obj ) { 103 return !!obj.nodeType; 104 } 105 }); 106 107 108 // 基本的 DOM 操作,此处假设selector是DOM对象 109 YY.fn.extend({ 110 appendTo: function ( selector ) { 111 // 将 this.elements 加入到 selector 中 112 YY.each( this.elements, function () { 113 selector.appendChild( this ); 114 } ); 115 } 116 }); 117 118 119 </script> 120 121 <script type="text/javascript"> 122 onload = function () { 123 YY( '<div>1</div><div>2</div><div>3</div><div>4</div>' ) 124 .appendTo( document.body ); 125 } 126 </script> 127 </head> 128 <body> 129 </body> 130 </html>
假如selector是id选择器,那么如何实现appendTo方法呢
//YY( selector )返回结果为对象,YY( selector ).elements是一个数组 YY.fn.extend({ appendTo: function ( selector ) { YY.each( this.elements, function () { YY( selector ).elements[ 0 ].appendChild( this ); } ); } });
假如selector是标签选择器,那么如何实现appendTo方法呢
YY.fn.extend({ appendTo: function ( selector ) { var _this = this; var objs = YY( selector ).elements; YY.each( objs, function ( i1, v1 ) { var that = this; YY.each( _this.elements, function ( i2, v2 ) { // this 当前元素, 要加到 that 上 that.appendChild( i1 == objs.length - 1? this : this.cloneNode( true ) ); // 判断如果是最后一个就无须克隆 }); }); } });