我正在尝试实现类似于jQuery的东西。
基本上,每当我要对 DOM 元素做某事时,我都想使用包装器对象的方法,而不是直接操作 DOM。
这就是我到目前为止所拥有的
.HTML:
<a href='#!'></a>
.JS:
var dd = function(selector)
{
return new dd.prototype.constructor(selector);
}
dd.prototype =
{
constructor: function(selector)
{
var nodes = document.querySelectorAll(selector);
for(var i = 0; i < nodes.length; i++)
this[i] = nodes[i];
this.length = nodes.length;
return Array.prototype.slice.call(this);
},
addClass: function(cl)
{
alert('a');
}
};
var a = dd('[href="#!"]');
a.addClass('asd');
问题:
- 我在浏览器控制台中收到一个错误,说
a.addClass is not a function
-
dd('a') instanceof dd === false
$('a') instanceof $ === true
,所以我知道我的逻辑在这里有些错误。
可悲的是,我不太明白我做错了什么。
虽然重新发明轮子不是一个好主意,接下来的内容应该对您有所帮助。
考虑到jQuery
支持自定义构建,所以,首先,看看这里 https://github.com/jquery/jquery#how-to-build-your-own-jquery。
var dd = (function() {
function dd(selector) {
// class call check
if(!(this instanceof dd)) {
return new dd(selector);
}
Array
.from(document.querySelectorAll(selector), (el, i) => {
this[i] = el;
})
;
Object
.defineProperty(this, 'length', {
get: () => Object.keys(this).length
})
;
}
dd.prototype.forEach = function(cb) {
Object
.keys(this)
.forEach(i => {
cb(this[i], i)
})
;
return this;
}
dd.prototype.addClass = function() {
this.forEach(el => el.classList.add(...Array.from(arguments)));
return this;
}
dd.prototype.removeClass = function() {
this.forEach(el => el.classList.remove(...Array.from(arguments)));
return this;
}
return dd;
})();
var odd = dd('strong');
var even = dd('span');
window.setTimeout(() => odd.addClass('foo'), 2000);
window.setTimeout(() => even.addClass('baz'), 3000);
console.log('odd', odd.length);
console.log('even', even.length);
.cntr strong,
.cntr span {
display: inline-flex;
width: 20px;
height: 20px;
transition: 250ms all linear;
margin: 2px;
border: 1px solid cyan;
background: lightseagreen;
}
.cntr .foo { background: yellow; }
.cntr .baz { background: orange; }
<section class="cntr">
<strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span><strong></strong><span></span>
</section>
不确定您要实现的目标,但让我们看看现在出了什么问题。
1(你在constructor
上调用new,然后返回return Array.prototype.slice.call(this);
所以你得到的a
是一个数组。显然数组不知道你的函数addClass
.
2(如果您注释掉数组切片部分,您将返回一个this
设置为constructor
的对象,但同样addClass
不会添加到constructor
的对象prototype
。为此,您需要添加如下所示addClass
:
dd.prototype.constructor.prototype.addClass = function (cl) {
alert('a');
}
通过这些更改,您将收到警报,并希望可以进一步进行。所以总的来说这些变化:
var dd = function(selector) {
return new dd.prototype.constructor(selector);
}
dd.prototype = {
constructor: function(selector) {
var nodes = document.querySelectorAll(selector);
for (var i = 0; i < nodes.length; i++)
this[i] = nodes[i];
this.length = nodes.length;
//return Array.prototype.slice.call(this);
},
//addClass: function (cl) {
// alert('a');
//}
};
dd.prototype.constructor.prototype.addClass = function(cl) {
alert('a');
}
var a = dd('[href="#!"]');
a.addClass('asd');
<a href='#!'></a>
您正在混合类和对象工厂。你不能两全其美。
要么你做(jQuery 样式(:
function dd(selector) {
return {
addClass: function () {/**/}
};
}
var a = dd('[href="#!"]');
a.addClass('asd');
或者你这样做:
function dd(selector) {
this.selector = selector;
}
dd.prototype.addClass = function () {/**/};
var a = new dd('[href="#!"]');
a.addClass('asd');
请注意,这不会像jQuery那样自动产生a instanceof Array
。你需要一些黑魔法来做到这一点。