1. 自定义事件
1.1 浏览器自带事件
1.2 自定义事件
button1.addEventListener('click', () => {
const event = new CustomEvent("zhangsan", {
detail: {
name: 'zhangsan',
age: 18
},
bubbles: true, // 能否冒泡
cancelable: false // 是否阻止默认事件
})
button1.dispatchEvent(event)
})
div1.addEventListener('zhangsan', (e) => {
console.log('zhangsan')
console.log(e.detail)
})
2. 事件委托
由于冒泡阶段,浏览器从用户点击的内容从下往上遍历至 window,逐个触发事件处理函数, 因此可以监听一个祖先节点(例如爸爸节点、爷爷节点)来同时处理多个子节点的事件
2.1 场景一:给100个按钮添加点击事件
分析:监听100个按钮的祖先,等冒泡的时候判断target是不是这100个按钮中的一个 代码
div1.addEventListener('click',(e)=>{
const t = e. target
if(t.tagName.toLowerCase() === 'button'){
console.log('button被点击了')
console.log('button 的内容是'+t.textContent)
console.log('button data-id 是'+t.dataset.id)
}
})
2.2 场景二:监听目前不存在的点击事件
分析:监听祖先,等点击的时候看看是不是想要坚挺的元素即可 代码
setTimeout(()=>{
const button = document.createElement('button')
button.textContent = 'click 1'
div1.appendChild(button)
},1000)
div1.addEventListener('click',(e)=>{
const t = e.target
if(t.tagName.toLowerCase() === 'button'){
console.log('button被click点击')
}
})
2.3 优点
- 省监听数(内存)
- 可以监听动态元素
3. 封装事件委托
setTimeout(() => {
const button = document.createElement('button')
button.textContent = 'click 1'
div1.appendChild(button)
}, 1000)
on('click','#div1','button',()=>{
console.log('button被点击了')
})
function on(eventType,element,selector,fn){
if(!(element instanceof Element)){
element = document.querySelector(element)
}
element.addEventListener(eventType,(e)=>{
// t是用户操作的元素
const t = e.target
if(t.matches(selector)){
fn(e)
}
})
}
给button嵌套一层span,当点击span时(e.target === 'span'),button点击事件监听依然生效:代码
setTimeout(() => {
const button = document.createElement('button')
const span = document.createElement('span')
span.textContent = 'click 1'
button.appendChild(span)
div1.appendChild(button)
}, 1000)
on('click', '#div1', 'button', () => {
console.log('button 被点击了')
})
function on(eventType, element, selector, fn) {
if (!(element instanceof Element)) {
element = document.querySelector(element)
}
element.addEventListener(eventType, (e) => {
// t是用户操作的元素
let el = e.target
while (!el.matches(selector)) {
if (element === el) {
el = null
break
}
el = el.parentNode
}
el && fn.call(el, e, el)
})
return element
}
4. 整合jQuery
$('#xxx').on('click','li',fn) 代码
let dom = {
on: function(element, eventType, selector, fn) {
element.addEventListener(eventType, e => {
let el = e.target
while (!el.matches(selector)) {
if (element === el) {
el = null
break
}
el = el.parentNode
}
el && fn.call(el, e, el)
})
return element
},
onSwipe: function(element, fn) {
let x0, y0
element.addEventListener('touchstart', function(e) {
x0 = e.touches[0].clientX
y0 = e.touches[0].clientY
})
element.addEventListener('touchmove', function(e) {
if (!x0 || !y0) {
return
}
let xDiff = e.touches[0].clientX - x0
let yDiff = e.touches[0].clientY - y0
if (Math.abs(xDiff) > Math.abs(yDiff)) {
if (xDiff > 0) {
fn.call(element, e, 'right')
} else {
fn.call(element, e, 'left')
}
} else {
if (yDiff > 0) {
fn.call(element, e, 'down')
} else {
fn.call(element, e, 'up')
}
}
x0 = undefined
y0 = undefined
})
},
index: function(element) {
let siblings = element.parentNode.children
for (let index = 0; index < siblings.length; index++) {
if (siblings[index] === element) {
return index
}
}
return -1
},
uniqueClass: function(element, className) {
dom.every(element.parentNode.children, el => {
el.classList.remove(className)
})
element.classList.add(className)
return element
},
every: function(nodeList, fn) {
for (var i = 0; i < nodeList.length; i++) {
fn.call(null, nodeList[i], i)
}
return nodeList
},
create: function(html, children) {
var template = document.createElement('template')
template.innerHTML = html.trim()
let node = template.content.firstChild
if (children) {
dom.append(node, children)
}
return node
},
append: function(parent, children) {
if (children.length === undefined) {
children = [children]
}
for (let i = 0; i < children.length; i++) {
parent.appendChild(children[i])
}
return parent
},
prepend: function(parent, children) {
if (children.length === undefined) {
children = [children]
}
for (let i = children.length - 1; i >= 0; i--) {
if (parent.firstChild) {
parent.insertBefore(children[i], parent.firstChild)
} else {
parent.appendChild(children[i])
}
}
return parent
},
removeChildren: function(element) {
while (element.hasChildNodes()) {
element.removeChild(element.lastChild)
}
return this
},
dispatchEvent: function(element, eventType, detail) {
let event = new CustomEvent(eventType, { detail })
element.dispatchEvent(event)
return this
},
}
5. JS支持事件吗
JS并不支持事件,事件指的是DOM事件,并不属于JS的功能,因为DOM是浏览器提供的功能,JS只是调用了DOM提供的addEventListener接口而已。