知识补充- let 和 const
作用:
在程序设计时,一些数据永远不会被更改,优先用const(不小心发现被修改,程序就报错,有利于解决)
能用const就用const,不能用const就用let
永远不用var
区别:
1.普通类型的数据 直接写 = 表示修改数据 报错
2.复杂类型的数据 直接写 = 表示修改 报错 (如果arr.push不会报错。等于号才报错)
3.复杂类型的数据 写= 相当于重新开辟新空间 报错
总结:
1.cosnt和let一样都可以声明变量
2.const 声明的变量不能修改 let 可以随意修改
3.判断是不是修改 直接看有没有 写= 或者自增自减
4.能用const 就不用let
DOM-事件高级
事件对象
本质:
1.事件对象也是一个对象,这个对象装的是当我们触发事件时的相关信息
2.例如:点击事件中,时间存放了鼠标点在哪个位置等信息
语法:
常用属性
1.type
获取当前事件类型
2.clientX、clientY
获取光标相对于浏览器窗口左上角位置(元素移动还是参照浏览器)
3.offsetX、offsetY
获取光标相对于当前DOM元素左上角位置(参照自身元素位置)
4.key
用户按下的键盘值
移动案例
<script>
let img = document.querySelector(`img`)
document.addEventListener(`mousemove`,function(e){
const left = e.clientX
const top = e.clientY
img.style.left = left+`px`
img.style.top = top+`px`
})
</script>
思路:
1.主要在于client属性获取的是X,Y数字
2.联想定位letf,top
3.把属性值给图片的定位值
回车案例
<script>
let are = document.querySelector(`.are`)
let btn = document.querySelector(`button`)
let ul = document.querySelector(`ul`)
btn.addEventListener(`click`,function(){
if(are.value.trim()===``){
return //返回不再执行
}
if(are.value.length!==0){
let html = `<li>${are.value}</li>`
ul.innerHTML += html
are.value=``
}
})
document.addEventListener(`keydown`,function(e){
if(e.key===`Enter`){
btn.click()
}
e.preventDefault()//阻止浏览器标签默认行为 阻止a跳转行为
})
</script>
</body>
</html>
思路:
1.主要在回车发布,给整个body添加按下事件
2.判断当只有e.key是回车时,才执行代码 要加``
3.两个额外知识点要注意
事件流(了解)
本质:事件流值的是事件执行过程的流动
代码举例:
<body>
<div class="a">爷
<div class="b">爸
<div class="c">儿</div>
</div>
</div>
<script>
const a = document.querySelector(`.a`)
a.addEventListener(`click`,function(){
console.log(a);
},false)//默认,冒泡阶段
const b = document.querySelector(`.b`)
b.addEventListener(`click`,function(){
console.log(b);
},true)// 捕获阶段
const c = document.querySelector(`.c`)
c.addEventListener(`click`,function(){
console.log(c);
},false)
</script>
</body>
理解:
1.本质这里就是给多个嵌套的父子结构绑定点击事件,如果点击了子元素,就产生了事件流动
2.事件流动分为两个阶段(1.捕获阶段;2.冒泡阶段(默认))
3.就像跳水一样 :
4.可以修改触发事件,选择捕获还是冒泡(默认是冒泡)
addEventlistener(事件类型,函数,捕获还是冒泡(默认是false,可以省略))
addEventlistener ("click",function(){},true)这就是修改为捕获阶段
总结:了解特点,之后开发过程默认使用冒泡阶段。
小案例:点击上面嵌套盒子,点谁显示谁颜色
<script>
let p = document.querySelector(`p`)
const a = document.querySelector(`.a`)
a.addEventListener(`click`,function(){
p.style.backgroundColor = `red`
},true)
const b = document.querySelector(`.b`)
b.addEventListener(`click`,function(){
p.style.backgroundColor = `pink`
},true)
const c = document.querySelector(`.c`)
c.addEventListener(`click`,function(){
p.style.backgroundColor = `aqua`
},true)
</script>
问题延伸:如果换成数字相加,发现此做法不行,不能点谁加谁,数字会叠加父元素数字,还是会触发父元素。因为事件时间捕获和冒泡阶段。
阻止冒泡(解决方式)
本质:默认存在的冒泡,会导致事件影响到父元素
作用:若要把事件执行限制在当前元素内,就要阻止事件流动
语法:
问题延伸解决方案:
<script>
let p = document.querySelector(`p`)
const a = document.querySelector(`.a`)
a.addEventListener(`click`,function(e){
p.style.backgroundColor = `red`
p.innerText = +(p.innerText)+1
e.stopPropagation()
console.log(a);
})
const b = document.querySelector(`.b`)
b.addEventListener(`click`,function(e){
p.style.backgroundColor = `pink`
p.innerText = +(p.innerText)+10
e.stopPropagation()
console.log(b);
})
const c = document.querySelector(`.c`)
c.addEventListener(`click`,function(e){
p.style.backgroundColor = `aqua`
p.innerText = +(p.innerText)+100
// 阻止事件流动
e.stopPropagation()
</script>
阻止默认行为
本质:让标签默认行为不执行,如a标签跳转
语法:
代码举例:
<script>
const form = document.querySelector(`form`)
const button = document.querySelector(`button`)
const a = document.querySelector(`a`)
a.addEventListener(`click`,function(e){
e.preventDefault()//阻止默认行为 跳转
})
form.addEventListener(`submit`,function(e){
e.preventDefault()//不让页面刷新
})
button.addEventListener(`click`,function(e){
e.preventDefault()//不让页面刷新
})
</script>
右键重新设置案例
<script>
let ul = document.querySelector(`ul`)
document.addEventListener(`contextmenu`,function(e){
e.preventDefault()
ul.style.display = `block`
let left = e.clientX+`px`
let top = e.clientY+`px`
ul.style.left = left
ul.style.top = top
})
document.addEventListener(`click`,function(){
ul.style.display = `none`
})
</script>
思路:
1.首先写静态结构,写出一个想要的结构
2.给body添加右键事件,阻止右键默认行为 也就是右键弹出的页面
3.把想要的结构用之前的跟随移动案例 把新的结构给右键点击事件
4.给body添加点击事件,点击就消息页面
事件委托
本质:事件委托是利用事件流的特征(捕获冒泡),解决开发需求
作用:给父元素加事件,之前都是给每个子元素遍历绑定,更加高效。
语法:事件对象.target 表示当前事件触发的是哪个标签(触发时的最底层标签,依据事件流特点!!!)
之前获取LI点击事件做法:
<script>
let li = document.querySelectorAll(`li`)
for (let index = 0; index < li.length; index++) {
li[index].addEventListener(`click`,function(){
li[index].style.backgroundColor=`red`
})
}
</script>
现在获取做法:
<script>
let ul = document.querySelector(`ul`)
ul.addEventListener(`click`,function(e){
//事件委托,把本来要遍历li绑定的事件 绑定父元素上 实现
//点哪个元素,就获取哪个(最底层)
e.target.style.backgroundColor=`red`
//不过这样做,可能获取ul,li,a 不够完美
})
</script>
优化做法:(只要点击li)
<script>
let ul = document.querySelector(`ul`)
if(e.target.nodeName===`LI`){
e.target.style.backgroundColor=`red`
}
})
</script>
总结:
1.把事件委托给父元素
2.用target触发
3.如果想要只点击LI才触发 用判断配合nodeName(获取标签,大写)
综合案例
<script>
let arr = [
// {id:`1`,uname:`黄某`,age:`18`,gender:`男`,salary:`200`,city:`广州`}
]
let name = document.querySelector(`.uname`)
let age = document.querySelector(`.age`)
let sex = document.querySelector(`.gender`)
let money = document.querySelector(`.salary`)
let city = document.querySelector(`.city`)
let btn = document.querySelector(`.add`)
let tbody = document.querySelector(`tbody`)
rander()
btn.addEventListener(`click`,function(){
const date = {
id:Date.now(),
uname:name.value,
age:age.value,
gender:sex.value,
salary:money.value,
city:city.value
}
arr.push(date)
rander()
})
tbody.addEventListener(`click`,function(event){
if(event.target.nodeName===`A`){
const index = event.target.dataset.index
arr.splice(index,1)
rander()
}
})
function rander() {
let html = ``
for (let index = 0; index < arr.length; index++) {
html += `<tr>
<td>${arr[index].id}</td>
<td>${arr[index].uname}</td>
<td>${arr[index].age}</td>
<td>${arr[index].gender}</td>
<td>${arr[index].salary}</td>
<td>${arr[index].city}</td>
<td>
<a data-index="${index}" href="javascript:" class="del">删除</a>
</td>
</tr>`
}
return tbody.innerHTML =html
}
</script>
解题思路:
1.创建一个对象数组,存放数据(数据驱动视图!!!)
2.封装渲染函数,提取对象数组中的值
3.点击了发布,把插入内容整合成一个对象,把对象插入外边大的数组对象中,放入封装好的渲染函数。
4.点击删除,运用事件委托,给父元素声明点击事件,用e.target判断只有标签A才可以点击。
5.如何删除,思考要是存在下标,那我点谁就获取哪个下标然后可以删除谁。
6.在渲染函数的删除标签上添加data-index=“${index}”,dir一下e.target发现在这个对象中的dataset有一个下标,和数组一样。点击谁就获取递增的下标
7.将下标值赋予一个变量,用splice(index,1)点击就删除
总结:多做多思考,尽量通过思考而不是肌肉记忆