根据实际的使用情况,之前的用法是
import {DOM} from 'pocket-tool';
// 先获取dom元素
const element = DOM.getElement('#id');
// 再对进行添加class
DOM.addClass(element, 'new-class');
额。。。我自己用起来也是相当不爽的,于是乎,改!换链式写法。
最终效果如下
import {DOM} from 'pocket-tool';
// 先获取dom元素
const element = DOM.getElement('#id');
// 再对进行添加class
element.addClass('new-class');
恩,这样就清爽多了,接下来开始分析具体的思路。
修改两次写法
其实链式写法的关键在于最后的return this;
proto
第一次是使用了__proto__
的写法,其实思路也蛮简单的,将每个DOM
的原型链该写到我定义的对象中。
// 获取dom元素
let element = document.getElmentByClassName('class');
// 拓展方法
const extendObj = {
addClass(className) {
...
return this; // 需要支持链式写法的方法,最后返回this
},
removeClass(className) {
...
return this;
},
on(event, handler, propagation) {
return ... // 不需要支持链式写法的方法,则不需要返回
},
off(event, handler, propagation) {
return ...
},
getDataSet(key) {
return ...
}
};
// 将类数组对象转换为数组对象
element = Array.from(element);
// 构建Element的原型链
element.forEach(e => {
if (!Utils.isNull(e)) {
e.__proto__ = Object.assign(e.__proto__, __proto__); // 重新创建__proto__
}
});
这样虽然可以,但是会有很多不可控因素,因为都坚决抵制修改原生方法的原型链,而且在IE
中也不支持__proto__
,所以当我提交代码后,没过多久就进行修改了。
借鉴jQuery
尝试了各种方法无果后,最后还是去借鉴了一下jQuery
,为啥一开始没看咧,理由很简单,因为一些事情总要自己摸索的嘛。虽然说最后还是回到了jQuery
但是过程还是很愉快的,哈哈哈。jQuery
是将一个个DOM
元素加到数组中,然后进行访问,但是数据的原型链又是Object
。所以就借鉴它们的写法,只不过我没有转化为类数组对象,而是将DOM
按顺序,通过index
作为key
,最后再加上length
。
let elementArray = document.getElementbyClassName('class');
// 拓展方法
const extendObj = {
addClass(className) {
...
return this;
},
removeClass(className) {
...
return this;
},
on(event, handler, propagation) {
return ...
},
off(event, handler, propagation) {
return ...;
},
getDataSet(key) {
return ...;
}
};
// 构建Element的原型链
let element = Object.create(extendObj);
// 创建类数组对象
elementArray.forEach((e, index) => {
element[index] = e;
});
// 赋上length
element.length = elementArray.length;
其实思路蛮简单的,只要将element
的原型链指向extendObj
就好了,这样在访问方法时会自动在原型链上进行查找。return this
的话,其实就是返回当前的对象,也就是element
因此还能继续访问对应的方法。具体的代码就不展开了。
原型链很重要
原型链蛮重要的,额,说实话我也掌握的并没有很好,其中有错误的地方还需要大家指正,当然这里也不会写很多关于原型链的知识。
这里想说的是我如何使用的。原来DOM
元素上原型链不能去修改,因为会导致其他不可预知的错误。所以通过上面的写法,当我们调用方法的时候,访问的原型链其实是extendObj
。当然也增加了一个用来访问原生DOM
元素的方法eq
// 拓展方法
const extendObj = {
eq(index) {
if (this[index]) { // this 是element这个对象,index刚好能够访问对应key的元素
let e = Object.create(extendObj);// 这时还要创建一个新的对象,保证还能继续使用我们定义的方法
e[0] = this[index];
e.length = 1;
return e; // 返回取得的元素
}
return this[index];
}
};
element.eq(0)
这样访问的就是原生的DOM元素啦,这样就做了相对的隔离,又保证了功能的完整性。