核心方法
- 获取DOM =>
$('button') - 返回指定下标元素 =>
eq() - 添加点击事件click =>
$().click() - 添加事件 =>
$().on() - 返回上一个操作对象 =>
end() - 样式设置与获取 =>
$().css() - css样式拦截 =>
$.cssHooks
链式调用原理
原理是在内部每一个方法后面都加了一个return this。
在一个对象里面,this指向的是对象本身,当我们调用方法的时候,这些方法都是在对象内部调用的,所以加this才可以访问到这些方法。
如果没有加上return this的话,那么执行完一个函数之后,会默认返回undefined,undefine是JS内部隐式添加的。
DOMContentLoaded和load
两者触发时机不一样,先执行DOMContentLoaded,再执行load,DOM文档加载的步骤为:
- 解析HTML结构;
- 加载外部脚本和样式表文件;
- 解析并执行脚本代码;
- DOM树构建完成,执行
DOMContentLoaded; - 加载图片等外部文件;
- 页面加载完毕,执行
load。
实现代码
function $(...arg) {
// 调用$方法并返回Jerry实例化
return new Jerry(...arg)
}
// 类中的this始终指向new 实例化对象
class Jerry {
constructor(arg, root) {
// 保存上一次操作对象,用于调用end()返回
this.prevObject = root || $('document', {})
if (typeof arg === 'string') {
/** @字符串 **/
const eles = document.querySelectorAll(arg)
this.setElement(eles)
} else if (typeof arg === 'object') {
/** @对象 **/
this.setElement(arg)
} else if (typeof arg === 'function') {
/** @函数 **/
// 监听DOMContentLoaded事件
window.addEventListener('DOMContentLoaded', arg)
}
}
// 🔥1、将DOM添加到this上
setElement(eles) {
// 如果没有length,表示是DOM对象且只有一个元素
if (eles.length === undefined) {
this[0] = eles
this.length = 1
} else {
// 多个元素
for (let i = 0; i < eles.length; i++) {
this[i] = eles[i]
}
this.length = eles.length
}
// 返回this,形成链式结构
return this
}
// 🔥2、获取指定元素
eq(index) {
return $(this[index], this)
}
// 🔥3、给this上所有元素添加点击事件
click(fn) {
for (let i = 0; i < this.length; i++) {
// 注意fn不能写成fn()
this[i].addEventListener('click', fn)
}
// 返回this,形成链式结构
return this
}
// 🔥4、添加事件(可多个事件绑定同一个方法)
on(eventNames, fn) {
// mousemove mouseup => ['mousemove', 'mouseup']
// 去除两边空格
eventNames = eventNames.trim().split(' ')
// 去除无用空格
eventNames = eventNames.filter(item => item)
for (let i = 0; i < this.length; i++) {
for (let j = 0; j < eventNames.length; j++) {
this[i].addEventListener(eventNames[j], fn)
}
}
}
// 🔥5、返回上一个操作对象
end() {
return this.prevObject
}
// 🔥6、样式相关
css(...arg) {
// 字符串 agr[0] && !arg[1] => 获取样式
// 字符串 agr[0] && arg[1] => 设置单个样式
// 对象 agr[0] => 批量设置样式
if (typeof arg[0] === 'string') {
const [ attr, value ] = arg // 注意arg是个数组
// 设置单个样式
if (value) {
for (let i = 0; i < this.length; i++) {
Jerry.setStyle(this[i], attr, value)
}
} else {
// 获取样式,获取第一个元素的样式
return Jerry.getStyle(this[0], attr) // 注意要return
}
} else if (typeof arg[0] === 'object') {
// 批量设置样式
for (const attr in arg[0]) {
for (let i = 0; i < this.length; i++) {
Jerry.setStyle(this[i], attr, arg[0][attr])
}
}
}
// 返回this,形成链式结构
return this
}
// 🔥静态方法setStyle,方便class内部、外部直接使用
static setStyle(el, attr, value) {
// 🔥7、css Hooks拦截(设置单个样式时)
if (attr in $.cssHooks) {
// 拦截了要设置的样式
$.cssHooks[attr].set(el, attr, value)
} else {
el.style[attr] = value
}
}
// 🔥静态方法setStyle,方便class内部、外部直接使用
static getStyle(el, attr) {
// 🔥7、css Hooks拦截(获取单个样式时)
if (attr in $.cssHooks) {
// 拦截了要设置的样式
$.cssHooks[attr].get(el, attr)
} else {
return getComputedStyle(el)[attr]
}
}
}
使用
<div flex>
<button class="btn1">按钮1</button>
<button class="btn2">按钮2</button>
<button class="btn3">按钮3</button>
</div>
// Dom内容加载完毕执行
$(function () {
console.log('页面加载')
})
// 7、css Hooks拦截(获取/设置单个样式时)
$.cssHooks = {
backgroundColor: {
set () {
console.log('你设置了背景')
},
get () {
console.log('你获取了背景')
}
}
}
// 1、获取元素
console.log($('button'), '左获取标签为button的所有元素')
console.log($(document.querySelector('button')), '⬅️获取button的第一个元素')
console.log($(document.querySelectorAll('button')), '⬅️获取button的所有元素')
// 2、获取指定元素
console.log($('button').eq(1), '⬅️获取下表为1的元素')
// 3、添加点击事件
$('button').click(function(){
console.log(this)
})
// 4、添加事件(可多个事件绑定同一个方法)
$('button').eq(0).on('mouseenter mouseleave', function () {
console.log('第一个按钮鼠标移入和移出')
})
// 5、返回上一个操作对象
console.log($('button').eq(0).end(), '上一个操作对象')
// 6、样式相关
// 获取样式
console.log($('button').css('backgroundColor'), '获取了样式,无法再链式调用')
// 设置单个样式
$('button').eq(0).css('backgroundColor', '#F56C6C')
// 批量设置样式
$('button').eq(0).css({
opacity: 0.5,
borderRadius: '100px'
})