用过JQuery的同学们肯定知道$这个函数了,也肯定知道JQ中方法的链式调用的强大,其实链式调用只不过是一种语法招数,能让你通过重用一个初始操作来达到用少量代码表达复杂操作的目的。这种技术包含两个部分:一个创建代码HTML元素对象的工厂,以及一批对这个HTML元素执行某些操作的方法。每一个这种方法都可以在方法名前附上一个圆点后加入调用连中。方法的链式调用可以被视为选择一个或一批DOM元素对其进行一个或多个操作的过程。下面我们将简单的模拟下$的实现,并详细解析链式调用的原理。
$函数通常返回一个HTML元素或一个HTML元素的集合,我们这里先简单实现一个$函数,能够支持基本的CSS选择符(#id, .class tag),也能够将传入的DOM标签元素包装起来返回,同时根据传入的参数个数选择符合参数的元素。但未支持如:“p a”这种形式的CSS嵌套选择。
/*
* @param {Object} name
* 需要查找的类名
* @param {Object} type
* 需要匹配的元素,默认为全部
* 返回符合匹配的元素集合
*/
var getElementsByClassName = function(name, type){
var ret = [],
elems = document.getElementsByTagName(type || '*'),
reg = new RegExp("(^|\\s)" + name + "($|\\s)");
for(var i = 0, len = elems.length; i < len; ++i){
if(reg.test(elems[i].className)) {
ret.push(elems[i]);
}
}
return ret;
};
/*
* 简单的元素选择器
* */
var $ = function(){
var elems = [];
for (var i = 0, len = arguments.length; i < len; ++i) {
if ('string' === typeof arguments[i]) { //传入字符串
if ('#' === arguments[i].charAt(0)) { //传入ID
var elem = doucment.getElementById(arguments[i].substr(1));
if (elem) {
elems.push(elem);
}
} else if ('.' === arguments[i].charAt(0)) {//传入class
elems = elems.concat(getElementsByClassName(arguments[i].substr(1)));
} else { //传入标签
var tagElems = document.getElementsByTagName(arguments[i]);
for (var j = 0, tagLen = tagElems.length; j < tagLen; ++j) {
elems.push(tagElems[j]);
}
}
} else if (1 === arguments.nodeType) { //传入标签元素
elems.push(arguments[i]);
}
}
return elems;
};
如果把这个函数改造为一个构造器,把那些元素集合保存在一个实例属性中,并让所有定义在构造器函数的prototype属性所指对象中的方法都返回调用方法的那个实例的引用(this),那么它就具有了进行链式调用的能力。我们首先需要把$函数改造成负责创建支持链式调用的对象,同时利用闭包将构造器定义为私有函数。修改后的代码如下:
//自运行函数,用于创建$方法,从而支持链式调用
(function(){
/*私有构造器,用于包装集合元素*/
function _$(els){
this.elems = [];
for (var i = 0, len = els.length; i < len; ++i) {
if ('string' === typeof els[i]) { //传入字符串
if ('#' === els[i].charAt(0)) { //传入ID
var elem = doucment.getElementById(els[i].substr(1));
if (elem) {
this.elems.push(elem);
}
} else if ('.' === els[i].charAt(0)) {//传入class
this.elems = this.elems.concat(getElementsByClassName(els[i].substr(1)));
} else { //传入标签
var tagElems = document.getElementsByTagName(els[i]);
for(var j = 0, tagLen = tagElems.length; j < tagLen; ++j){
this.elems.push(tagElems[j]);
}
}
} else if(1 === els.nodeType){ //传入标签元素
elems.push(els[i]);
}
}
}
//公共接口$
window.$ = function(){
return new _$(arguments);
};
})();
由于所有对象都会继承其原型对象的属性和方法,所以我们可以让定义在原型对象中的那几个方法都返回实例对象的引用,这样就实现了方法的链式调用。我们先给_$增加一些原型方法:
_$.prototype = {
each:function(fn, scope){
for(var i = 0, len = this.elems.length; i < len; ++i){
fn.call(scope||this, this.elems[i]);
}
return this;
},
setStyle:function(prop, value){
this.each(function(elem){
elem.style[prop] = value;
});
return this;
},
show:function(){
this.each(function(elem){
elem.style.display = 'block';
});
return this;
}
};
于是这样就构造了一个链式调用的包装元素,我们可以这样调用: $('div').setStyle('width', '100px').setStyle('height', '100px').setStyle('backgroudColor', 'red'); 这里就给页面的所有div元素设置成高度100px,宽度100px,背景色为红色。完全可以根据自己的需要和想法增加原型方法,这样就可以实现自己的JS库。
分享到:
相关推荐
javascirpt的一些经典特效 第一章.文本特效类 第二章.图片特效类 第三章.鼠标键盘类 第四章.按钮特效类 第五章.日期时间类 第六章.计数转换类 第七章.系统检测类 第八章.页面特效类 第九章.菜单特效类 第十章.密码...
深入讲解javascript
jquery 打造的lightbox插件
javascirpt 小技巧 javascirpt 帮助 javascirpt 小技巧 javascirpt 帮助 javascirpt 小技巧 javascirpt 帮助
通用javaScript的验证框架
javascirpt图片切换效果 rok
JavaScript的基本语法 事件处理 window对象
HTML/javascirpt/css
用Javascript定义类大全 方便编程的模块化 大家快快下载啊 多多交流 用Javascript定义类大全 方便编程的模块化 大家快快下载啊 多多交流
里面有很多JAVAScript的实际运用,比如联动菜单什么的!很好好!推荐给大家
JavaScirpt经典教程+demo JavaScirpt经典教程+demo JavaScirpt经典教程+demo
JavaScirpt搜索关键字(中英文)下拉框提示 在网上查找资料后修改合成的新作,希望指教!
echarts_javascirpt
javascirpt editor专业开发与调式工具 英文版
php mysql javascirpt flash实现网站图片新闻.pdf
图片在窗体间移动效果(HTML+JavaScirpt):图片会在窗体中到处移动效果。
Furious.js 是 AMD 开发的 JavaScirpt 科学计算包,灵感来源于 NumPy。 标签:Furious
里面是关于一些javascript的效果代码,可以帮助大家对js功能有一个大的认识。很实用
这是用Js实现的个模态提示效果,当点击页面上的按钮后会弹出一个提示框,背景会变成灰色不可用。用div模拟模态效果。