其他事件
页面加载事件
- 加载外部资源(如图片,外联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(){//被卷去的头部大于300const 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=0window.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值//页面被卷去的头部>=秒杀模块的位置offsetTopconst n=document.documentElement.scrollTopif(n>=sk.offsetTop){header.style.top=0}else {header.style.top='-80px'}})
实现哔哩哔哩点击小滑块移动效果
需求:当点击链接,下面红色滑块跟着移动
分析:
- 用到时间委托
- 点击链接得到当前元素的offsetLeft值
- 修改line颜色块的transform值=点击链接的offsetLeft
- 添加过渡效果
// 1. 事件委托的方法 获取父元素 tabs-listconst 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(){//被卷去的头部大于300const 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=0window.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//先获取这个类名//若找不到该类名,就返回空nullconst old=document.querySelector('.xtx-elevator-list .active')//判断if(old){old.classList.remove('active')}//当前元素添加activee.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(){//先获取这个类名//若找不到该类名,就返回空nullconst 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.scrollTopif(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:hm=m<10?'0'+m:ms=s<10?'0'+s:sreturn `今天是:${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/1div.innerHTML=date.toLocaleString()//2024/4/1 21:00:15div.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)//函数封装 getCountTimefunction 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:hm=m<10?'0'+m:ms=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=hminutes.innerHTML=msecond.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. 根据数据的个数,创建 对应的小lifor (let i = 0; i < data.length; i++) {// 2. 创建新的小liconst 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追加小liul.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++){//生成trconst 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事件委托 tbodytbody.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>