前言
JavaScript 的核心是支援面向物件的,同时它也提供了强大灵活的 OOP 语言能力。本文将使用面向物件的方式,来教大家用原生js写出一个类似jQuery这样的类库。我们将会学到如下知识点:闭包:减少变数污染,缩短变数查询范围自执行函式在物件中的运用extend的实现原理如何实现跨浏览器的事件监听原型链与继承接下来我会对类库的核心api进行讲解和展示,文章最后后附带类库的完整源代码,在我之前的文章《3分钟教你用原生js实现具有进度监听的档案上传预览元件》中也使用了类似的方式,感兴趣的可以一起学习,交流。
更加完整的类库地址,请移步github《Xuery——仿jquery API风格的轻量级可扩充套件的原生js框架》
类库设计思路

API介绍和效果展示
事件系结 Xuery.on(eventName, fn) 案例如下:Xuery(\'#demo\').on(\'click\', function(e){
alert(\'hello world!\')
})
复制程式码
访问和设定css Xuery.css(string|object, ?[string]) 案例如下:// 访问css
Xuery(\'#demo\').css(\'width\')
// 设定css
Xuery(\'#demo\').css(\'width\', \'1024px\')
// 设定css
Xuery(\'#demo\').css({
width: \'1024px\',
height: \'1024px\'
})
复制程式码
访问和设定属性 Xuery.attr(string|object, ?[string]) 案例如下:// 访问attr
Xuery(\'#demo\').attr(\'title\')
// 设定attr
Xuery(\'#demo\').attr(\'title\', \'1024px\')
// 设定attrs
Xuery(\'#demo\').attr({
title: \'1024px\',
name: \'1024px\'
})
复制程式码
访问和设定html 案例如下:// 访问
Xuery(\'#demo\').html()
// 设定
Xuery(\'#demo\').html(\'前端学习原生框架\')
复制程式码
还有其他几个常用的API在这里就不介绍了,大家可以在我的github上检视,或者基于这套基础框架,去扩充套件属于自己的js框架。
核心源代码
以下源代码相关功能我做了注释,建议大家认真阅读,涉及到原型链和建构函式的指向的问题,是实现上述呼叫方式的核心,又不懂可以在评论区交流沟通。
/**
* 链模式实现自己的js类库
*/
(function(win, doc){
var Xuery = function(selector, context) {
return new Xuery.fn.init(selector, context)
};
Xuery.fn = Xuery.prototype = {
constructor: Xuery,
init: function(selector, context) {
// 设定元素长度
this.length = 0;
// 预设获取元素的上下文document
context = context || document;
// id选择符,则按位非将-1转化为0
if(~selector.indexOf(\'#\')) {
this[0] = document.getElementById(selector.slice(1));
this.length = 1;
}else{
// 在上下文中选择元素
var doms = context.getElementsByTagName(selector),
i = 0,
len = doms.length;
for(; i this[i] = doms[i];
}
}
this.context = context;
this.selector = selector;
return this
},
// 增强阵列
push: [].push,
sort: [].sort,
splice: [].splice
};
// 方法扩充套件
Xuery.extend = Xuery.fn.extend = function(){
// 扩充套件物件从第二个引数算起
var i = 1,
len = arguments.length,
target = arguments[0],
j;
if(i === len){
target = this;
i--;
}
// 将引数物件合并到target
for(; i for(j in arguments[i]){
target[j] = arguments[i][j];
}
}
return target
}
// 扩充套件事件方法
Xuery.fn.extend({
on: (function(){
if(document.addEventListener){
return function(type, fn){
var i = this.length -1;
for(; i>=0;i--){
this[i].addEventListener(type, fn, false)
}
return this
}
// ie浏览器dom2级事件
}else if(document.attachEvent){
return function(type, fn){
var i = this.length -1;
for(; i>=0;i--){
this[i].addEvent(\'on\'+type, fn)
}
return this
}
// 不支援dom2的浏览器
}else{
return function(type, fn){
var i = this.length -1;
for(; i>=0;i--){
this[i][\'on\'+type] = fn;
}
return this
}
}
})()
})
// 将‘-’分割线转换为驼峰式
Xuery.extend({
camelCase: function(str){
return str.replace(/-(w)/g, function(all, letter){
return letter.toUpperCase();
})
}
})
// 设定css
Xuery.extend({
css: function(){
var arg = arguments,
len = arg.length;
if(this.length return this
}
if(len === 1) {
if(typeof arg[0] === \'string\') {
if(this[0].currentStyle){
return this[0].currentStyle[arg[0]];
}else{
return getComputedStyle(this[0], false)[arg[0]]
}
}else if(typeof arg[0] === \'object\'){
for(var i in arg[0]){
for(var j=this.length -1; j>=0; j--){
this[j].style[Xuery.camelCase(i)] = arg[0][i];
}
}
}
}else if(len === 2){
for(var j=this.length -1; j>=0; j--){
this[j].style[Xuery.camelCase(arg[0])] = arg[1];
}
}
return this
}
})
// 设定属性
Xuery.extend({
attr: function(){
var arg = arguments,
len = arg.length;
if(len return this
}
if(len === 1){
if(typeof arg[0] === \'string\'){
return this[0].getAttribute(arg[0])
}else if(typeof arg[0] === \'object\'){
for(var i in arg[0]){
for(var j=this.length -1; j>= 0; j--){
this[j].setAttribute(i, arg[0][i])
}
}
}
}
else if(len === 2){
for(var j=this.length -1; j>=0; j--){
this[j].setAttribute(arg[0], arg[1]);
}
}
return this
}
})
// 获取或者设定元素内容
Xuery.fn.extend({
html: function(){
var arg = arguments,
len = arg.length;
if(len === 0){
return this[0] && this[0].innerHTML
}else{
for(var i=this.length -1; i>=0; i--){
this[i].innerHTML = arg[0];
}
}
return this
}
})
Xuery.fn.init.prototype = Xuery.fn;
window.Xuery = Xuery;
})(window, document);





























