事件的绑定方式
DOM 0级
事件属性方式
<button onclick="alert()">按钮1</button>
赋值式
<button>按钮2</button>
var btn2 = document.querySelectorAll('button')
btn2.onclick = function(){
alert('事件赋值1')
}
解绑赋值式
ele.onclick = null
DOM 2级
事件监听方式
- ele.addEventListener('事件类型',function(){})
- 事件监听方式后面的事件不会覆盖前面的事件
<button>按钮3</button>
var btn3 = document.querySelectorAll('button') btn3.addEventListener('click',function(){ alert('事件监听1') }) btn3.addEventListener('click',function(){ alert('事件监听2') }
解绑事件监听
- ele.removeEventListener('事件类型',事件处理函数名)
- 这里要把监听方式改为函数,才方便解除
<button>按钮3</button>
var btn3 = document.querySelectorAll('button') function fun1(){ alert('事件监听1') } function fun2(){ alert('事件监听2') } btn3.addEventListener('click',fun1) btn3.addEventListener('click',fun2) btn3.removeEventListener('click',fun1)
兼容性问题
- 兼容IE7,8 : ele.addEvent('on事件类型',function(){})
区别:
事件赋值与事件监听同事件属性相比,实现了结构与行为分离
事件赋值与事件监听:事件监听方式后面的事件不会覆盖前面的事件,而事件赋值会覆盖掉
事件目标对象
事件对象
- event
事件目标对象target
- 当前选中的元素节点,点击谁就是谁
- 例如:div里有p,点击p就返回p
<div> <p></p> </div>
var divEle = document.querySelector('div') divEle.addEventListener('click',function(e){ e = e || window.event // 事件对象 var target = e.target || e.srcElement // 事件目标对象 console.log('target ',target) })
*{padding: 0;margin: 0;} div{ width: 200px; height: 200px; background-color: skyblue; margin: 100px; } p{ width: 100px; height: 100px; ackground-color: pink; }
兼容IE
e.target || e.srcElement
事件传播
事件冒泡
- 嵌套的元素,事件会传播
- 事件传播方向问题:从事件目标对象开始,依次往外传,传到window结束
- 由内向外传的事件方式称为事件冒泡(默认传播行为)
<div> <h4> <p></p> </h4> </div>
var divEle = document.querySelector('div') var pEle = document.querySelector('p') var h4Ele = document.querySelector('h4') divEle.addEventListener('click', function (e) { e = e || window.event // 事件对象 var target = e.target || e.srcElement // 事件目标对象 console.log('div元素 ', target) //div }) pEle.addEventListener('click', function (e) { console.log('p元素') //p 、h4、div })
* { padding: 0; margin: 0; } div { width: 200px; height: 200px; background-color: skyblue; margin: 100px; } p { width: 100px; height: 100px; background-color: pink; } h4 { width: 150px; height: 150px; background-color: blueviolet; }
事件捕获
- 由外向内,从window对象往事件目标对象传
- 利用监听事件,将第三个参数设为true表示事件捕获,默认为false表示事件冒泡
- ele.addEventListener('事件类型',function(){},true)
var divEle = document.querySelector('div') var pEle = document.querySelector('p') var h4Ele = document.querySelector('h4') divEle.addEventListener('click', function (e) { e = e || window.event // 事件对象 var target = e.target || e.srcElement // 事件目标对象 console.log('div元素 ', target) //div },true) pEle.addEventListener('click', function (e) { console.log('p元素') //div h4 p },true)
阻止事件传播
- e.stopPropagation()
- 兼容性写法:e.stopPropagation?e.stopPropagation():e.cancelBubble = true
- 写在哪,就从哪开始结束
h4Ele.addEventListener('click', function (e) { e.stopPropagation?e.stopPropagation():e.cancelBubble = true // 阻止事件传播 console.log('h4元素') //点p 返回 p、h4 点h4就返回h4 },false)
事件委托
事件委托/代理 利用 事件冒泡 实现
使用场景
当要给多个元素循环绑定事件的时候可以考虑使用事件委托简化操作
注: 不支持事件冒泡的不能使用 如:焦点事件
好处
- 减少了事件绑定的数量;
- 对后来动态创建的元素依然有效,
- 解决动态添加的元素节点无法绑定事件的问题
<ul> <li>张同学</li> <li>李同学</li> <li>王同学</li> </ul>
function test1() { var liEles = document.querySelectorAll('li') for (var i = 0; i < liEles.length; i++) { iEles[i].addEventListener('click', function () { alert(this.innerHTML + '收到外买') }) } } /** * 每个同学收外买的事情,交给ul代理接收 */ function test2(){ var ulEle = document.querySelector('ul') ulEle.addEventListener('click',function(e){ e = e || window.event // 事件对象 var target = e.target || e.srcElement // 事件目标对象 alert(target.innerHTML + '代收到外买成功') }) } test2()
案例:todoList3.0 事件委托改造事件
<div class="container">
<input type="text" placeholder="请输入内容" /><button>确定</button>
<ul>
</ul>
</div>
var arr = ['html','css'] // 数据
/*
数据操作-实现显示列表
遍历数组,拼接字符串,将字符串作用内容设置给显示元素
点击确定按钮,获取输入框内容,添加数组
*/
function showList() {
var liArr = arr.map(function (item,index) {
return `<li data-index="${index}">${item}</li>`
})
var liStr = liArr.join('')
var ulEle = document.querySelector('ul')
ulEle.innerHTML = liStr
}
// 删除元素
function onDelete(){
// 删除事件操作委托给ul上级元素处理
var ulEle = document.querySelector('ul')
ulEle.addEventListener('click',function(e){
e = e || window.event
var target = e.target || e.srcElement // 事件目标对象
var index = target.dataset.index
arr.splice(index,1)
showList()
})
}
//添加元素
var btn = document.querySelector('button')
btn.onclick = function () {
var inputEle = document.querySelector('input')
var inputValue = inputEle.value
arr.push(inputValue)
inputEle.value = '' // 清空输入框
showList() // 刷新
}
showList() // 初始化执行
onDelete() // 初始化执行
案例二:
选项卡 事件委托改造事件2.0
<div class="container">
<div class="active">选项1</div>
<div>选项2</div>
<div>选项3</div>
</div>
/*
1. 确定选中的选项
1.1 this关键字
2. 清除原来选中效果
for(var i = 0; i < div.length; i++){
div[i].className = ''
}
3. 设置当前选项选中效果
this.className = 'active'
*/
var containerEle = document.querySelector('.container')
containerEle.addEventListener('click',function(e){
e = e || window.event // 事件对象
// 1. 确定选中的选项
var target = e.target || e.srcElement // 事件目标对象
//2. 清除原来选中效果
clearActive()
// 3. 设置当前选项选中效果
target.className = 'active'
})
/**
* 清除所有选项选中效果
*/
function clearActive() {
// 获取所有选项
var divEles = document.querySelectorAll('.container>div')
// 循环遍历所有选项,清除样式
for (var i = 0; i < divEles.length; i++) {
divEles[i].className = ''
}
}
* {
padding: 0;
margin: 0;
}
.container {
width: 400px;
margin: 100px;
display: flex;
align-items: center;
}
.container div {
flex: 1;
height: 50px;
background-color: skyblue;
text-align: center;
line-height: 50px;
border-right: 1px solid pink;
}
.container div:hover {
cursor: pointer;
}
.container .active {
background-color: rgb(223, 57, 16);
}
选项卡完善3.0
<div class="container">
<ul>
<li class="active">选项1</li>
<li>选项2</li>
<li>选项3</li>
</ul>
<ol>
<li class="on">区域1</li>
<li>区域2</li>
<li>区域3</li>
</ol>
</div>
var ulLis = document.querySelectorAll('ul>li')
var olLis = document.querySelectorAll('ol>li')
// 循环给所有选项绑定事件
for (var i = 0; i < ulLis.length; i++) {
ulLis[i].setAttribute('index',i) // 动态添加索引号
ulLis[i].addEventListener('click',function(){
// 1. 清除所有样式
clearStyle()
// 2. 当前选设置样式
this.className = 'active'
// 3. 确定当前选项对应的区域
var index = this.getAttribute('index')
olLis[index].className = 'on'
})
}
/* 清除样式*/
function clearStyle(){
for (var i = 0; i < ulLis.length; i++) {
ulLis[i].className = '' // 清除选项样式
olLis[i].className = '' //清除区域样式
}
}
* {
padding: 0;
margin: 0;
}
ul,
li {
list-style: none;
}
.container {
width: 400px;
margin: 100px;
}
.container ul {
height: 50px;
background-color: skyblue;
text-align: center;
line-height: 50px;
display: flex;
}
.container ul li {
flex: 1;
border-right: 1px solid pink;
}
.container ul li:hover {
cursor: pointer;
}
.container ol {
position: relative;
height: 300px;
background-color: blueviolet;
}
.container ol li {
position: absolute;
top: 0;
left: 0;
text-align: center;
width: 400px;
line-height: 300px;
display: none;
}
.container ul .active {
background-color: rgb(223, 57, 16);
}
.container ol .on {
display: block;
}
默认行为
默认行为
a标签
- 默认行为:href实现链接跳转
form表单
- 默认行为:执行action的url页面跳转
右键事件 contextmenu
- 默认行为:右键时弹出菜单
阻止默认行为
e.preventDefault()
<a href="">按钮</a>
<a href="javascript:void(0)" >确定</a>
<div>
<form>
<input type="text" placeholder="请输入内容" name="message"><br>
<input type="submit" value="提交">
</form>
</div>
function test1() {
var aEle = document.querySelector('a')
aEle.addEventListener('click', function (e) {
e = e || window.event // 事件对象
e.preventDefault() // 阻止a标签默认行为
alert('事件监听a标签')
})
}
function test2(){
var formEle = document.querySelector('form')
formEle.addEventListener('submit',function(e){
e = e || window.event // 事件对象
e.preventDefault() // 阻止a标签默认行为
alert('表单提交事件')
})
}
test2()
function test3(){
document.addEventListener('contextmenu',function(e){
e = e || window.event // 事件对象
e.preventDefault() // 阻止a标签默认行为
alert('右键事件')
})
}
test3()
扩展
<a href="javascript:void(0)" >确定</a>
函数补充
自调用函数
函数定义和调用写在一块
封装代码,封装私有变量,独立于全局变量
(function(){
//函数体
})()
arguments 对象
- 表示函数所有实参的集合
- 函数体中直接使用
- 类数组
- 实现函数可变参数(动态传参),可以不用定形参
function fun(){
// arguments 类数组形式存在
console.log(arguments) //显示类数组接收的实参 10,20,30
for(var i = 0; i < arguments.length; i++){
console.log(arguments[i]) //分别显示10 20 30
}
}
fun(10,20,30)
// 计算任意数总和
function sum(){
var s = 0
for(var i = 0; i < arguments.length; i++){
s = s + arguments[i]
}
return s
}
var s = sum(10,20,30,50)
alert(s)
this关键字
this表示当前对象
根据不同场景下,this表示不同的对象
事件处理函数中的this
- this -> 事件源
<button>确定</button>
function test1() { var btn = document.querySelector('button') btn.addEventListener('click', function () { // this->事件源->button按钮 console.log('this : ', this) }) }
对象方法中的this
-
this -> 当前对象
-
调用该方法引用变量
var obj = { name:'jack', say: function(){ console.log(this.name + '说话, say方法调用'); console.log('对象Object方法中this -> ',this) } } obj.say()
普通函数中/定时器中/自调用函数中的this
- this -> widow对象
购物车案例2.0 数据操作
<table class="containter">
<!-- 动态渲染 -->
</table>
var productList = [
{number:1001,name:'javascript高级',url:'./image/shoppingBg_03.jpg',price:88.98,num:2},
{number:1002,name:'css高级编程',url:'./image/shoppingBg_06.jpg',price:58.58,num:1},
{number:1003,name:'html高级编程',url:'./image/shoppingBg_03.jpg',price:48.58,num:1},
]
/*
显示商品列表
*/
function showProductList(){
var str = `<tr>
<th>商品图片</th>
<th>商品信息</th>
<th>单价</th>
<th>数量</th>
<th width="100px">总价</th>
<th>操作</th>
</tr>`
var trArr = productList.map(function(item,index){
return `<tr>
<td><img src="${item.url}" alt="图片1" /></td>
<td>${item.name}</td>
<td>¥${item.price}</td>
<td>
<input type="button" value="-" name="minus" /><input type="text" value="${item.num}" name="amount"/><input type="button" value="+" name="plus" />
</td>
<td>¥${item.price * item.num}</td>
<td>移入收藏<br />删除</td>
</tr>`
})
str = str + trArr.join('')
var tableEle = document.querySelector('table')
tableEle.innerHTML = str
}
showProductList()
* {
padding: 0;
margin: 0;
}
.containter {
width: 1200px;
margin: 100px auto;
}
.containter tr {
line-height: 40px;
text-align: center;
}
.containter tr,
th,
td {
border-bottom: 1px dotted gray;
}
.containter tr input {
width: 20px;
text-align: center;
}