Jquery 对象
一般来说,我们都将 Jquery 对象视为一个数组,精确点的说是视为一个类数组对象,可以直接使用 1 2 3 4 5等下标取得所需要的DOM元素或者其他。
练手自己的函数库的时候,便遇到了一些关于实现上的问题,我有一个 $ 的模块,很简单是返回一个包含查询结果的DOM数组,然后又有了一个关于处理 CSS 的模块,那么如果两个模块不相干 直接可以想这样的使用:
-
CSS.addClass( $(".classOne"), "classTwo" );
显然也没什么问题,不过就是看上去不那么顺畅,比不上:
-
$(".classOne").addClass( "classTwo" );
那么的舒服,于是就想整合在一起。
相当于需要将许多是关乎于 DOM 的操作的方法放置到 $ 产生的对象的原型链上,于是问题来了,我的 $ 模块中由于需要判断各种情况 所以基本均是使用 return [] 的方式得到的结果,[] 原型链上只有 Array.prototype 和 Object.prototype 当然不能说在这两个对象上添加 addClass 等方法。
然后就认为,那么不适用 return [] 这种方式,而是得到一个 new 出来的对象,该对象的原型链上添入所需要的方法即可。
可是对于需要对参数做各种判断在实现的函数不使用return实在是不现实。
-
function $(str,root){
-
var elements = [],
-
ele_len = 0,
-
reg_spl = /\s*,\s*/,
-
reg_white = /^\s+|\s+$/,
-
dom_obj = {},
-
ret = [],
-
root = root || d,
-
element,i,name;
-
-
if(str.nodeType){ return [str]; }
-
-
if(typeof str !== "string"){ return []; }
-
-
// 单个情况
-
if(str.indexOf(",") === -1){
-
return getDomObj(str,root);
-
}
-
-
elements = str.split(reg_spl);
-
ele_len = elements.length;
-
for(i = 0; i<ele_len; i++){
-
dom_obj = getDomObj(elements[i],root);
-
ret = ret.concat(dom_obj);
-
}
-
return ret;
-
}
-
-
-
function getDomObj(str, root){
-
if(root.querySelectorAll){
-
return slice.call(root.querySelectorAll(str));
-
}else{
-
if(str.indexOf("#")){
-
str = str.slice(1);
-
return [d.getElementById(str)];
-
}else if(str.indexOf(".")){
-
str = str.slice(1);
-
return getByClass(str,root);
-
}else{
-
return slice.call(root.getElementsByTagName(str));
-
}
-
}
-
}
实在无法改动。
Jquery的实现
那么Jquery那边是如何实现的,很简答,使用 return 但是是 return this;
不但可以在各个判断之处及时跳出函数返回结果,也可以方便的控制其原型链。
简单的类Jquery的结构
-
var jQ = function( selector, context ) {
-
return new jQ.fn.init( selector, context );
-
}
-
jQ.fn =jQ.prototype = {}
-
jQ.fn.init = function( selector, context ) {
-
this[0] = document.getElementById(selector); // #开头某一个情况
-
this.length=1;
-
return this;
-
}
-
jQ.fn.init.prototype = jQ.fn;
-
jQ.fn.abc = 1;
那么 所有 jQ 生成的对象可以在内部判断中适当的情况及时 return 出,并且 jQ对象原型链上包含对象 jQ.fn.init.prororype,即 jQ.fn,即 jQ.prototype。所有的 jQ 对象均可以访问 abc 属性。当然,之所以这里这么绕,也和Jquery的自身结构与实现方式有关。
那么:
-
// 模块中的部分代码结构
-
-
// 几个基本选择器方法
-
function getDomObj(str, root){
-
if(root.querySelectorAll){
-
return slice.call(root.querySelectorAll(str)); //使用内置方法
-
}else{
-
if(str.indexOf("#")){
-
str = str.slice(1);
-
return [d.getElementById(str)];
-
}else if(str.indexOf(".")){
-
str = str.slice(1);
-
return getByClass(str,root);
-
}else{
-
return slice.call(root.getElementsByTagName(str));
-
}
-
}
-
}
-
-
function getByClass(classname, root){
-
var elements, doms = [], len;
-
if(root.getElementsByClassName){
-
return slice.call(root.getElementsByClassName(classname))
-
}else{
-
elements = root.getElementsByTagName("*");
-
len = elements.length;
-
-
each(elements, function(ele){
-
if((" " + ele.classname + " ").indexof(" "+str+" ") !== -1){
-
doms.push(ele);
-
}
-
});
-
return doms;
-
}
-
}
-
-
// 转化类数组形似的 each
-
function likeArrayEach( nObj, iterator, context){
-
var arr = [], i, len = nObj.length;
-
-
for (i=0; i<len; i++) {
-
if( nObj[i] ){
-
arr[i] = nObj[i];
-
}
-
};
-
-
each( arr, iterator, context )
-
}
-
-
function dealClass( classStr ){
-
var classesName = [],
-
classStr = trim( classStr );
-
-
return classStr.split(/\s+/g);
-
}
-
-
//为了可以继承DOM的一般方法,将DOM数组信息放入实例对象中
-
function markNObject( array, obj ){
-
for( var i=0,len=array.length; i<len; i++ ){
-
obj[i] = array[i];
-
}
-
obj.length = len;
-
return obj;
-
}
-
-
-
/** 微型选择器 $
-
*
-
* @method $ 目前只支持简单的复合选着 如$("#id, .classname") & $("#id") & $("#id1,#id2")
-
* 暂不支持层级选着 如 $("#id tag")
-
* @param {String} str 必选,选择字符串
-
* @param {Object} obj 可选 选择节点的区域
-
*
-
* @return {Array} 返回目标DOM对象数组
-
*
-
*/
-
function $(str,root){ // $(".classname") & $("#id") & $("#id1,#id2")
-
var elements = [], // 分割后的数组
-
ele_len = 0, // 数组长度
-
reg_spl = /\s*,\s*/, // 截取
-
reg_white = /^\s+|\s+$/,
-
dom_obj = {}, // dom 对象
-
ret = [], // 返回的dom对象
-
root = root || d,
-
element,i,name;
-
-
// 参数为DOM对象
-
if(str.nodeType){
-
this[0] = str;
-
this.length = 1;
-
return this;
-
}
-
-
//不为string返回空数组
-
if(typeof str !== "string"){
-
this.length=0;
-
return this;
-
}
-
-
// 单个情况
-
if(str.indexOf(",") === -1){
-
return markNObject( getDomObj(str,root), this);
-
}
-
-
elements = str.split(reg_spl);
-
ele_len = elements.length;
-
-
for(i = 0; i<ele_len; i++){
-
dom_obj = getDomObj(elements[i],root);
-
ret = ret.concat(dom_obj);
-
}
-
-
return markNObject( ret, this);
-
}
-
-
$.prototype = {
-
constructor : $,
-
-
addClass : function( classes ){
-
var self = this;
-
if( !isArray(classes) ){
-
classes = [classes];
-
}
-
-
likeArrayEach( self, function( dom ){
-
var classStr = dom.className,
-
oldclasses = dealClass( classStr ),
-
newclasses;
-
-
newclasses = arrayUtil.mergeRepeatArray( classes, oldclasses );
-
-
dom.className = newclasses.join(" ");
-
} );
-
-
return this;
-
},
-
deleteClass : function( classes ){
-
var self = this;
-
if( !isArray(classes) ){
-
classes = [classes];
-
}
-
-
likeArrayEach( self, function( dom ){
-
var classStr = dom.className,
-
oldclasses = dealClass( classStr ),
-
newclasses;
-
-
newclasses = arrayUtil.deleteRepeat( oldclasses, classes );
-
-
dom.className = newclasses.join(" ");
-
} );
-
-
return this;
-
},
-
-
hide : function(){
-
var self = this;
-
markNObject( self, function( dom ){
-
dom.style.display = "none";
-
} );
-
-
return this;
-
},
-
show : function(){
-
var self = this;
-
markNObject( self, function( dom ){
-
dom.style.display = "block";
-
} );
-
-
return this;
-
},
-
-
extend : function( obj ){
-
extend( $.prototype, obj );
-
return this;
-
}
-
}
上面为选择器模块中的部分代码。
阅读(4119) | 评论(0) | 转发(0) |