文档插入
再看一组逻辑一致的方法,按一样的套路解决
append(content|fn)
– 将参数添加至匹配元素尾部prepend(content|fn)
– 将参数添加至匹配元素头部after(content|fn)
– 将参数添加至匹配元素后方before(content|fn)
– 将参数添加至匹配元素前方
通用逻辑
- 概述:将参数插入至匹配元素相应的位置
- 解析:
- 与前面的不同,这边参数接收的尺度要宽一些
- 对于字符串,不会再当作选择器处理,直接以HTML形式插入
- 对于数字,当作字符串处理,对于普通对象不搭理,对于数组,则遍历按规矩处理
- 对于函数
- 遍历当前的调用者,将遍历的索引值和当前遍历元素的内容作为参数提供给函数,且函数执行时的
this
指向此元素 - 将执行函数的返回值重新塞入进行判断
- 遍历当前的调用者,将遍历的索引值和当前遍历元素的内容作为参数提供给函数,且函数执行时的
- 返回值为调用者
因为已经有经验,那么此处就直接展示最后的集合版
jquery.each([
{
type: "append",
position: "beforeend",
}, {
type: "prepend",
position: "afterbegin",
}, {
type: "after",
position: "afterend",
}, {
type: "before",
position: "beforebegin",
},
], (_i, { type, position }) => {
jquery.fn[type] = function(content) {
//不接受null 和 undefined
if (content == null) {
return this;
} else if (isFunction(content)) {//对于函数,将返回值重新重新塞入
return this.each(function(index) {
jquery(this)[type](content.call(this, index, this.innerHTML));
});
} else if (isArrayLike(content)) {//对于数组
const n = this.length;//记录当前调用者的长度
return this.each( function (index) {
//创造一个定位节点
const node = document.createElement("div");
//将节点插入至相应的位置
this.insertAdjacentElement(position, node);
//获取定位节点的父节点,由它来操控定位节点
const father = node.parentNode;
//当遍历不为最后一次时,需要检查是否有节点元素,进行克隆
if (index === n - 1) {
$.each(content, (_i, target) => {
if (typeof target === "object" && this.nodeType) {
father.insertBefore(target, node);
} else {
node.insertAdjacentHTML('beforebegin', target);
}
});
} else {
$.each(content, (_i, target) => {
if (typeof target === "object" && this.nodeType) {
father.insertBefore(target.cloneNode(true), node);
} else {
node.insertAdjacentHTML('beforebegin', target);
}
});
}
//最后移除掉定位节点
node.remove();
});
} else if (content.nodeType) {//对于DOM元素节点,需要保留样本,克隆
return this.each((index, value) => {
if (index === this.length - 1) {
value.insertAdjacentElement(position, content);
} else {
value.insertAdjacentElement(position, content.cloneNode(true));
}
});
} else if (typeof content !== "object") {//普通的对象不接收
return this.each(function() {
this.insertAdjacentHTML(position, content);
});
}
};
});
因为参数的宽大政策,导致结构更加的复杂,这一点很坑
对于数组参数的处理当中,我是想直接遍历数组,将元素一个个塞入,但是对于头部插入时又会导致上下颠倒,强行遍历也需要根据数据类型来定,不过这么写条件限制也不会有好结果,点到为止
对于文档处理的函数,都涉及到了克隆,不仅仅是节点本身克隆,还有事件,所以后续的几个方法暂时略过,等完成事件处理后再回补
属性操作
属性的操作上,分了三批
-
HTML内容、纯文本、value值
-
CSS类
-
属性与属性节点
HTML内容、纯文本、value值
从这三个函数入手
-
html([val|fn])
-
text([val|fn])
-
val([val|fn])
对于参数的逻辑处理是一致,只是读取和修改的值不一样
三者的逻辑总结
- 没有参数时,返回第一个匹配元素的内容
- 有参数,则将参数设定为所有匹配元素的内容
- 对于函数参数,则会执行遍历,提供相应的参数,有效的返回值将作为对应元素的内容
对于内容,原生DOM元素都有相应可读可写的属性
//HTML\text\value
jquery.fn.extend({
html(value) {
return modifiedData.call(this, "innerHTML", value);
},
text(value) {
return modifiedData.call(this, "innerText", value);
},
val(value) {
return modifiedData.call(this, "value", value);
},
});
再搭建modifiedData()
函数
//type对应属性 value对应收到的参数
const modifiedData = function(type, value) {
if (typeof value == 'undefined') {//null可以接受,作为清空属性使用
return this[0][type];
} else if (isFunction(value)) {
return this.each(function(index) {
const data = value.call(this, index, this[type]);
if (typeof data != 'undefined') {
this[type] = data;
}
});
} else {
return this.each(function() {
this[type] = value;
});
}
};
需要注意的是,这三个都是属性,修改value值时,并不会改变属性节点value