我正在尝试实现类似于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
,所以我知道我的逻辑在某种程度上是错误的。答案 0 :(得分:2)
虽然重新发明轮子不是一个好主意, 以下内容可以帮助您。
考虑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 :(得分:1)
不确定你想要实现的目标但是现在就看看出了什么问题。
1)您在constructor
上调用new,然后返回return Array.prototype.slice.call(this);
,因此您在a
中获得的是一个数组。显然,数组不知道你的函数addClass
2)如果您注释掉数组切片部分,您将返回this
设置为constructor
的对象,但addClass
的{{1}}对象未添加prototype
{1}}。为此,您需要添加constructor
,如下所示:
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');
答案 2 :(得分:1)
您正在混合类和对象工厂。你无法双管齐下。
你要么(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
。你需要一些黑魔法来做到这一点。