尝试实现类似于jQuery的东西



我正在尝试实现类似于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。你需要一些黑魔法来做到这一点。

最新更新