本帖最后由 小鲁哥哥 于 2018-4-13 14:07 编辑
【济南校区】前端就业班笔记框架封装(三)
实际上, 在 DOM 操作中使用的最多的是 增加数据( 增加 DOM 节点 ), 删除数据( 删除节点等 ),修改数据( 修改属性, 修改样式 ), 查询( 获得元素, 找寻节点对象 ).
-> parseHTML 方法
传统与 jq 中创建标签的办法
1) document.createElement( 'div' )
2) $( '<div></div>' )
现在需要提供一个字符串, 然后将其转换成 HTML 标签( DOM 对象 )
1> 如何判断用户输入的是标签格式的字符串
思考: 选择器的字符串结构与 HTML 字符串结构有何不同???
在 HTML 中必须有 尖括号, 而且一定在两端,但是选择器中, 尖括号只会出现在选择器中间, 表示子代元素
if ( str.charAt( 0 ) === '<' && str.charAt( str.length - 1 ) === '>' )
这就是说明了 它是一个 html 格式的字符串
2> 如何解析这个字符串???
-> 字符串解析( 正则表达式 )
常用 html 格式有两种形态
1) 单标签形态: 例如 <br /> <input type="text"> 等
这个标签满足格式 /<.+\/>/ 或者: /<\S+.*?\/>/
2) 复杂的标签形态: 例如: <div><img /></div>
如果使用格式: /<(.+)>.*<\/\1>/
无法处理: <div><div></div></div>
-> 将解析的工作交给 浏览器来完成
思考, 在 HTML 的方法中有没有一个 将 HTML 格式字符串转换为 DOM 的办法,很显然, innerHTML
注意: 该方法使用 的是 div 作为容器, 因此在内部不能够直接创建 tr, td 等元素
[JavaScript] 纯文本查看 复制代码 function parseHTML ( htmlStr ) {
var rest = [], i,
div = document.createElement( 'div' );
div.innerHTML = htmlStr;
for ( i = 0; i < div.childNodes.length; i++ ) {
rest.push( div.childNodes[ i ] );
}
return rest
}
// 有一组数据
var datas = [
{ name: 'jim1', age: 19, gender: '男' },
{ name: 'jim2', age: 9, gender: '女' },
{ name: 'jim3', age: 29, gender: '男' },
{ name: 'jim4', age: 39, gender: '女' },
{ name: 'jim5', age: 49, gender: '女' }
];
// 生成一个 table 表格
// 只需要保证 table 中有 tr 即可, 不考虑 thead 等数据
parseHTML( '<table border="1" width="400">' + datas.map(function ( v ) {
// v 就是每一项数据, 即每一行数据
var rest = [];
for( var k in v ) {
// 此时 k 就是 对应的 name, age, 和 gender
rest.push( '<td>' + v[ k ] + '</td>' );
}
return '<tr>' + rest.join( '' ) + '</tr>';
}).join( '' ) + '</table>' ).forEach( function ( v ) {
document.body.appendChild( v );
});
引入到框架
1> 修改构造方法, 使得可以处理其他数据
2> 将 parseHTML 方法挂载到 构造函数上
3> 如何组织代码
今天的前端开发已经不再是以前的切切图就可以解决的了
现在的前端, 有大量的代码需要编写, 可以非常注重项目结构化.
因此需要将代码分解到不同的文件中.
按照功能进行分解: 核心模块, DOM 操作模块, 事件模块, 属性样式模块, 其他模块
[JavaScript] 纯文本查看 复制代码 (function ( window ) {
var arr = [],
push = arr.push,
slice = arr.slice;
function Itcast( selector ) {
return new Itcast.fn.init( selector );
}
Itcast.fn = Itcast.prototype = {
constructor: Itcast,
length: 0,
init: function ( selector ) {
// 需要判断, 根据传入的数据不同而实现不同的功能
if ( !selector ) return this;
if ( typeof selector == 'string' ) {
// 判断是选择器 还是 html 字符串
if ( selector.charAt( 0 ) == '<' && selector.charAt( selector.length - 1 ) == '>' ) {
// HTML 标签
push.apply( this, Itcast.parseHTML( selector ) );
return this;
} else {
// 选择器
push.apply( this, Itcast.select( selector ) );
return this;
}
}
},
each: function ( callback ) {
return Itcast.each( this, callback );
},
map: function ( callback ) {
return Itcast.map( this, callback );
},
toArray: function () {
return slice.call( this );
},
get: function ( index ) {
// arguments.length == 0
if ( index === undefined ) {
// 没有传参
return this.toArray();
} else {
// 传入了参数
if ( index >= 0 ) {
return this[ index ];
} else if ( index < 0 ) {
return this[ this.length + index ];
}
}
return this; // 如果传入的既不是正数, 也不是负数, 也不是没有传参
}
};
Itcast.fn.init.prototype = Itcast.fn;
Itcast.isArrayLike = function ( array ) {
var length = array && array.length;
return typeof length === 'number' && length >= 0;
}
Itcast.each = function ( array, callback ) {
var i, k;
if ( Itcast.isArrayLike( array ) ) {
// 使用 for 循环
for ( i= 0; i < array.length; i++ ) {
if( callback.call( array[ i ], i, array[ i ] ) === false ) break;
}
} else {
// 使用 for-in 循环
for ( k in array ) {
if( callback.call( array[ i ], k , array[ k ] ) === false ) break;
}
}
return array;
}
Itcast.map = function ( array, callback ) {
var i, k,
res = [],
tmp;
if ( Itcast.isArrayLike( array ) ) {
// 使用 for 循环
for ( i= 0; i < array.length; i++ ) {
tmp = callback( array[ i ], i );
if ( tmp !== undefined ) {
res.push( tmp );
}
}
} else {
// 使用 for-in 循环
for ( k in array ) {
tmp = callback( array[ k ], k );
if ( tmp !== undefined ) {
res.push( tmp );
}
}
}
return res;
}
Itcast.select = function ( selector ) {
return document.querySelectorAll( selector );
}
Itcast.extend = Itcast.fn.extend = function ( obj ) {
for ( var k in obj ) {
this[ k ] = obj[ k ];
}
};
// DOM 处理
function parseHTML ( htmlStr ) {
var rest = [], i,
div = document.createElement( 'div' );
div.innerHTML = htmlStr;
for ( i = 0; i < div.childNodes.length; i++ ) {
rest.push( div.childNodes[ i ] );
}
return rest
}
Itcast.parseHTML = parseHTML;
window.Itcast = window.I = Itcast; // 在 全局范围内 引入两个变量
})( window );
// 创建一个 div 加到页面中
I( 'body' ).get( 0 ).appendChild(
I( '<div id="dv" style="border: 1px solid red; width: 200px; height: 70px;">123</div>' ).get( 0 )
);
// 修改 刚刚加入的 div
I( '#dv' ).each(function (){
this.style.border = '1px dashed blue';
})
基本 DOM 方法
-> 什么是 DOM 操作
所谓的 DOM 操作就是在操作 DOM.
1) 增加 DOM 元素
创建元素: $( ... )
加入: $( ... ).appendTo( ... )
$( ... ).append( ... )
...
2) 删除 DOM 元素
$( ... ).remove()
3) 修改 DOM 元素
所谓的修改就是 修改属性, 修改样式, 实际上将原有移除, 新加一个即可
-> appendTo
在 jq 中该方法的含义是 将 前面的 jq 对象中包含 DOM 元素, 全部加到 后面的 元素中
$( '<div>1</div>' ).appendTo( 'body' )
新建一个 div 标签, 然后将其追加到 body 中.
关于 appendTo 的参数
$( ... ).appendTo( 'body' ) 参数是一个选择器
$( ... ).appendTo( $( 'body' ) ) 参数是一个 jq 对象
$( ... ).appendTo( document.body ) 参数是一个 dom 对象
转化: 如果一个函数可以传入三种参数, 而且这三种参数的处理逻辑不太相同
一般来说结构就可以写成
[JavaScript] 纯文本查看 复制代码 function xxx ( args ) {
if ( typeof args == 'string' ) {
...
} else if ( args.nodeType ) {
...
} else if ( args 是 Itcast 对象 ) {
...
}
}
划归: 将一个问题转化成一个已经解决的问题
可以将所有的情况转化成 处理 数组的 模型中
1) 字符串 -> Itcast 对象 -> 数组
2) DOM 元素 -> Itcast 对象 -> 数组
3) Itcast 对象 -> 数组
思考: jq 中, $ 函数可以处理什么参数
$( '选择器' ), $( dom ), $( $( ... ) ), $( fn ), ...
如果 我们的 Itcast 构造函数可以将 各种数据 转化成 Itcast 对象( 即数组 )
[JavaScript] 纯文本查看 复制代码 Itcast.fn.appendTo = function ( selector ) {
var iObj = Itcast( selector ); // 数组
return this.each(function () {
for ( var i = 0; i < iObj.length; i++ ) {
iObj[ i ].appendChild( i == iObj.length - 1
? this
: this.cloneNode( true ) );
}
});
};
-> 构造函数
在 jq 中 构造函数参数的用法
1) 允许传入选择: string
2) 允许传入 html 字符串: string
3) 允许传入 dom 元素: object, 如何判断??? nodeType 属性
4) 允许传入 jQuery 对象: object, 如何判断??? .constructor
在 jquery 中原型上有一个属性 selector, 该属性用于记录选择器.
jquery 使用的就是该属性来判断的.
5) 允许传入 函数: function 相当于 onload 事件.
6) 数组等
-> 考虑 返回值
每次需要 克隆 DOM 对象, 因此准备一个数组, 然后将数组加载完成以后生成一个新的 Itcast 对象即可
-> 记录下链破坏之前原来对象
iNewObj.prevObj = this
每次链破坏的时候, 都可以记录下来, 那么只要调用 end 方法就将原来的数据取出来即可
-> append
-> prepend
-> prependTo
-> insertAfter
-> insertBefore
-> after
-> before
-> 成员访问方法
就是在访问相关的元素( 访问亲属元素 )
-> .parent()
-> .prev()
-> .prevAll()
-> .next()
-> .nextAll()
-> .sblings()
如果你想了解更多黑马课程请点击这里,如果你想加入黑马这个大家庭学习先进技术,广交天下好友! 黑马程序员济南中心联系电话:0531-55696830
|