搜索
首页web前端js教程如jQuery般易用的api风格代码分享_javascript技巧

回到正题,如jQuery般易用的api风格?那到底是什么样的风格呢?个人觉得比较重要的有两点,一是对dom操作的链式调用,并且都呈队列状态,不仅仅使代码的可读语义变得通俗易懂,而且省去了对同一dom元素的多个链式操作时的回调中嵌回调的方式,这是很重要的一点。
二是对元素的批量操作,这是建立在它强大的选择器上的。jq选择器很强大,这是人所众知的,就不多说了。而且肯定也不是一两天就能实现的了的,所以下面就对我所说的这两点谈谈我的看法。

基于它强大的选择器,jquery所有的dom操作都依赖于根据它选择器取到的一个数组,很多人喜欢把这叫做jq对象。那咱们暂时也先这样叫吧。然后所有的dom操作都是依赖于这个jq对象中每一个元素并发批量执行的。具体到每一个dom操作,大部分的都是呈链式回调的状态,也就是说在这个方法链里面,直接根据方法调用在链中的先后顺序就能知道他们执行的顺序。这种方法链并且串行的形式是它的一大特色。
以至于很多人喜欢用jquery,基本就看中它两点,选择器确实很强大,链式调用确实很方便很易用,代码逻辑瞬间变得简单。正因为他把很多的代码逻辑都放到自己内部去处理了,留给编码者考虑的问题就少了很多,所以一方面你觉得好用的同时,也就失去了一次锻炼编码逻辑的机会。因此我不建议初学者直接学习使用jquery或者其他的框架,因为他们会让你对js的理解越来越少。我的观点是所有的框架或者库都是拿来使用的,拿来提高开发效率和管理便利度的,而不是拿来学习的。(当然,研究源码的除外)。
那么,既然觉得jquery的api风格好用,那我们何尝不尝试一下构建这种类似的api风格呢?(声明:以下尝试都仅仅是提供一种思路,代码并不完善...)

复制代码 代码如下:

var get = function (ids) {
var d = document, a = -1;
this.elements = [];
if (typeof ids != 'string' && !!ids.length) {
for (var i=0; ivar id = ids[i], o;
o = typeof id == 'string' ? d.getElementById(id) : id;
this.elements.push(o);
}
} else {
while (typeof arguments[ a] == 'string') {
this.elements.push(d.getElementById(arguments[a]));
}
}
}

然后为它扩展一些操作dom的方法
复制代码 代码如下:

get.prototype = {
each : function () {},
animate : function () {}
}

当然,这种方式和jQuery看起来不太一样,但能理解就行,jquery可能是这个样子:
复制代码 代码如下:

jQuery = window.jQuery = window.$ = function( selector, context ) {

return new jQuery.fn.init( selector, context );
}

jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {}
}

接下来对获取的队列进行批量操作,不可避免的就需要一个each的遍历方法。
复制代码 代码如下:

each : function (fn) {
for (var i=0; ifn.call(this, this.elements[i])
}
return this;
},

each为get.prototype扩展出的方法,提供一个参数function,并且遍历dom列表,把function绑定到每一个元素上。然后让它返回get.prototype,因为prototype本身具有类似于“超类”的性质,所以凡是返回给prototype对象的方法都能继续调用prototype扩展出来到方法。

为了使这个尝试更有意义一点,接下来来做一个animate的函数吧。这个函数是jquery对dom操作很常用的一个方法,有了它,大部分的动画都变得那么简单和容易了。下面会是一个简单的实现:
复制代码 代码如下:

animate: function (config) {
if (!this.animQueue) this.animQueue = HR._animQueue = [];
var a = 0, time, tween, ease, callback;
while (arguments[ a]) {
if (typeof arguments[a] == 'number') time = arguments[a];
if (typeof arguments[a] == 'string') {
if (/^ease*/.test(arguments[a])) ease = arguments[a];
else tween = arguments[a];
}
if (HR.isFunction(arguments[a])) callback = arguments[a];
}

this.animQueue.push({
config: config,
time: time,
tween: tween,
ease: ease,
callback: callback
});
if (this.animQueue.length == 1) this.execute(this.animQueue);

return this;
},

光看这一段可能看不出什么端倪,是的,因为要像jquery一样做成串行的方法链,就需要一个临时队列来操作,要不然即使方法链形成了,但这些方法都是并行的,达不到我们想要的效果。所以上面一段代码主要是处理animate推入队列的一个逻辑,然后对参数arguments做了一些判断,以便在写参数的时候能更加随意,除了第一个参数和最后一个callback外,其余参数不用考虑位置和是否必填,以增强易用性。
核心的变换函数在execute上,
复制代码 代码如下:

execute : function (queue) {
var _this = this, m = 0, n = 0,
_anim = function (el, key, from, to, at, tw, ease, cb) {
var isOP = (key == 'opacity' && !HR.support.opacity), _key = key;
if (isOP) {to = to*100; _key = 'filter'}
var s = new Date,
d = at,
b = parseFloat(from) || 0,
c = to-b;

(function () {
var t = new Date - s;
if (t >= d) {
n ;
t = d;
el.style[_key] = (isOP ? 'alpha(opacity=' : '') Tween.Linear(t, b, c, d) (key != 'opacity' ? 'px' : '') (isOP ? ')' : '');
!!cb && cb.apply(el);
if (m == n && _this.animQueue.length > 1) {
_this.animQueue.shift();
_this.execute(_this.animQueue);
}

return;
}
el.style[_key] = (isOP ? 'alpha(opacity=' : '') Tween[tw][ease](t, b, c, d) (key != 'opacity' ? 'px' : '') (isOP ? ')' : '');

if (!HR.timers[el.id]) HR.timers[el.id] = [];
HR.timers[el.id].push(setTimeout(arguments.callee, 16));

})();
},
_q = this.animQueue[0];

return this.each(function (el) {
for (var k in _q.config) {
m ;
_anim(el,
k,
k == 'opacity' && !HR.support.opacity ? HR.getStyle('filter', el) == '' ? 100 : parseInt(HR.getStyle('filter', el).match(/d{1,3}/g)[0]) : HR.getStyle(k, el),
_q.config[k],
typeof _q.time == 'number' ? _q.time : 1000,
typeof _q.tween == 'string' && !/^ease*/.test(_q.tween) ? _q.tween : 'Quart',
typeof _q.ease == 'string' && /^ease*/.test(_q.ease) ? _q.ease : 'easeOut',
_q.callback)
}
});
}

这一段看起来就要复杂一些了,最基本的变化还是在_anim这个私有函数上。其余的代码基本在做一些批量的操作,和透明度变化兼容性,以及当前变换是否执行完毕的功能。结合这两段,基本就实现了jquery的animate的效果了。属于一个简化版本。
当然,还不能忘了很重要的一点,就是既然可以变换,那就必须有个stop的方法让这个变换可控,要不然这个代码的可用性会大打折扣,参考以下代码:
复制代码 代码如下:

stop : function (clearQueue) {
if (clearQueue) HR._animQueue.length = 0;
this.each(function (el) {
if (!!HR.timers[el.id])
for (var i=0; i});
return this;
},

针对不同的dom元素id设置专门的临时计时器存贮,HR.timers[el.id],然后遍历当前dom列表,把对应的计时器clear掉。参数clearQueue作为可选参数,用来控制是否清掉后续等待执行的animate。

为了让这个方法更加好玩一点,我加了几种额外的缓动方式,jquery只有一种swing,然后所有的缓动算法放置在Tween对象中以供使用。下面是我做测试的源码,(如有纰漏,各位见谅)
复制代码 代码如下:

/* =========== animate js ============ */
/* @author:hongru.chen */
/* =================================== */

if (typeof HR == 'undefined' || !HR)
HR = {
extend : function (destination, source, override) {
if (override === #ff0000) override = true;
for (var property in source) {
if (override || !(property in destination)) {
destination[property] = source[property];
}
}
return destination;
}
};

(function () {

var Tween = { // 以下算子的参数分别表示: t:运行时间,b:开始量,c:总变化量,d:总时间
Linear: function(t,b,c,d){ return c*t/d b; },
Quad: {
easeIn: function(t,b,c,d){
return c*(t/=d)*t b;
},
easeOut: function(t,b,c,d){
return -c *(t/=d)*(t-2) b;
},
easeInOut: function(t,b,c,d){
if ((t/=d/2) return -c/2 * ((--t)*(t-2) - 1) b;
}
},
Cubic: {
easeIn: function(t,b,c,d){
return c*(t/=d)*t*t b;
},
easeOut: function(t,b,c,d){
return c*((t=t/d-1)*t*t 1) b;
},
easeInOut: function(t,b,c,d){
if ((t/=d/2) return c/2*((t-=2)*t*t 2) b;
}
},
Quart: {
easeIn: function(t,b,c,d){
return c*(t/=d)*t*t*t b;
},
easeOut: function(t,b,c,d){
return -c * ((t=t/d-1)*t*t*t - 1) b;
},
easeInOut: function(t,b,c,d){
if ((t/=d/2) return -c/2 * ((t-=2)*t*t*t - 2) b;
}
},
Quint: {
easeIn: function(t,b,c,d){
return c*(t/=d)*t*t*t*t b;
},
easeOut: function(t,b,c,d){
return c*((t=t/d-1)*t*t*t*t 1) b;
},
easeInOut: function(t,b,c,d){
if ((t/=d/2) return c/2*((t-=2)*t*t*t*t 2) b;
}
},
Sine: {
easeIn: function(t,b,c,d){
return -c * Math.cos(t/d * (Math.PI/2)) c b;
},
easeOut: function(t,b,c,d){
return c * Math.sin(t/d * (Math.PI/2)) b;
},
easeInOut: function(t,b,c,d){
return -c/2 * (Math.cos(Math.PI*t/d) - 1) b;
}
},
Expo: {
easeIn: function(t,b,c,d){
return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) b;
},
easeOut: function(t,b,c,d){
return (t==d) ? b c : c * (-Math.pow(2, -10 * t/d) 1) b;
},
easeInOut: function(t,b,c,d){
if (t==0) return b;
if (t==d) return b c;
if ((t/=d/2) return c/2 * (-Math.pow(2, -10 * --t) 2) b;
}
},
Circ: {
easeIn: function(t,b,c,d){
return -c * (Math.sqrt(1 - (t/=d)*t) - 1) b;
},
easeOut: function(t,b,c,d){
return c * Math.sqrt(1 - (t=t/d-1)*t) b;
},
easeInOut: function(t,b,c,d){
if ((t/=d/2) return c/2 * (Math.sqrt(1 - (t-=2)*t) 1) b;
}
},
Elastic: {
easeIn: function(t,b,c,d,a,p){
if (t==0) return b; if ((t/=d)==1) return b c; if (!p) p=d*.3;
if (!a || a else var s = p/(2*Math.PI) * Math.asin (c/a);
return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) b;
},
easeOut: function(t,b,c,d,a,p){
if (t==0) return b; if ((t/=d)==1) return b c; if (!p) p=d*.3;
if (!a || a else var s = p/(2*Math.PI) * Math.asin (c/a);
return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) c b);
},
easeInOut: function(t,b,c,d,a,p){
if (t==0) return b; if ((t/=d/2)==2) return b c; if (!p) p=d*(.3*1.5);
if (!a || a else var s = p/(2*Math.PI) * Math.asin (c/a);
if (t return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 c b;
}
},
Back: {
easeIn: function(t,b,c,d,s){
if (s == undefined) s = 1.70158;
return c*(t/=d)*t*((s 1)*t - s) b;
},
easeOut: function(t,b,c,d,s){
if (s == undefined) s = 1.70158;
return c*((t=t/d-1)*t*((s 1)*t s) 1) b;
},
easeInOut: function(t,b,c,d,s){
if (s == undefined) s = 1.70158;
if ((t/=d/2) return c/2*((t-=2)*t*(((s*=(1.525)) 1)*t s) 2) b;
}
},
Bounce: {
easeIn: function(t,b,c,d){
return c - Tween.Bounce.easeOut(d-t, 0, c, d) b;
},
easeOut: function(t,b,c,d){
if ((t/=d) return c*(7.5625*t*t) b;
} else if (t return c*(7.5625*(t-=(1.5/2.75))*t .75) b;
} else if (t return c*(7.5625*(t-=(2.25/2.75))*t .9375) b;
} else {
return c*(7.5625*(t-=(2.625/2.75))*t .984375) b;
}
},
easeInOut: function(t,b,c,d){
if (t 否则返回 Tween.Bounce.easeOut(t*2-d, 0, c, d) * .5 c*.5 b;
}
}
}

var get = function (ids) {
var d = document, a = -1;
this.elements = [];
if (typeof ids != 'string' && !!ids.length) {
for (var i=0; ivar id = ids[i],哦;
o = typeof id == '字符串' ? d.getElementById(id) : id;
this.elements.push(o);
}
} else {
while (typeof argument[ a] == 'string') {
this.elements.push(d.getElementById(arguments[a]));
}
}
}

get.prototype = {

each : function (fn) {
for (var i=0; ifn.call(this, this.elements[i])
}
返回这个;
},

setStyle : function (p, v) {
this.each(function (el) {
el.style[p] = v;
});
返回这个;
},

show : function () {
var _this = this;
this.each(function (el) {
_this.setStyle('display', 'block');
})
返回这个;
},

隐藏 : function () {
var _this = this;
this.each(function (el) {
_this.setStyle('display', 'none');
})
返回这个;
},

animate: function (config) {
if (!this.animQueue) this.animQueue = HR._animQueue = [];
var a = 0,时间,补间,缓动,回调;
while (arguments[a]) {
if (typeof argument[a] == 'number') time = argument[a];
if (typeof argument[a] == 'string') {
if (/^ease*/.test(arguments[a])) ease = argument[a];
else tween = 参数[a];
}
if (HR.isFunction(arguments[a])) 回调 = argument[a];
}

this.animQueue.push({
config: 配置,
时间: 时间,
补间: 补间,
ease: 轻松,
回调:回调
});
if (this.animQueue.length == 1) this.execute(this.animQueue);

返回此;
},

stop : function (clearQueue) {
if (clearQueue) HR._animQueue.length = 0;
this.each(function (el) {
if (!!HR.timers[el.id])
for (var i=0; i});
返回这个;
},

execute : function (queue) {
var _this = this, m = 0, n = 0,
_anim = function (el, key, from, to, at , tw, ease, cb) {
var isOP = (key == 'opacity' && !HR.support.opacity), _key = key;
if (isOP) {to = to*100; _key = 'filter'}
var s = new Date,
d = at,
b = parseFloat(from) || 0,
c = to-b;

(function () {
var t = new Date - s;
if (t >= d) {
n ;
t = d;
el .style[_key] = (isOP ? 'alpha(opacity=' : '') Tween.Linear(t, b, c, d) (key != 'opacity' ? 'px' : '') (isOP ? ' )' : '');
!!cb && cb.apply(el);
if (m == n && _this.animQueue.length > 1) {
_this.animQueue.shift( );
_this.execute(_this.animQueue);

返回;
}
el.style[_key] = (isOP ? 'alpha(opacity=' : '') Tween[tw][ease](t, b, c, d) (key != 'opacity' ? 'px' : '') (isOP ? ')' : ''); >if (!HR.timers[el.id]) HR.timers[el.id] = []
HR.timers[el.id].push(setTimeout(arguments.callee, 16)); 🎜>
})();
},
_q = this.animQueue[0];

return this.each(function (el) {
for (var k in _q.config) {
m ;
_anim(el,
k,
k == 'opacity' && !HR.support.opacity ? HR.getStyle('filter', el) == '' ? 100 : parseInt(HR.getStyle('filter', el).match(/d{1, 3}/g)[0]) : HR.getStyle(k, el),
_q.config[k],
typeof _q.time == 'number' ? _q.time : 1000,
typeof _q.tween == 'string' && !/^ease*/.test(_q.tween) ? _q.tween : 'Quart',
typeof _q.ease == 'string' && /^ease* /.test(_q.ease) ? _q.ease : 'easeOut',
_q.callback)
}
});
}
}

HR.extend(HR, {
get : function () {
返回新的 get(参数);
},
isFunction : function(o) {
return typeof(o) == 'function' && (!Function.prototype.call || typeof(o.call) == 'function')
},
getStyle : function (p, el) {
返回 el.currentStyle ? function () {
try {
var d = document.createElement('div');
d.style['display'] = 'none';
d.innerHTML = '';
var a = d.getElementsByTagName('a')[0];
return {
不透明度: a.style.opacity === '0.5'
}
} 最后 {
d = null;
}
})(),

计时器 : { }

});
})();



然后为了让大家看的直观一点,小做了两个demo
【demo1】

[Ctrl A 全选 注:
如需引入外部Js需刷新才能执行
]
【demo2】
[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]
声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
JavaScript评论:使用//和 / * * / * / * /JavaScript评论:使用//和 / * * / * / * /May 13, 2025 pm 03:49 PM

JavaScriptusestwotypesofcomments:single-line(//)andmulti-line(//).1)Use//forquicknotesorsingle-lineexplanations.2)Use//forlongerexplanationsorcommentingoutblocksofcode.Commentsshouldexplainthe'why',notthe'what',andbeplacedabovetherelevantcodeforclari

Python vs. JavaScript:开发人员的比较分析Python vs. JavaScript:开发人员的比较分析May 09, 2025 am 12:22 AM

Python和JavaScript的主要区别在于类型系统和应用场景。1.Python使用动态类型,适合科学计算和数据分析。2.JavaScript采用弱类型,广泛用于前端和全栈开发。两者在异步编程和性能优化上各有优势,选择时应根据项目需求决定。

Python vs. JavaScript:选择合适的工具Python vs. JavaScript:选择合适的工具May 08, 2025 am 12:10 AM

选择Python还是JavaScript取决于项目类型:1)数据科学和自动化任务选择Python;2)前端和全栈开发选择JavaScript。Python因其在数据处理和自动化方面的强大库而备受青睐,而JavaScript则因其在网页交互和全栈开发中的优势而不可或缺。

Python和JavaScript:了解每个的优势Python和JavaScript:了解每个的优势May 06, 2025 am 12:15 AM

Python和JavaScript各有优势,选择取决于项目需求和个人偏好。1.Python易学,语法简洁,适用于数据科学和后端开发,但执行速度较慢。2.JavaScript在前端开发中无处不在,异步编程能力强,Node.js使其适用于全栈开发,但语法可能复杂且易出错。

JavaScript的核心:它是在C还是C上构建的?JavaScript的核心:它是在C还是C上构建的?May 05, 2025 am 12:07 AM

javascriptisnotbuiltoncorc; saninterpretedlanguagethatrunsonenginesoftenwritteninc.1)javascriptwasdesignedAsalightweight,解释edganguageforwebbrowsers.2)Enginesevolvedfromsimpleterterterpretpreterterterpretertestojitcompilerers,典型地提示。

JavaScript应用程序:从前端到后端JavaScript应用程序:从前端到后端May 04, 2025 am 12:12 AM

JavaScript可用于前端和后端开发。前端通过DOM操作增强用户体验,后端通过Node.js处理服务器任务。1.前端示例:改变网页文本内容。2.后端示例:创建Node.js服务器。

Python vs. JavaScript:您应该学到哪种语言?Python vs. JavaScript:您应该学到哪种语言?May 03, 2025 am 12:10 AM

选择Python还是JavaScript应基于职业发展、学习曲线和生态系统:1)职业发展:Python适合数据科学和后端开发,JavaScript适合前端和全栈开发。2)学习曲线:Python语法简洁,适合初学者;JavaScript语法灵活。3)生态系统:Python有丰富的科学计算库,JavaScript有强大的前端框架。

JavaScript框架:为现代网络开发提供动力JavaScript框架:为现代网络开发提供动力May 02, 2025 am 12:04 AM

JavaScript框架的强大之处在于简化开发、提升用户体验和应用性能。选择框架时应考虑:1.项目规模和复杂度,2.团队经验,3.生态系统和社区支持。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具