其他事件
页面加载事件
- 加载外部资源(如图片,外联css和js等)加载完毕时触发的事件
- 有时候需要等页面资源全部处理完之后做一些事情
- 老代码喜欢把script写在head中,这时候直接找dom元素找不到
- 事件名:load
- 监听页面所有资源加载完毕:给windows添加load事件
//等待页面所有资源加载完毕,就去执行回调函数
window.addEventListener('load',function(){
const btn=document.querySelector('button')
btn.addEventListener('click',function(){
alert(11)
})
})
img.addEventListener('load',function(){
//等待图片加载完毕 再去执行里面的代码
})
注意:不光可以监听整个页面资源加载完毕,也可以针对某个资源绑定load事件
- 当初始的 HTML文档被完全加载和解析完成之后,DOMContentLoaded事件被触发,而无需等待样式表,图像等完全加载
- 事件名:DOMContentLoaded
- 监听页面DOM加载完毕:给DOMContentLoaded事件
document.addEventListener('DOMContentLoaded',function(){
})
元素滚动事件
- 滚动条在滚动的时候持续触发的事件
- 很多网页需要检测用户把页面滚动到某个区域后做一些处理,比如固定导航栏,比如返回顶部
- 事件名:scroll
- 监听整个页面滚动:
window.addEventListener('scroll',function(){
console.log('滚了')
})
- 页面出现滚动条之后才有用
- 给window或document添加scroll事件
- 监听某个元素的内部滚动直接给某个元素添加即可
获取位置
scrollLeft和scrollTop(属性)
- 获取被卷去的大小
- 获取元素内容往左,往上滚出去看不到的距离
- 这两个值是可读写的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
padding: 100px;
height: 3000px;
}
div {
display: none;
overflow: scroll;
margin: 100px;
width: 200px;
height: 200px;
border: 1px solid #000;
}
</style>
</head>
<body>
<!-- <button>点击</button> -->
<div>
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
我里面有很多文字
<script>
document.documentElement.scrollTop=800//可改写
const div=document.querySelector('div')
window.addEventListener('scroll',function(){
const n=document.documentElement.scrollTop//返回数字型 不带单位
if(n>=100){
div.style.display='block'
}
else {
div.style.display='none'
}
})
// const div=document.querySelector('div')
// div.addEventListener('scroll',function(){
// console.log(111)
// console.log(div.scrollTop)
// })
// </script>
</body>
</html>
小tip:
- document.body可获得body标签
- document.documentElement可获得html标签
页面滚动显示隐藏侧边栏
//获取元素
const elevator=document.querySelector('.xtx-elevator')
//1.当页面滚动大于300px,就显示电梯导航
//2.给页面添加滚动事件
window.addEventListener('scroll',function(){
//被卷去的头部大于300
const n=document.documentElement.scrollTop
// if(n>=300){
// elevator.style.opacity=1
// }
// else {
// elevator.style.opacity=0
// }
elevator.style.opacity=n>300?1:0
})
//点击返回页面顶部
const backTop=document.querySelector('#backTop')
backTop.addEventListener('click',function(){
//可读写
// document.documentElement.scrollTop=0
window.scrollTo(0,0)
})
tip:
页面滚动事件-滚动到指定的坐标
- scrollTo()方法可把内容滚动到指定的坐标
- 语法:元素.scrollTo(x,y)
//让页面滚动到y轴1000px的位置 window.scrollTo(0,1000)
页面尺寸事件
会在窗口尺寸改变的时候触发事件:
resize
//resize浏览器窗口大小发生变化的时候触发的事件
window.addEventListener('resize',function(){
console.log(1)
})
获取元素宽高
获取宽高:
- 获取元素的可见部分宽高(不包含边框,margin,滚动条等,包含padding)
- clientWith和clientHeight
const div=document.querySelector('div')
console.log(div.clientWidth)
//resize浏览器窗口大小发生变化的时候触发的事件
window.addEventListener('resize',function(){
console.log(1)
})
元素的尺寸和位置
使用场景:
- 前面案例滚动多少距离,都是我们自己算的,最好是页面滚动到某个元素,就可以做某些事。‘
- 简单说,就是通过js的方式,得到元素在页面中的位置
- 这样我们就可以做,页面滚动到这个位置,就可以做某些操作,省去计算了
获取宽高:
- 获取元素的自身宽高,包含元素自身设置的宽高、padding,border
- offsetWidth和offsetHeight
- 获取出来的是数值,方便计算
- 注意:获取的是可视宽高,如果盒子是隐藏的,获取的结果是0
获取位置:
- 获取元素距离自己定位父级元素的左,上距离(最近一级带有定位的祖先元素)
- offsetLeft和offsetTop 注意是只读属性
const div=document.querySelector('div')
console.log(div.offsetLeft)
仿京东固定导航案例
需求:当页面滚动到秒杀模块,导航栏自动滑入,否则滑出
分析:
- 用到页面滚动事件
- 检测页面滚动大于等于秒杀模块的位置则滑入,否则滑出
- 主要移动的是秒杀模块的顶部位置
const sk=document.querySelector('.sk')
const header=document.querySelector('.header')
// 1.页面滚动事件
window.addEventListener('scroll',function(){
//当页面滚动到秒杀模块时,就改变头部的top值
//页面被卷去的头部>=秒杀模块的位置offsetTop
const n=document.documentElement.scrollTop
if(n>=sk.offsetTop){
header.style.top=0
}
else {
header.style.top='-80px'
}
})
实现哔哩哔哩点击小滑块移动效果
需求:当点击链接,下面红色滑块跟着移动
分析:
- 用到时间委托
- 点击链接得到当前元素的offsetLeft值
- 修改line颜色块的transform值=点击链接的offsetLeft
- 添加过渡效果
// 1. 事件委托的方法 获取父元素 tabs-list
const list = document.querySelector('.tabs-list')
const line = document.querySelector('.line')
// 2. 注册点击事件
list.addEventListener('click', function (e) {
// 只有点击了A 才有触发效果
if (e.target.tagName === 'A') {
// console.log(11)
// 当前元素是谁 ? e.target
// 得到当前点击元素的位置
// console.log(e.target.offsetLeft)
// line.style.transform = 'translateX(100px)'
// 把我们点击的a链接盒子的位置 然后移动
line.style.transform = `translateX(${e.target.offsetLeft}px)`
}
})
获取位置
element.getBoundingClientRect()
方法返回元素的大小及其相对于视口的位置
区别于offsetTop:offsetTop是相对于整个页面来说的,而getVBoundingClientRect()是相对于视口来说,如果滚动整个界面,则位置坐标就会改变
总结
属性 | 作用 | 说明 |
---|---|---|
scrollLeft和scrollTop | 被卷去的头部和左侧 | 配合页面滚动来写,可读写 |
clientWidth和clientHeight | 获得元素宽高 | 不包含border,margin,滚动条用于js获取元素的大小,只读属性 |
offsetWidth和offsetHeight | 获取元素宽度和高度 | 包含border,padding,滚动条等,只读 |
offsetLeft和offsetTop | 获取元素距离自己定位父级元素的左,上距离 | 获取元素位置的时候使用,只读属性 |
电梯导航综合案例
需求:点击不同的模块,页面可以自动跳转不同的位置
模块分析:
- 页面滚动到对应的位置,导航显示,否则隐藏模块
- 点击导航对应小模块,页面会跳到对应大模块的位置
- 页面滚动到对应位置,电梯导航对应模块自动发生变化
- 显示隐藏电梯盒子和返回顶部已经完成,可以放到自执行函数里面,防止变量污染
- 电梯模块单独放到自执行函数里面
模块分析2:点击每个模块,页面自动滚动到对应模块,使用事件委托方法更加简单
- 点击小模块,当前添加active类名
- 解决初次获取不到active报错的问题
解决方案:
- 不能直接获取这个类,然后移除,这样会报错
- 先获取这个类,然后加个判断:如果有这个类,就移除,如果没有,返回null,就不执行移除,就不报错了
点击每个模块,页面跳转至对应大盒子位置
核心思想:
- 把对应大盒子的offsetTop'给document.documentElement.scrollTop
- 我们发现小盒子li的自定义属性里面值跟大盒子后面一致
- 利用模板字符串 把点击的自定义属性给大盒子 就找到对应的大盒子了
- 然后拿到这个大盒子的offsetTop值给·document.documentElement.scrollTop即可·
模块分析3:页面滚动到大盒子位置,电梯导航小盒子对应模块自动处于选中状态
- 当页面滚动了,先移除所有小li里面a的状态 active防止有多个active
- 因为页面滚动需要不断获取大盒子的位置,所以需要把所有的大盒子都获取过来
- 开始进行滚动判断
- 如果页面滚动大于大盒子的offsetTop 并且小于下一个大盒子的offsetTop就把对应的小盒子拿出来添加类
- 以此类推
- 最后一个,如果大于等于最新专题模块,就选出最后一个对应小盒子(更精确)
// 第一模块 页面滑动可以显示和隐藏
(function(){
//获取元素
const entry=document.querySelector('.xtx_entry')
const elevator=document.querySelector('.xtx-elevator')
//1.当页面滚动大于300px,就显示电梯导航
//2.给页面添加滚动事件
window.addEventListener('scroll',function(){
//被卷去的头部大于300
const n=document.documentElement.scrollTop
// if(n>=300){
// elevator.style.opacity=1
// }
// else {
// elevator.style.opacity=0
// }
elevator.style.opacity=n>entry.offsetTop?1:0
})
//点击返回页面顶部
const backTop=document.querySelector('#backTop')
backTop.addEventListener('click',function(){
//可读写
// document.documentElement.scrollTop=0
window.scrollTo(0,0)
})
})();
//第二第三到放到另外一个执行函数里面
(function(){
const list=document.querySelector('.xtx-elevator-list')
list.addEventListener('click',function(e){
//console.log(11)
if(e.target.tagName==='A'&&e.target.dataset.name){
//排他思想
//先移除原来的类active
//先获取这个类名
//若找不到该类名,就返回空null
const old=document.querySelector('.xtx-elevator-list .active')
//判断
if(old){
old.classList.remove('active')
}
//当前元素添加active
e.target.classList.add('active')
// 获得自定义属性
// console.log(e.target.dataset.name)
// 根据小盒子的自定义属性值去选择 对应的大盒子
// console.log(document.querySelector(`.xtx_goods_${e.target.dataset.name}`).offsetTop)
const top=document.querySelector(`.xtx_goods_${e.target.dataset.name}`).offsetTop
// 让页面滚动到对应的位置
document.documentElement.scrollTop=top
}
})
// 3.页面滚动事件 可以根据大盒子选 添加active类
window.addEventListener('scroll',function(){
//先获取这个类名
//若找不到该类名,就返回空null
const old=document.querySelector('.xtx-elevator-list .active')
//判断
if(old){
old.classList.remove('active')
}
// 判断当前页面滑动的位置 选择小盒子
//获取四个大盒子
const news=document.querySelector('.xtx_goods_new')
const popular=document.querySelector('.xtx_goods_popular')
const brand=document.querySelector('.xtx_goods_brand')
const topic=document.querySelector('.xtx_goods_topic')
const n=document.documentElement.scrollTop
if(n>=news.offsetTop&&n<popular.offsetTop){
//选择第一个小盒子
document.querySelector('[data-name=new]').classList.add('active')
}else if(n>=popular.offsetTop&&n<brand.offsetTop){
document.querySelector('[data-name=popular]').classList.add('active')
}else if(n>=brand.offsetTop&&n<topic.offsetTop){
document.querySelector('[data-name=brand]').classList.add('active')
}else if(n>=topic.offsetTop){
document.querySelector('[data-name=topic]').classList.add('active')
}
})
})();
tip:
html {
scroll-behavior: smooth;//让滚动条添加滑动效果
}
日期对象
- 日期对象:用来表示时间的对象
- 作用:可以得到当前系统的时间
实例化
- 在代码中发现了new关键字时,一般将这个操作称为实例化
- 创建一个事件对象并获取时间
- 获取当前时间 const date=new Date()
- 获得指定时间 const date=new Date('2008-8-8')
//实例化 new
// const date=new Date()
// console.log(date)
// 获得指定时间
const date=new Date('2008-8-8 08:30:00')
console.log(date)
事件对象方法
使用场景:因为日期对象返回的数据我们不能直接使用,所以需要转换为实际开发中常用格式
方法 | 作用 | 说明 |
---|---|---|
getFullYear() | 获得年份 | 获取四位年份 |
getMonth() | 获得月份 | 取值为0~11 |
getDate() | 获取月份中的每一天 | 不同月份取值也不相同 |
getDay() | 获取星期 | 取值为0~6 |
getHours() | 获取小时 | 取值为0~23 |
getMinutes() | 获取分钟 | 取值为0~59 |
getSeconds() | 获取秒 | 取值为0~59 |
页面显示时间
需求:将当前时间以:YYYY-MM-DD HH:mm形式显示在页面 2008-08-08 08:08
分析:
- 调用日期对象方法进行转换
- 记得数字要补0
const div=document.querySelector('div')
function getMydate(){
const date=new Date()
let h=date.getHours()
let m=date.getMinutes()
let s=date.getSeconds()
h=h<10?'0'+h:h
m=m<10?'0'+m:m
s=s<10?'0'+s:s
return `今天是:${date.getFullYear()}年${date.getMonth()+1}月${date.getDate()}号 ${h}:${m}:${s}`
}
div.innerHTML=getMydate()//确保页面刷新之后立刻就出现时间
setInterval(function(){
div.innerHTML=getMydate()
},1000)
时间的另外一种写法
//得到日期对象
const date=new Date()
div.innerHTML=date.toLocaleDateString()// 2024/4/1
div.innerHTML=date.toLocaleString()//2024/4/1 21:00:15
div.innerHTML=date.toLocaleTimeString()//21:01:16
时间戳
- 使用场景:如果计算倒计时效果,前面方法无法直接计算,需要借助于时间戳完成
- 什么是时间戳:是指1970年01月01日00时00分00秒起至现在的毫秒数,它是一种特殊的计量时间的方式
- 算法:
- 将来的时间戳 -现在的时间戳=剩余时间毫秒数
- 剩余时间毫秒数 转换为剩余时间的年月日时分秒就是倒计时时间
- 比如 将来时间戳 2000ms - 现在时间戳1000ms=1000ms
- 1000ms转换为就是0小时0分1秒
三种方式获取时间戳:
1、使用getTime()方法
2、简写 +new Date() (无需实例化)
3、使用Date.now() (无需实例化)
但是只能得到当前的时间戳,而前面两种可以返回指定时间的时间戳
// 1.getTime()
const date=new Date()
console.log(date.getTime())
// 2.+new Date()
console.log(+new Date())
// 3.Date.now()
console.log(Date.now())
console.log(+new Date())
console.log('---------------')
//返回指定时间
console.log(+new Date('2022-4-1 18:30:00'))
返回星期
const arr=['星期天','星期一','星期二','星期三','星期四','星期五','星期六']
console.log(arr[new Date().getDay()])
毕业倒计时
需求:计算到下课还有多少时间
分析:
- 用将来的时间减去现在的时间就是剩余的时间
- 核心:使用将来的时间戳减去现在的时间戳
- 把剩余的时间转换为天 时 分 秒
注意:
1.通过时间戳得到的时毫秒,需要转换为秒再计算
2.转换公式:
d=parseInt(总秒数/60/60/24);//计算天数
h=parseInt(总秒数/60/60%24);//计算小时
m=parseInt(总秒数/60%60);//计算分数
s=parseInt(总秒数%60);//计算秒数
// 1.自定义一个随机颜色函数
function getRandomcolor(flag=true){
if(flag){
let str='#'
let arr=['0','1' ,'2','3','4','5','6','7','8','9','a','b','c','d','e','f']
//利用for循环循环六次,累加到str里面
for(let i=1;i<=6;i++){
let Random=Math.floor(Math.random()*arr.length)
str+=arr[Random]
}
return str
}
else{
let r=Math.floor(Math.random()*256)
let g=Math.floor(Math.random()*256)
let b=Math.floor(Math.random()*256)
return `rgb(${r},${g},${b})`
}
}
const countdown=document.querySelector('.countdown')
countdown.style.backgroundColor=getRandomcolor(true)
//函数封装 getCountTime
function getCountTime(){
const next=document.querySelector('.next')
function gettime(){
let date=new Date()
return `今天是${date.getFullYear()}年${date.getMonth()+1}月${date.getDate()}日`
}
next.innerHTML=gettime()
// 1.得到当前的时间戳
const now=+new Date()
// 2.得到将来的时间戳
const last=+new Date('2024-4-1 23:00:00')
// 3.得到剩余的时间戳 count 记得转化为秒数
const count=(last-now)/1000
// 转换为时分秒
let d=parseInt(count/60/60/24)
let h=parseInt(count/60/60%24)//计算小时
let m=parseInt(count/60%60)//计算分数
let s=parseInt(count%60)//计算秒数
h=h<10?'0'+h:h
m=m<10?'0'+m:m
s=s<10?'0'+s:s
// console.log(d,h,m,s)
// 5.把时分秒写到对应的盒子里面
const hour=document.querySelector('#hour')
const minutes=document.querySelector('#minutes')
const second=document.querySelector('#second')
hour.innerHTML=h
minutes.innerHTML=m
second.innerHTML=s
}
getCountTime()
// 开启定时器
setInterval(getCountTime,1000)
节点操作
DOM节点
DOM树里的每一个内容都称之为节点
节点类型
元素节点
- 所有的标签 比如body、div
- html是根节点
属性节点
- 所有的属性 比如 href
文本节点
- 所有的文本
其他
查找节点
关闭二维码案例:
- 点击关闭按钮,关闭的是二维码的盒子,还要获取二维码盒子
- 关闭按钮和二维码之间是父子关系
- 所以我们可以这么做,直接关闭他的爸爸,就无需获取二维码元素了
节点关系:针对的找亲戚返回的都是对象
-
父节点
parentNode属性
返回最近一级的父节点 找不到返回null
子元素.parentNode
const close=document.querySelectorAll('.close')
for(let i=0;i<close.length;i++){
close[i].addEventListener('click',function(){
this.parentNode.style.display='none'//按钮的父元素即为盒子,其父元素不再显示
})
}
-
子节点
childNodes
获得所有的子节点,包括文本节点(空格,换行)、注释节点等
children 属性 (重点)
- 仅获得所有元素的节点
- 返回的还是一个伪数组
父元素.children
const ul=document.querySelector('ul')
console.log(ul.children)//得到伪数组 选择的是亲儿子
-
兄弟节点
兄弟关系查找
1.下一个兄弟节点
nextElementSibling属性
2.上一个兄弟节点
previousElementSibling属性
console.log(li2.previousElementSibling)//上一个兄弟
console.log(li2.nextElementSibling)//下一个兄弟
增加节点
很多情况下,我们需要在页面中增加元素
比如:点击发布按钮,可以新增一条信息
一般情况下,我们新增节点,按照如下操作:
- 创建一个新的节点
- 把创建的新的节点放入到指定的元素内部
追加节点
- 要想在页面中看到,还得插入到某个父元素中
- 插入到父元素的最后一个子元素:
父元素.appendChild(插入的元素)
document.body.appendChild(div)
在ul里末尾添加li元素
<body>
<ul></ul>
<script>
const ul=document.querySelector('ul')
const li=document.createElement('li')
li.innerHTML='我是li'
ul.appendChild(li)
</script>
</body>
- 插入到父元素的某个子元素的前面
//插入到某个子元素的前面
父元素.insertBefore(要插入的元素,在哪个元素前面)
ul.insertBefore(li,ul.children[0])//放在数组第一个元素前面
创建节点
即创建出一个新的网页元素,再添加到网页内,一般先创建节点,然后插入节点
创建元素节点方法:
const div =document.createElement('div')
学成在线案例渲染
需求:按照数据渲染界面
分析:
- 准备好空的ul结构
- 根据数据的个数,创建一个新的空li
- li里面添加img标题等
- 追加给ul
// 1. 重构
let data = [
{
src: 'images/course01.png',
title: 'Think PHP 5.0 博客系统实战项目演练',
num: 1125
},
{
src: 'images/course02.png',
title: 'Android 网络动态图片加载实战',
num: 357
},
{
src: 'images/course03.png',
title: 'Angular2 大前端商城实战项目演练',
num: 22250
},
{
src: 'images/course04.png',
title: 'Android APP 实战项目演练',
num: 389
},
{
src: 'images/course05.png',
title: 'UGUI 源码深度分析案例',
num: 124
},
{
src: 'images/course06.png',
title: 'Kami2首页界面切换效果实战演练',
num: 432
},
{
src: 'images/course07.png',
title: 'UNITY 从入门到精通实战案例',
num: 888
},
{
src: 'images/course08.png',
title: 'Cocos 深度学习你不会错过的实战',
num: 590
},
]
const ul = document.querySelector('.box-bd ul')
// 1. 根据数据的个数,创建 对应的小li
for (let i = 0; i < data.length; i++) {
// 2. 创建新的小li
const li = document.createElement('li')
// 把内容给li 属性之间记得保留空格
li.innerHTML = `
<a href="#">
<img src=${data[i].src} alt="">
<h4>
${data[i].title}
</h4>
<div class="info">
<span>高级</span> • <span>${data[i].num}</span>人在学习
</div>
</a>
`
// 3. ul追加小li
ul.appendChild(li)
}
特殊情况下,我们新增节点,按照如下操作:
- 复制一个原有的节点
- 把复制的节点放入到指定的元素内部
克隆节点
//克隆一个已有的元素节点
元素.cloneNode(布尔值)
cloneNode会克隆出一个跟原标签一样的元素,括号内传入布尔值
- 若为true,则代表克隆时会包含后代节点一起克隆,深克隆
- 若为false,则代表克隆时不包含后代节点,只克隆标签,不克隆内容,浅克隆
- 默认为false
//克隆一个节点并追加到ul元素的最后面
const ul=document.querySelector('ul')
//1.克隆节点 元素.cLoneNode(true)
const li1=ul.children[0].cloneNode(true)
ul.appendChild(li1)
删除节点
- 若一个节点在页面中已不需要时,可以删除它
- 在JavaScript原生DOM操作中,要删除的元素必须通过父元素删除
语法:父元素.removeChild(要删除的元素)
const ul=document.querySelector('ul')
ul.removeChild(ul.children[0])
注:
- 如果不存在父子关系则删除不成功
- 删除节点和隐藏节点(display)有区别的:隐藏节点还是存在的,但是删除,则从html中删除节点
M端事件
移动端也有自己独特的地方,比如触屏事件touch(也称触摸事件),Android和IOS都有
- 触屏事件touch(也称触摸事件),Andiroid和IOS都有
- touch对象代表一个触摸点,触摸点可能是一根手指,也可能是一根触摸笔,触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。
- 常见的触屏事件如下:
触屏touch事件 | 说明 |
---|---|
touchstart | 手指触摸到一个DOM元素时触发 |
touchmove | 手指在一个DOM元素上滑动时触发 |
touchend | 手指从一个DOM元素上移开时触发 |
插件
插件:就是别人写好的一些代码,我们只需要复制对应的代码,就可以直接实现对应的效果
学习插件的基本过程
- 熟悉官网,了解这个插件可以完成什么需求 https://www.swiper.com.cn/
- 看在线演示,找到符合自己需求的demo https://www.swiper.com.cn/demo/index.html
- 查看基本使用流程 https://www.swiper.com.cn/usage/index.html
- 查看APi文档,去配置自己的插件 https://www.swiper.com.cn/api/index.html
- 注意:多个swiper同时使用的时候,类名需要注意区分
插件的具体使用参见pink老师124-swiper的使用
学生信息表案例
业务模块:
- 点击按钮可以录入数据
- 点击删除可以删除当前的数据
- 本次案例,尽量减少dom操作,采取操作数据的形式
- 增加和删除都是针对于数组的操作,然后根据数组数据渲染页面
核心思路:
- 声明一个空数组
- 点击录入,根据相关数据,生成对象,追加到数组里面
点击录入模块
1.首先取消表单默认提交事件
2.创建新的对象,里面存储表单获取过来的数据
- 根据数组数据渲染页面-表格的行
- 点击删除按钮,删除的是对应数组里面的数据
- 再次根据数组的数据,渲染页面
3.追加给数组
4.渲染数据,遍历数组,动态生成tr,里面填写对应td数据,并追加给tbody
5.重置表单
6..注意防止多次生成多条数据,先清空tbody
点击删除模块
1.采用事件委托形式,给tbody注册点击事件
2.点击链接,要删除的是对应数组里面的这个数据,而不是dom节点
点击新增需要验证表单
1.获取所有需要填写的表单,他们共同特点都有name属性
2.遍历这些表单,如果有一个值为空,则return返回提示输入为空中断程序
3.注意书写的位置,应该放到新增数据的前面,阻止默认行为的后面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>学生信息管理</title>
<link rel="stylesheet" href="css/index.css" />
</head>
<body>
<h1>新增学员</h1>
<!-- autoplaycomplete='off' 不会显示之前输入过的内容 -->
<form class="info" autocomplete="off">
姓名:<input type="text" class="uname" name="uname" />
年龄:<input type="text" class="age" name="age" />
性别:
<select name="gender" class="gender">
<option value="男">男</option>
<option value="女">女</option>
</select>
薪资:<input type="text" class="salary" name="salary" />
就业城市:<select name="city" class="city">
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="广州">广州</option>
<option value="深圳">深圳</option>
<option value="曹县">曹县</option>
</select>
<button class="add">录入</button>
</form>
<h1>就业榜</h1>
<table>
<thead>
<tr>
<th>学号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>薪资</th>
<th>就业城市</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!--
<tr>
<td>1001</td>
<td>欧阳霸天</td>
<td>19</td>
<td>男</td>
<td>15000</td>
<td>上海</td>
<td>
<a href="javascript:">删除</a>
</td>
</tr>
-->
</tbody>
</table>
<script>
//获取元素
const uname=document.querySelector('.uname')
const age=document.querySelector('.age')
const gender=document.querySelector('.gender')
const salary=document.querySelector('.salary')
const city=document.querySelector('.city')
const tbody=document.querySelector('tbody')
// 获取所有带有name属性的元素
const items=document.querySelectorAll('[name]')
//声明一个空的数组 增加和删除都是对这个数组进行操作
const arr=[]
// 1.录入模块
// 1.1表单提交事件
const info=document.querySelector('.info')
info.addEventListener('submit',function( e){
//阻止form默认行为 点击提交之后不跳转至新页面
e.preventDefault()
// 这里进行表单验证 如果不通过 直接中断 不需要添加数据
// 先遍历循环
for(let i=0;i<items.length;i++){
if(items[i].value===''){
return alert('输入内容不能为空')
}
}
// console.log(11)
//创建新的对象
const obj={
stuID:arr.length+1,
uname:uname.value,
age:age.value,
gender:gender.value,
salary:salary.value,
city:city.value
}
// console.log(obj)
//追加到数组里面
arr.push(obj)
// console.log(arr)
//提交之后输入表单
this.reset()//重置表单 恢复默认状态
//调用渲染函数
render()
})
function render(){
//先清空tbody,把最新数组里面的数据渲染完毕
tbody.innerHTML=''
// 遍历数组
for(let i=0;i<arr.length;i++){
//生成tr
const tr=document.createElement('tr')
tr.innerHTML=`
<td>${arr[i].stuID}</td>
<td>${arr[i].uname}</td>
<td>${arr[i].age}</td>
<td>${arr[i].gender}</td>
<td>${arr[i].salary}</td>
<td>${arr[i].city}</td>
<td>
<a href="javascript:" data-id=${i}>删除</a>
</td>
`
// 追加元素 父元素.appendChild(子元素)
tbody.appendChild(tr)
}
}
// 3.删除操作
// 3.1事件委托 tbody
tbody.addEventListener('click',function(e){
if(e.target.tagName==='A'){
//得到当前元素的自定义属性 data-id
// console.log(e.target.dataset.id)
// 删除arr 数组里面对应的数据
arr.splice(e.target.dataset.id,1)
// 重新渲染一次
render()
}
})
</script>
</body>
</html>