文章目录
前端学习–js部分中(APIs)
1.变量声明
const
//特殊记忆 //写简单数据类型的时候最好用let声明 //使用const声明简单数据类型的前提是,必须保证变量只出现在声明处一次。 const num=10 num=10 console.log(num) //即使值没有变化也会报错
小结
2.Web APIs
2.1简介
小结
2.2DOM
2.2.1DOM简介
2.2.2DOM树
2.2.3DOM对象
小结
2.3获取DOM对象
2.3.1根据CSS选择器获取DOM元素
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JS</title> </head> <style> </style> <body> <div class="box">123</div> <div class="box">abc</div> <div id="nav">导航栏</div> <div class="nav"> <ul> <li>测试1</li> <li>测试2</li> <li>测试3</li> </ul> </div> <script> // 不管一个多个引号必须写 // 1.获取一个匹配元素,应用 querySelector const box1 = document.querySelector('div') console.log(box1) const box2 = document.querySelector('.box') console.log(box2) // const p = document.querySelector('#nav') // console.log(p) const li = document.querySelector('ul li:first-child') console.log(li) //可以直接修改样式 li.style.color = 'blue' // 2.获取多个匹配元素,应用 querySelectorAll // 获取所有li // const lis=document.querySelectorAll('ul li') const lis = document.querySelectorAll('.nav li') console.log(lis) // 输出的是伪数组 for (let i = 0; i < lis.length; i++) { console.log(lis[i]) } //修改样式只能先遍历,然后依次给里面的元素进行修改 const p = document.querySelectorAll('#nav') console.log(p) p[0].style.color = 'red' </script> </body> </html>
2.3.2其他获取DOM元素方法(不推荐使用)
小结
2.4操作元素内容(常用)
小结
2.5操作元素属性
2.5.1操作元素常用属性
2.5.2操作元素样式属性
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JS</title> </head> <style> div { /* 实际上输入的是w200+h200+bc(最后按回车) */ width: 200px; height: 200px; background-color: plum; } </style> <body> <div class="box"></div> <script> // 1.获取元素 const box = document.querySelector('.box') // 2.修改样式 // 不要忘记单位 box.style.width = '300px' // 多组单词(需要连字符)采取小驼峰命名法 box.style.backgroundColor = 'yellow' box.style.border = '2px solid blue' </script> </body> </html>
小结
更改类名,我们现在更推荐使用classList这种方法,classList不会影响之前的类名。当然需要更改的样式还是写在CSS中的。
2.5.3操作表单属性
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JS</title> </head> <body> <!-- 如果不想点击按钮 --> <!-- H5新规范,属性名和属性值如果一样可以只写一个单词 --> <!-- <button disabled>点击</button> --> <button>点击</button> <script> // checked // 有了这个可以直接获取 input框的,舍弃之前 prompt const ipt = document.querySelector('input') ipt.checked = true // 勾选 // disabled const button = document.querySelector('button') // console.log(button.disabled) // 默认 flase,可以点击 button.disabled = true //禁用按钮 </script> </body> </html>
2.5.4自定义属性
2.6定时器-间歇函数
2.6.1简介
2.6.2详情
<script> // setInterval(函数, 间隔时间) 1秒===1000 // 1.直接写匿名函数 // setInterval(function () { // console.log('一秒执行一次') // }, 1000) // 2.有函数名 function fn() { console.log('一秒执行一次') } // setInterval(函数名,间隔时间) //定时器我们都会给他一个变量名方便关闭定时器 let n = setInterval(fn, 1000) // setInterval('fn()', 1000) //极其少见,不要这样写 </script>
2.7事件监听(绑定)
小结
2.8事件对象
2.8.1简介
2.8.2事件对象常用属性
2.9环境对象 this
<body> <button>点击</button> <script> const btn = document.querySelector('button') btn.addEventListener('click', function () { // console.log(this) //能直接查看this指的是谁 // btn.style.color='red' //这种写法被替换 this.style.color = 'red' }) </script> </body>
小结
2.10回调函数
小结
2.11事件流
2.11.1简介
2.11.2事件捕获(基本不用)
2.11.3事件冒泡
2.11.4阻止冒泡
事件对象是e。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JS</title> </head> <style> .grandpa { width: 200px; height: 200px; background-color: #0080ff; } .father { width: 100px; height: 100px; background-color: #ea7070; } .son { width: 50px; height: 50px; background-color: #98e798; } </style> <body> <div class="grandpa"> <div class="father"> <div class="son"> </div> </div> </div> <script> const gp = document.querySelector('.grandpa') const fa = document.querySelector('.father') const son = document.querySelector('.son') gp.addEventListener('click', function () { alert('grandpa') }) fa.addEventListener('click', function () { alert('father') }) son.addEventListener('click', function (e) { alert('son') // 我们要阻止冒泡,因为很多时候只想在儿子身上做文章。 e.stopPropagation() // 注意 e 事件对象 }) </script> </body> </html>
2.11.5事件解绑
匿名函数无法解绑。
2.11.6扩展:
鼠标经过事件
L0事件和L2事件的区别
2.12事件委托
它是一种技巧,巧妙的运用冒泡。
小结
2.13阻止默认行为
小结
2.14其他事件
2.14.1页面加载事件
小结
2.14.2页面滚动事件
小结
2.14.3页面尺寸事件
2.14.5元素尺寸事件
小结
小结表格(重点)
2.15M事件
2.16日期
2.16.1日期对象
2.16.2实例化
日期案例简易版
2.16.3时间戳
小结
2.17节点操作
2.17.1DOM结点
小结
2.17.2查找节点
<body> <div class="grandpa"> <div class="dad"> <div class="baby"></div> <div class="baby1"></div> </div> </div> <script> const baby = document.querySelector('.baby') const baby1 = document.querySelector('.baby1') const dad = document.querySelector('.dad') console.log(baby) // 子级 console.log(baby.parentNode) // 父级 console.log(baby.parentNode.parentNode) //爷级 console.log(dad.children) // 得到伪数组 选择亲儿子 console.log(baby1.previousElementSibling) // 上一个兄弟 console.log(baby.nextElementSibling) // 下一个兄弟 </script> </body>
小结
2.17.3增加节点
<body> <ul> <li>old</li> </ul> <script> let data = [ { title: '你好' }, { title: 'thanks' } ] // 所有的都是先创建后追加 // 1.创建节点 // const div = document.createElement('div') // console.log(div) // 2.追加节点 作为最后一个子元素 // document.body.appendChild(div) // console.log(div) // 3.在指定的位置追加节点 const ul = document.querySelector('ul') // 创建的标签不要乱写 const li = document.createElement('li') // 放在指定元素的前面 ul.insertBefore(li, ul.children[0]) li.innerHTML = 'new' const li1 = document.createElement('li') ul.appendChild(li1) // innerHtml可以用模板字符串 li1.innerHTML = ` <h4>${data[0].title}</h4> ` </script> </body>
2.16.4克隆节点
2.17.5删除节点
2.18 js插件(常用)
在swiper网站上直接下载,在下载完成的压缩包内找到package文件夹,css文件和js文件都在package文件夹中,我们需要的效果主要是使用css文件和js文件。
如果我们需要预览效果,单击在线演示即可。预览到自己喜欢的样式时,记住对应序号。然后我们找到下载完成的swiper文件中的demo文件,在demo文件中找到对应序号的html文件。打开html文件,右键单击查看网页源代码,进行复制粘贴。
这里需要注意的是不建议使用太新的swiper文件。
2.19 Window对象
下面讲解的内容属于Window对象。Window对象是最大的。
window.document.qyerySelector() //window可省略
2.19.1BOM
BOM我们平时用的少,DOM使用的多。BOM大于DOM。
2.19.2定时器-延时函数
<!-- 5秒之后关闭广告 --> <body> <img src="./images/ad.png" alt=""> <script> // 1.获取元素 const img = document.querySelector('img') setTimeout(function () { img.style.display = 'none' }, 5000) </script> </body>
两种定时器的区别
2.19.3 js执行机制
简介
执行顺序
浏览器是多线程。
2.19.4location对象
小结
2.19.5navigator对象(了解)
主要是为移动端服务。
2.19.6history对象 (了解)
2.20本地存储(重点)
2.20.1简介
2.20.2localStorage
2.20.3sessionStorage(不推荐使用)
经过本地存储的内容在这里,浏览器页面按F12快捷键。
2.20.4本地存储处理复杂数据类型
map方法和join方法
2.21正则表达式
2.21.1正则表达式的使用
小结
2.21.2元字符
元字符的好处
元字符的分类
边界符
量词
有中括号的更常用。
{n}重复的次数必须等于n,{n,}重复的次数大于等于n。
{m,n}注意写的时候逗号左右两侧千万不能有空格。
字符类
<body> <script> // []匹配字符集合 // 1.后面的字符只要包含abc中的任意一个字符,就返回true console.log(/[abc]/.test('andy')) // true console.log(/[abc]/.test('baby')) // true console.log(/[abc]/.test('city')) // true console.log(/[abc]/.test('die')) // false // 2.在abc中只选一个,返回true console.log(/^[abc]$/.test('a')) // true console.log(/^[abc]$/.test('b')) // true console.log(/^[abc]$/.test('c')) // true console.log(/^[abc]$/.test('ab')) // false console.log(/^[abc]{2}$/.test('ab')) // true // 3.[a-z]中只选一个,返回true // []里面加上连字符,表示一个范围 console.log(/^[A-Z]$/.test('p')) // false console.log(/^[A-Z]$/.test('P')) // true console.log(/^[0-9]$/.test(2)) // true console.log(/^[a-zA-Z]$/.test(2)) // false console.log(/^[a-zA-Z0-9]$/.test('p')) // true console.log(/^[a-zA-Z0-9]$/.test('P')) // true // 扩展 从10000开始都是true // 一个中括号代表一位数 , {4,}大括号作用于离他最近的一位数 console.log(/^[1-9][0-9]{4,}$/.test(10000)) //true // 4.中括号里面加 ^ 取反符号 // 匹配除了大写字母以外的字符 注意取反符号要写在中括号里面 console.log(/^[^A-Z]$/.test('2')) // true // 5..匹配除换行符外的所有字符 console.log(/^.$/.test('\n')) // false console.log(/^.$/.test('b')) //true // 扩展 选取所有字母以及下划线 console.log(/^[a-zA-Z0-9_]$/.test('_')) // true console.log(/^[a-zA-Z0-9-_]$/.test('_')) // true 不推荐这种写法 </script> </body>
2.21.3修饰符
3.综合案例
年会抽奖
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>年会抽奖 主要练习innerHTML</title> <style> .wrapper { width: 840px; height: 420px; background: url(./images/1.jpg) no-repeat center / cover; padding: 100px 250px; box-sizing: border-box; } </style> </head> <body> <div class="wrapper"> <strong>传智教育年会抽奖</strong> <h1>一等奖:<span id="one">???</span></h1> <h3>二等奖:<span id="two">???</span></h3> <h5>三等奖:<span id="three">???</span></h5> </div> <script> // 1.声明数组 const personArr = ['周杰伦', '刘德华', '周星驰', 'Pink老师', '张学友'] // 2. 先做一等奖 // 2.1 随机数 数组的下标 const random = Math.floor(Math.random() * personArr.length) // console.log(personArr[random]) // 2.2 获取one 元素 const one = document.querySelector('#one') // 2.3 把名字给 one one.innerHTML = personArr[random] // 2.4 删除数组这个名字 personArr.splice(random, 1) // console.log(personArr) // 3. 二等奖 // 2.1 随机数 数组的下标 const random2 = Math.floor(Math.random() * personArr.length) // console.log(personArr[random]) // 2.2 获取one 元素 const two = document.querySelector('#two') // 2.3 把名字给 one two.innerHTML = personArr[random2] // 2.4 删除数组这个名字 personArr.splice(random2, 1) // 4. 三等奖 // 2.1 随机数 数组的下标 const random3 = Math.floor(Math.random() * personArr.length) // console.log(personArr[random]) // 2.2 获取one 元素 const three = document.querySelector('#three') // 2.3 把名字给 one three.innerHTML = personArr[random3] // 2.4 删除数组这个名字 personArr.splice(random3, 1) </script> </body> </html>
轮播图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>轮播图点击切换</title> <style> * { box-sizing: border-box; } .slider { width: 560px; height: 400px; overflow: hidden; } .slider-wrapper { width: 100%; height: 320px; } .slider-wrapper img { width: 100%; height: 100%; display: block; } .slider-footer { height: 80px; background-color: rgb(100, 67, 68); padding: 12px 12px 0 12px; position: relative; } .slider-footer .toggle { position: absolute; right: 0; top: 12px; display: flex; } .slider-footer .toggle button { margin-right: 12px; width: 28px; height: 28px; appearance: none; border: none; background: rgba(255, 255, 255, 0.1); color: #fff; border-radius: 4px; cursor: pointer; } .slider-footer .toggle button:hover { background: rgba(255, 255, 255, 0.2); } .slider-footer p { margin: 0; color: #fff; font-size: 18px; margin-bottom: 10px; } .slider-indicator { margin: 0; padding: 0; list-style: none; display: flex; align-items: center; } .slider-indicator li { width: 8px; height: 8px; margin: 4px; border-radius: 50%; background: #fff; opacity: 0.4; cursor: pointer; } .slider-indicator li.active { width: 12px; height: 12px; /*透明度*/ opacity: 1; } </style> </head> <body> <div class="slider"> <div class="slider-wrapper"> <img src="./images/slider01.jpg" alt="" /> </div> <div class="slider-footer"> <p>对人类来说会不会太超前了?</p> <ul class="slider-indicator"> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> <div class="toggle"> <button class="prev"><</button> <button class="next">></button> </div> </div> </div> <script> // 1. 初始数据 const sliderData = [ { url: './images/slider01.jpg', title: '对人类来说会不会太超前了?', color: 'rgb(100, 67, 68)' }, { url: './images/slider02.jpg', title: '开启剑与雪的黑暗传说!', color: 'rgb(43, 35, 26)' }, { url: './images/slider03.jpg', title: '真正的jo厨出现了!', color: 'rgb(36, 31, 33)' }, { url: './images/slider04.jpg', title: '李玉刚:让世界通过B站看到东方大国文化', color: 'rgb(139, 98, 66)' }, { url: './images/slider05.jpg', title: '快来分享你的寒假日常吧~', color: 'rgb(67, 90, 92)' }, { url: './images/slider06.jpg', title: '哔哩哔哩小年YEAH', color: 'rgb(166, 131, 143)' }, { url: './images/slider07.jpg', title: '一站式解决你的电脑配置问题!!!', color: 'rgb(53, 29, 25)' }, { url: './images/slider08.jpg', title: '谁不想和小猫咪贴贴呢!', color: 'rgb(99, 72, 114)' }, ] // 1. 需要一个随机数 const random = parseInt(Math.random() * sliderData.length) // console.log(sliderData[random]) // 2. 把对应的数据渲染到标签里面 // 2.1 获取图片 const img = document.querySelector('.slider-wrapper img') // 2.2. 修改图片路径 = 对象.url img.src = sliderData[random].url // 3. 把p里面的文字内容更换 // 3.1 获取p const p = document.querySelector('.slider-footer p') // 3.2修改p p.innerHTML = sliderData[random].title // 4. 修改背景颜色 const footer = document.querySelector('.slider-footer') footer.style.backgroundColor = sliderData[random].color // 5. 小圆点 //运用模板字符串,要把引号改为反引号 const li = document.querySelector(`.slider-indicator li:nth-child(${random + 1})`) // 让当前这个小li 添加 active这个类 li.classList.add('active') </script> </body> </html>
用户协议
<body> <textarea name="" id="" cols="30" rows="10"> 用户注册协议 欢迎注册成为京东用户!在您注册过程中,您需要完成我们的注册流程并通过点击同意的形式在线签署以下协议,请您务必仔细阅读、充分理解协议中的条款内容后再点击同意(尤其是以粗体或下划线标识的条款,因为这些条款可能会明确您应履行的义务或对您的权利有所限制)。 【请您注意】如果您不同意以下协议全部或任何条款约定,请您停止注册。您停止注册后将仅可以浏览我们的商品信息但无法享受我们的产品或服务。如您按照注册流程提示填写信息,阅读并点击同意上述协议且完成全部注册流程后,即表示您已充分阅读、理解并接受协议的全部内容,并表明您同意我们可以依据协议内容来处理您的个人信息,并同意我们将您的订单信息共享给为完成此订单所必须的第三方合作方(详情查看 </textarea> <br> <button class="btn" disabled>我已经阅读用户协议(5)</button> <script> // 1. 获取元素 const btn = document.querySelector('.btn') // console.log(btn.innerHTML) butto按钮特殊用innerHTML // 2. 倒计时 let i = 5 // 2.1 开启定时器 let n = setInterval(function () { i-- btn.innerHTML = `我已经阅读用户协议(${i})` if (i === 0) { clearInterval(n) // 关闭定时器 // 定时器停了,我就可以开按钮 btn.disabled = false btn.innerHTML = '同意' } }, 1000) </script> </body>
定时轮播图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>轮播图点击切换</title> <style> * { box-sizing: border-box; } .slider { width: 560px; height: 400px; overflow: hidden; } .slider-wrapper { width: 100%; height: 320px; } .slider-wrapper img { width: 100%; height: 100%; display: block; } .slider-footer { height: 80px; background-color: rgb(100, 67, 68); padding: 12px 12px 0 12px; position: relative; } .slider-footer .toggle { position: absolute; right: 0; top: 12px; display: flex; } .slider-footer .toggle button { margin-right: 12px; width: 28px; height: 28px; appearance: none; border: none; background: rgba(255, 255, 255, 0.1); color: #fff; border-radius: 4px; cursor: pointer; } .slider-footer .toggle button:hover { background: rgba(255, 255, 255, 0.2); } .slider-footer p { margin: 0; color: #fff; font-size: 18px; margin-bottom: 10px; } .slider-indicator { margin: 0; padding: 0; list-style: none; display: flex; align-items: center; } .slider-indicator li { width: 8px; height: 8px; margin: 4px; border-radius: 50%; background: #fff; opacity: 0.4; cursor: pointer; } .slider-indicator li.active { width: 12px; height: 12px; opacity: 1; } </style> </head> <body> <div class="slider"> <div class="slider-wrapper"> <img src="./images/slider01.jpg" alt="" /> </div> <div class="slider-footer"> <p>对人类来说会不会太超前了?</p> <ul class="slider-indicator"> <li class="active"></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> <div class="toggle"> <button class="prev"><</button> <button class="next">></button> </div> </div> </div> <script> // 1. 初始数据 const sliderData = [ { url: './images/slider01.jpg', title: '对人类来说会不会太超前了?', color: 'rgb(100, 67, 68)' }, { url: './images/slider02.jpg', title: '开启剑与雪的黑暗传说!', color: 'rgb(43, 35, 26)' }, { url: './images/slider03.jpg', title: '真正的jo厨出现了!', color: 'rgb(36, 31, 33)' }, { url: './images/slider04.jpg', title: '李玉刚:让世界通过B站看到东方大国文化', color: 'rgb(139, 98, 66)' }, { url: './images/slider05.jpg', title: '快来分享你的寒假日常吧~', color: 'rgb(67, 90, 92)' }, { url: './images/slider06.jpg', title: '哔哩哔哩小年YEAH', color: 'rgb(166, 131, 143)' }, { url: './images/slider07.jpg', title: '一站式解决你的电脑配置问题!!!', color: 'rgb(53, 29, 25)' }, { url: './images/slider08.jpg', title: '谁不想和小猫咪贴贴呢!', color: 'rgb(99, 72, 114)' }, ] // 1. 获取元素 const img = document.querySelector('.slider-wrapper img') const p = document.querySelector('.slider-footer p') let i = 0 // 信号量 控制图片的张数 // 2. 开启定时器 setInterval(function () { i++ // 无缝衔接位置 一共八张图片,到了最后一张就是 8, 数组的长度就是 8 if (i >= sliderData.length) { i = 0 } // 更换图片路径 img.src = sliderData[i].url // 把字写到 p里面 p.innerHTML = sliderData[i].title // 小圆点 // 先删除以前的active //document.querySelector是一家的,写querySelector就要写document document.querySelector('.slider-indicator .active').classList.remove('active') // 只让当前li添加active // i+1是因为li是1-8,但是数组是0-7 document.querySelector(`.slider-indicator li:nth-child(${i + 1})`).classList.add('active') }, 1000) </script> </body> </html>
随机点名
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JS</title> </head> <style> * { margin: 0; padding: 0; } h2 { text-align: center; } .box { width: 600px; margin: 50px auto; display: flex; font-size: 25px; line-height: 40px; } .qs { width: 450px; height: 40px; color: red; } .btns { text-align: center; } .btns button { width: 120px; height: 35px; margin: 0 50px; } </style> <body> <h2>随机点名</h2> <div class="box"> <span>名字是:</span> <div class="qs">这里显示姓名</div> </div> <div class="btns"> <button class="start">开始</button> <button class="end">结束</button> </div> <script> const arr = ['马超', '黄忠', '赵云', '关羽', '张飞'] //让 timerId变为全局变量,不然无法关闭定时器 let timerId = 0 let random = 0 // 1.开始按钮 // 获取开始按钮 const start = document.querySelector('.start') const end = document.querySelector('.end') const qs = document.querySelector('.qs') // 添加点击事件 start.addEventListener('click', function () { timerId = setInterval(function () { // 生成随机数 random = parseInt(Math.random() * arr.length) // console.log(arr[random]) // 进行一步最好检查一下 qs.innerHTML = arr[random] // 如果数组中只剩一个人名的时候不需要抽取,直接禁用按钮 if (arr.length === 1) { /* start.disabled = true end.disabled = true */ start.disabled = end.disabled = true } }, 35) }) end.addEventListener('click', function () { clearInterval(timerId) // 被抽到的内容要删除,避免二次出现 arr.splice(random, 1) // console.log(arr) }) </script> </body> </html>
轮播图完整版
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>轮播图点击切换</title> <style> * { box-sizing: border-box; } .slider { width: 560px; height: 400px; overflow: hidden; } .slider-wrapper { width: 100%; height: 320px; } .slider-wrapper img { width: 100%; height: 100%; display: block; } .slider-footer { height: 80px; background-color: rgb(100, 67, 68); padding: 12px 12px 0 12px; position: relative; } .slider-footer .toggle { position: absolute; right: 0; top: 12px; display: flex; } .slider-footer .toggle button { margin-right: 12px; width: 28px; height: 28px; appearance: none; border: none; background: rgba(255, 255, 255, 0.1); color: #fff; border-radius: 4px; cursor: pointer; } .slider-footer .toggle button:hover { background: rgba(255, 255, 255, 0.2); } .slider-footer p { margin: 0; color: #fff; font-size: 18px; margin-bottom: 10px; } .slider-indicator { margin: 0; padding: 0; list-style: none; display: flex; align-items: center; } .slider-indicator li { width: 8px; height: 8px; margin: 4px; border-radius: 50%; background: #fff; opacity: 0.4; cursor: pointer; } .slider-indicator li.active { width: 12px; height: 12px; opacity: 1; } </style> </head> <body> <div class="slider"> <div class="slider-wrapper"> <img src="./images/slider01.jpg" alt="" /> </div> <div class="slider-footer"> <p>对人类来说会不会太超前了?</p> <ul class="slider-indicator"> <li class="active"></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> <div class="toggle"> <button class="prev"><</button> <button class="next">></button> </div> </div> </div> <script> // 1. 初始数据 const data = [ { url: './images/slider01.jpg', title: '对人类来说会不会太超前了?', color: 'rgb(100, 67, 68)' }, { url: './images/slider02.jpg', title: '开启剑与雪的黑暗传说!', color: 'rgb(43, 35, 26)' }, { url: './images/slider03.jpg', title: '真正的jo厨出现了!', color: 'rgb(36, 31, 33)' }, { url: './images/slider04.jpg', title: '李玉刚:让世界通过B站看到东方大国文化', color: 'rgb(139, 98, 66)' }, { url: './images/slider05.jpg', title: '快来分享你的寒假日常吧~', color: 'rgb(67, 90, 92)' }, { url: './images/slider06.jpg', title: '哔哩哔哩小年YEAH', color: 'rgb(166, 131, 143)' }, { url: './images/slider07.jpg', title: '一站式解决你的电脑配置问题!!!', color: 'rgb(53, 29, 25)' }, { url: './images/slider08.jpg', title: '谁不想和小猫咪贴贴呢!', color: 'rgb(99, 72, 114)' }, ] // 获取元素 const img = document.querySelector('.slider-wrapper img') const p = document.querySelector('.slider-footer p') const footer = document.querySelector('.slider-footer') // 1. 右按钮业务 // 1.1 获取右侧按钮 const next = document.querySelector('.next') let i = 0 // 信号量 控制播放图片张数 // 1.2 注册点击事件 next.addEventListener('click', function () { i++ i = i >= data.length ? 0 : i // 调用函数 toggle() }) // 2. 左侧按钮业务 // 2.1 获取左侧按钮 const prev = document.querySelector('.prev') // 2.2 注册点击事件 prev.addEventListener('click', function () { i-- i = i < 0 ? data.length - 1 : i // 调用函数 toggle() }) // 声明一个渲染的函数作为复用 function toggle() { // 1.4 渲染对应的数据 img.src = data[i].url p.innerHTML = data[i].title footer.style.backgroundColor = data[i].color // 1.5 更换小圆点 先移除原来的类名, 当前li再添加 这个 类名 document.querySelector('.slider-indicator .active').classList.remove('active') document.querySelector(`.slider-indicator li:nth-child(${i + 1})`).classList.add('active') } // 3. 自动播放模块 let timerId = setInterval(function () { // 利用js自动调用点击事件 click() 一定加小括号调用函数 next.click() }, 1000) // 4. 鼠标经过大盒子,停止定时器 const slider = document.querySelector('.slider') // 注册事件 slider.addEventListener('mouseenter', function () { // 停止定时器 clearInterval(timerId) }) // 5. 鼠标离开大盒子,开启定时器 // 注册事件 slider.addEventListener('mouseleave', function () { // 停止定时器,好的习惯,先关再开 if (timerId) clearInterval(timerId) // 开启定时器 timerId = setInterval(function () { // 利用js自动调用点击事件 click() 一定加小括号调用函数 next.click() }, 1000) }) </script> </body> </html>
发布评论
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>js</title> </head> <style> /* 光标定位之后产生的变化,要采用过渡,没有过渡效果不美观 */ input { width: 200px; height: 30px; transition: all .3s; color: rgb(165, 165, 165); /*去input默认框*/ outline: none; } input:focus { height: 50px; color: black; } button { width: 100px; height: 30px; background-color: #5fc4ec; color: #fff; border-color: #fff; } p { color: rgb(165, 165, 165); padding-left: 140px; } </style> <body> <div> <input type="text" value="请输入内容"> <button>提交</button> <p>0/10个字</p> </div> </body> <script> const input = document.querySelector('input') const p = document.querySelector('p') input.addEventListener('focus', function () { input.value = '' }) input.addEventListener('blur', function () { input.value = '请输入内容' }) input.addEventListener('input', function () { // console.log(input.value.length) p.innerHTML = `${input.value.length}/10个字` if (input.value.length > 10) { alert('超过最大字符') input.value = '' } }) </script> </html>
评论回车发布
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>评论回车发布</title> <style> .wrapper { min-width: 400px; max-width: 800px; display: flex; justify-content: flex-end; } .avatar { width: 48px; height: 48px; border-radius: 50%; overflow: hidden; background: url(./images/avatar.jpg) no-repeat center / cover; margin-right: 20px; } .wrapper textarea { outline: none; border-color: transparent; resize: none; background: #f5f5f5; border-radius: 4px; flex: 1; padding: 10px; transition: all 0.5s; height: 30px; } .wrapper textarea:focus { border-color: #e4e4e4; background: #fff; height: 50px; } .wrapper button { background: #00aeec; color: #fff; border: none; border-radius: 4px; margin-left: 10px; width: 70px; cursor: pointer; } .wrapper .total { margin-right: 80px; color: #999; margin-top: 5px; opacity: 0; transition: all 0.5s; } .list { min-width: 400px; max-width: 800px; display: flex; } .list .item { width: 100%; display: flex; } .list .item .info { flex: 1; border-bottom: 1px dashed #e4e4e4; padding-bottom: 10px; } .list .item p { margin: 0; } .list .item .name { color: #FB7299; font-size: 14px; font-weight: bold; } .list .item .text { color: #333; padding: 10px 0; } .list .item .time { color: #999; font-size: 12px; } </style> </head> <body> <div class="wrapper"> <i class="avatar"></i> <textarea id="tx" placeholder="发一条友善的评论" rows="2" maxlength="200"></textarea> <button>发布</button> </div> <div class="wrapper"> <span class="total">0/200字</span> </div> <div class="list"> <div class="item" style="display: none;"> <i class="avatar"></i> <div class="info"> <p class="name">zhuie</p> <p class="text">大家都辛苦啦,感谢各位大大的努力,能圆满完成真是太好了[笑哭][支持]</p> <p class="time">2023-05-17 20:33:21</p> </div> </div> </div> <script> const tx = document.querySelector('#tx') const total = document.querySelector('.total') const item = document.querySelector('.item') const text = document.querySelector('.text') // 1. 当我们文本域获得了焦点,就让 total 显示出来 tx.addEventListener('focus', function () { total.style.opacity = 1 }) // 2. 当我们文本域失去了焦点,就让 total 隐藏出来 tx.addEventListener('blur', function () { total.style.opacity = 0 }) // 3. 检测用户输入 tx.addEventListener('input', function () { // console.log(tx.value.length) 得到输入的长度 total.innerHTML = `${tx.value.length}/200字` }) // 4. 按下回车发布评论 tx.addEventListener('keyup', function (e) { // 只有按下的是回车键,才会触发 if (e.key === 'Enter') { // 如果用户输入的不为空就显示和打印 //这里的trim()方法的作用是去除字符串整体的两侧空格 if (tx.value.trim()) { item.style.display = 'block' // console.log(tx.value) // 用户输入的内容 text.innerHTML = tx.value } // 等我们按下回车,结束,清空文本域 tx.value = '' // 按下回车之后,就要把 字符统计 复原 total.innerHTML = '0/200字' } }) </script> </body> </html>
tab栏切换
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>tab栏切换</title> <style> * { margin: 0; padding: 0; } .tab { width: 590px; height: 340px; margin: 20px; border: 1px solid #e4e4e4; } .tab-nav { width: 100%; height: 60px; line-height: 60px; display: flex; justify-content: space-between; } .tab-nav h3 { font-size: 24px; font-weight: normal; margin-left: 20px; } .tab-nav ul { list-style: none; display: flex; justify-content: flex-end; } .tab-nav ul li { margin: 0 20px; font-size: 14px; } .tab-nav ul li a { text-decoration: none; border-bottom: 2px solid transparent; color: #333; } .tab-nav ul li a.active { border-color: #e1251b; color: #e1251b; } .tab-content { padding: 0 16px; } .tab-content .item { display: none; } .tab-content .item.active { display: block; } </style> </head> <body> <div class="tab"> <div class="tab-nav"> <h3>每日特价</h3> <ul> <li><a class="active" href="javascript:;">精选</a></li> <li><a href="javascript:;">美食</a></li> <li><a href="javascript:;">百货</a></li> <li><a href="javascript:;">个护</a></li> <li><a href="javascript:;">预告</a></li> </ul> </div> <div class="tab-content"> <div class="item active"><img src="./images/tab00.png" alt="" /></div> <div class="item"><img src="./images/tab01.png" alt="" /></div> <div class="item"><img src="./images/tab02.png" alt="" /></div> <div class="item"><img src="./images/tab03.png" alt="" /></div> <div class="item"><img src="./images/tab04.png" alt="" /></div> </div> </div> <script> // 1. a 模块制作 要给 5个链接绑定鼠标经过事件 //注意:不能使用hover,因为鼠标经过之后的内容仍需要显示。 // 1.1 获取 a 元素 const as = document.querySelectorAll('.tab-nav a') for (let i = 0; i < as.length; i++) { // 要给 5个链接绑定鼠标经过事件 as[i].addEventListener('mouseenter', function () { // 鼠标经过 // 排他思想 // 干掉别人 移除类active document.querySelector('.tab-nav .active').classList.remove('active') // 我登基 我添加类 active this 当前的那个 a this.classList.add('active') // 下面5个大盒子 一一对应 .item // 干掉别人 document.querySelector('.tab-content .active').classList.remove('active') // 对应序号的那个 item 显示 添加 active 类 document.querySelector(`.tab-content .item:nth-child(${i + 1})`).classList.add('active') }) } </script> </body> </html>
全选文本框
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> * { margin: 0; padding: 0; } table { border-collapse: collapse; border-spacing: 0; border: 1px solid #c0c0c0; width: 500px; margin: 100px auto; text-align: center; } th { background-color: #09c; font: bold 16px "微软雅黑"; color: #fff; height: 24px; } td { border: 1px solid #d0d0d0; color: #404060; padding: 10px; } .allCheck { width: 80px; } </style> </head> <body> <table> <tr> <th class="allCheck"> <input type="checkbox" name="" id="checkAll"> <span class="all">全选</span> </th> <th>商品</th> <th>商家</th> <th>价格</th> </tr> <tr> <td> <input type="checkbox" name="check" class="ck"> </td> <td>小米手机</td> <td>小米</td> <td>¥1999</td> </tr> <tr> <td> <input type="checkbox" name="check" class="ck"> </td> <td>小米净水器</td> <td>小米</td> <td>¥4999</td> </tr> <tr> <td> <input type="checkbox" name="check" class="ck"> </td> <td>小米电视</td> <td>小米</td> <td>¥5999</td> </tr> </table> <script> // 1. 获取大复选框 const checkAll = document.querySelector('#checkAll') // 2. 获取所有的小复选框 const cks = document.querySelectorAll('.ck') // 3. 点击大复选框 注册事件 checkAll.addEventListener('click', function () { // 得到当前大复选框的选中状态 // console.log(checkAll.checked) // 得到 是 true 或者是 false // 4. 遍历所有的小复选框 让小复选框的checked = 大复选框的 checked for (let i = 0; i < cks.length; i++) { cks[i].checked = this.checked } }) // 5. 小复选框控制大复选框 for (let i = 0; i < cks.length; i++) { // 5.1 给所有的小复选框添加点击事件 cks[i].addEventListener('click', function () { // 判断选中的小复选框个数 是不是等于 总的小复选框个数 // console.log(document.querySelectorAll('.ck:checked').length) // console.log(document.querySelectorAll('.ck:checked').length === cks.length) checkAll.checked = document.querySelectorAll('.ck:checked').length === cks.length }) } </script> </body> </html>
tab栏切换升级版
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>tab栏切换</title> <style> * { margin: 0; padding: 0; } .tab { width: 590px; height: 340px; margin: 20px; border: 1px solid #e4e4e4; } .tab-nav { width: 100%; height: 60px; line-height: 60px; display: flex; justify-content: space-between; } .tab-nav h3 { font-size: 24px; font-weight: normal; margin-left: 20px; } .tab-nav ul { list-style: none; display: flex; justify-content: flex-end; } .tab-nav ul li { margin: 0 20px; font-size: 14px; } .tab-nav ul li a { text-decoration: none; border-bottom: 2px solid transparent; color: #333; } .tab-nav ul li a.active { border-color: #e1251b; color: #e1251b; } .tab-content { padding: 0 16px; } .tab-content .item { display: none; } .tab-content .item.active { display: block; } </style> </head> <body> <div class="tab"> <div class="tab-nav"> <h3>每日特价</h3> <ul> <li><a class="active" href="javascript:;" data-id="0">精选</a></li> <li><a href="javascript:;" data-id="1">美食</a></li> <li><a href="javascript:;" data-id="2">百货</a></li> <li><a href="javascript:;" data-id="3">个护</a></li> <li><a href="javascript:;" data-id="4">预告</a></li> </ul> </div> <div class="tab-content"> <div class="item active"><img src="./images/tab00.png" alt="" /></div> <div class="item"><img src="./images/tab01.png" alt="" /></div> <div class="item"><img src="./images/tab02.png" alt="" /></div> <div class="item"><img src="./images/tab03.png" alt="" /></div> <div class="item"><img src="./images/tab04.png" alt="" /></div> </div> </div> <script> // 采取事件委托的形式 tab栏切换 // 1. 获取 ul 父元素 因为 ul只有一个 const ul = document.querySelector('.tab-nav ul') // 获取 5个 item,生成的是数组。 const items = document.querySelectorAll('.tab-content .item') // 2. 添加事件 ul.addEventListener('click', function (e) { // console.log(e.target) // e.target是我们点击的对象 // 我们只有点击了 a 才会 进行 添加类和删除类操作 // console.log(e.target.tagName) // e.target.tagName 点击那个对象的 标签名 if (e.target.tagName === 'A') { // console.log('我选的是a') // 排他思想 ,先移除原来的active document.querySelector('.tab-nav .active').classList.remove('active') //当前元素添加 active 是 e.target // this 指向ul 不能用this e.target.classList.add('active') // 下面大盒子模块 //在采用事件委托的情况下,我们不再进行数组遍历,也就没有下标序号,所以要采用自定义属性。 // console.log(e.target.dataset.id) // 获取的是字符串,需转换为数字。它的范围是0~4,和数组下标一样。 const i = +e.target.dataset.id // 排他思想 ,先移除原来的active document.querySelector('.tab-content .active').classList.remove('active') // 对应的大盒子 添加 active // document.querySelector(`.tab-content .item:nth-child(${i + 1})`).classList.add('active') items[i].classList.add('active') } }) </script> </body> </html>
仿京东固定导航栏
<body> <div class="header">我是顶部导航栏</div> <div class="content"> <div class="sk">秒杀模块</div> </div> <div class="backtop"> <img src="./images/close2.png" alt=""> <a href="javascript:;"></a> </div> <script> const sk = document.querySelector('.sk') const header = document.querySelector('.header') // 页面滚动事件 window.addEventListener('scroll', function () { // 当页面滚动到 秒杀模块的时候,就改变 头部的 top值 // 页面被卷去的头部 >= 秒杀模块的位置 offsetTop const n = document.documentElement.scrollTop header.style.top = n >= sk.offsetTop ? 0 : '-80px' }) </script> </body>
实现bilibili 点击小滑块移动效果
<script> // 1. 事件委托的方法 获取父元素 tabs-list const list = document.querySelector('.tabs-list') const line = document.querySelector('.line') // 2. 注册点击事件 list.addEventListener('click', function (e) { // 只有点击了A(a标签在tagName中是A) 才有触发效果 if (e.target.tagName === 'A') { // 得到当前点击元素的位置 // console.log(e.target.offsetLeft) // 把我们点击的a链接盒子的位置 然后移动 line.style.transform = `translateX(${e.target.offsetLeft}px)` } }) </script>
电梯导航
<style> /* 让滚动条添加滑动效果(重要) */ html { /* 这句话的意思是:滚动条的行为是光滑的 */ scroll-behavior: smooth; } </style> <script> // 不要采用运用索引号的方法,不严谨,无法在新添元素。 // 运用的都是立即执行函数 // 第一大模块,页面滑动可以显示和隐藏 (function () { // 获取元素 const entry = document.querySelector('.xtx_entry') const elevator = document.querySelector('.xtx-elevator') // 1. 当页面滚动大于 300像素,就显示 电梯导航 // 2. 给页面添加滚动事件 window.addEventListener('scroll', function () { // 被卷去的头部大于 300 const n = document.documentElement.scrollTop 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 () { // 2. 点击页面可以滑动 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 // 先获取这个active的对象 const old = document.querySelector('.xtx-elevator-list .active') // console.log(old) // 判断 如果原来有active类的对象,就移除类,如果开始就没有对象,就不删除,所以不报错 if (old) old.classList.remove('active') // 当前元素添加 active 事件委托运用自定义属性(触发子元素就可以运用对应父元素的功能) e.target.classList.add('active') // 获得自定义属性 new topic // console.log(e.target.dataset.name) // 根据小盒子的自定义属性值 去选择 对应的大盒子 // console.log(document.querySelector(`.xtx_goods_${e.target.dataset.name}`).offsetTop) // 获得对应大盒子的 offsetTop const top = document.querySelector(`.xtx_goods_${e.target.dataset.name}`).offsetTop // 让页面滚动到对应的位置 记下来 只要页面滚动就是这句话 document.documentElement.scrollTop = top } }) // 3. 页面滚动,可以根据大盒子选 小盒子 添加 active 类 window.addEventListener('scroll', function () { // 3.1 先移除类 // 先获取这个active的对象 const old = document.querySelector('.xtx-elevator-list .active') // console.log(old) // 判断 如果原来有active类的对象,就移除类,如果开始就没有对象,就不删除,所以不报错 if (old) old.classList.remove('active') // 3.2 判断页面当前滑动的位置,选择小盒子 // 获取4个大盒子 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') } }) })(); </script>
日期案例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <style> div { display: inline; padding: 5px; border: 1px solid #808080; } </style> <body> <div></div> <script> const div = document.querySelector('div') function getMyDate() { const date = new Date() let h = date.getHours() let m = date.getMinutes() let s = date.getSeconds() // 按Ctrl+D快捷键,直接选中所有的 h 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) </script> </body> </html>
时间倒计时
<script> // 函数封装 getCountTime function getCountTime() { // 1. 得到当前的时间戳 const now = +new Date() // 2. 得到将来的时间戳 const last = +new Date('2022-4-1 18:30:00') // console.log(now, last) // 3. 得到剩余的时间戳 count 记得转换为 秒数 const count = (last - now) / 1000 // console.log(count) // 4. 转换为时分秒 // h = parseInt(总秒数 / 60 / 60 % 24) // 计算小时 // m = parseInt(总秒数 / 60 % 60) // 计算分数 // s = parseInt(总秒数 % 60) // 计算当前秒数 // let d = parseInt(count / 60 / 60 / 24) // 计算当前天数 let h = parseInt(count / 60 / 60 % 24) h = h < 10 ? '0' + h : h let m = parseInt(count / 60 % 60) m = m < 10 ? '0' + m : m let s = parseInt(count % 60) s = s < 10 ? '0' + s : s console.log(h, m, s) // 把时分秒写到对应的盒子里面 document.querySelector('#hour').innerHTML = h document.querySelector('#minutes').innerHTML = m document.querySelector('#scond').innerHTML = s } // 先调用一次 getCountTime() // 开启定时器 setInterval(getCountTime, 1000) </script>
学生信息表
<!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> <style> * { margin: 0; padding: 0; } a { /* 颜色继承 */ color: #b70000; text-decoration: none; } h1, .info { text-align: center; margin: 30px 0; } table { margin: auto; width: 900px; /* 这个要写在table属性上 */ border-collapse: collapse; text-align: center; } tr:hover { background-color: #e0e0e0; } th, td { border: 1px solid #808080; height: 50px; } th { background-color: #D3E5FE; color: #334764; font-weight: 400; } td { color: #808080; } input, .city, .gender { margin: 10px; width: 80px; height: 20px; border: 1px solid #808080; border-radius: 5px; outline: none; text-align: center; line-height: 20px; } .add { margin-left: 5px; background-color: #174188; /* outline: none; */ border: 0; border-radius: 5px; color: #fff; width: 50px; height: 20px; text-align: center; line-height: 20px; } </style> <body> <h1>新增学员</h1> <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表头包裹 tbody表格内容包裹 以后都这样写 --> <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) { // 阻止默认行为 不跳转 e.preventDefault() // 这里进行表单验证 如果不通过,直接中断,不需要添加数据 // 先遍历循环 for (let i = 0; i < items.length; i++) { if (items[i].value === '') { return alert('输入内容不能为空') } } // 2.创建新的对象 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) // 清空表单 reset重置 this.reset() // 调用渲染函数 render() }) // 2.渲染函数 因为增加和删除都需要渲染 function render() { // 先清空tbody以前的行,把最新数组里面的数据渲染完毕 tbody.innerHTML = '' // 遍历arr数组 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:" date-id=${i}>删除</a> </td> ` // 追加元素 父元素.appendChild(子元素) tbody.appendChild(tr) } } // 3.删除操作 // 3.1 事件委托 tbody tbody.addEventListener('click', function (e) { if (e.target.tagName === 'A') { // 自己的想法 不利用自定义属性 // arr.splice(e.target.stuId - 1, 1) // 得到当前元素的自定义属性 data-id // 删除arr数组对应的数据 arr.splice(e.target.dataset.id, 1) // 重新渲染 render() } }) </script> </body> </html>
5秒之后自动跳转页面
<body> <a href="http://www.itcast.cn">支付成功<span>5</span>秒钟之后跳转到首页</a> <script> // 1. 获取元素 const a = document.querySelector('a') // 2.开启定时器 // 3. 声明倒计时变量 let num = 5 let timerId = setInterval(function () { num-- a.innerHTML = `支付成功<span>${num}</span>秒钟之后跳转到首页` // 如果num === 0 则停止定时器,并且完成跳转功能 if (num === 0) { clearInterval(timerId) // 4. 跳转 location.href location.href = 'http://www.itcast.cn' } }, 1000) </script> </body>
学生就业统计表
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>js</title> </head> <style> * { margin: 0; padding: 0; } a { /* 颜色继承 */ color: #b70000; text-decoration: none; } h1, .info { text-align: center; margin: 30px 0; } table { margin: auto; width: 900px; /* 这个要写在table属性上 */ border-collapse: collapse; text-align: center; } tr:hover { background-color: #e0e0e0; } th, td { border: 1px solid #808080; height: 50px; } th { background-color: #D3E5FE; color: #334764; } td { color: #808080; } input, .city, .gender { /* margin: 10px; */ width: 80px; height: 20px; border: 1px solid #808080; border-radius: 5px; outline: none; text-align: center; line-height: 20px; } .title { display: flex; justify-content: end; box-sizing: border-box; width: 900px; background-color: #D3E5FE; height: 50px; margin: 5px auto; line-height: 50px; padding-right: 10px; } span { color: #ff4444; font-weight: 700; } .add { margin-left: 5px; background-color: #174188; /* outline: none; */ border: 0; border-radius: 5px; color: #fff; width: 50px; height: 20px; text-align: center; line-height: 20px; } </style> <body> <h1>学生就业统计表</h1> <form class="info" autocomplete="off"> <input type="text" class="uname" name="uname" placeholder="姓名" /> <input type="text" class="age" name="age" placeholder="年龄" /> <select name="gender" class="gender"> <option value="男">男</option> <option value="女">女</option> </select> <input type="text" class="salary" name="salary" placeholder="薪资" /> <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> <div class="title">共有几条数据<span>0</span>条</div> <table> <!-- thead表头包裹 tbody表格内容包裹 以后都这样写 --> <thead> <tr> <th>ID</th> <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> <script> const initData = [ { stuId: 1, uname: '迪丽热巴', age: 22, gender: '女', salary: '12000', city: '北京', time: '2099/9/9 08:08:08' } ] // 存储数据 转换为 json字符串 // 注意:本地存储存一次即可 这句话运行一遍之后一定要注释 // localStorage.setItem('data', JSON.stringify(initData)) // 1.渲染业务 // 1.1先读取本地存储的数据 // (1)本地存储有数据,要转化为对象,然后存储到变量中,用于后期渲染页面。 // (2)如果没有数据,用空数组代替 const arr = JSON.parse(localStorage.getItem('data')) || [] // console.log(arr) // 新思路:字符串的拼接,开发常用,效率高。 // 本案例利用 map()和join() 数组方法进行字符串的拼接,来提高效率。 // 1.2利用map和join方法渲染页面 const tbody = document.querySelector('tbody') function render() { // (1)map遍历数组处理数据生成tr数组 const trArr = arr.map(function (ele, index) { return ` <tr> <td>${ele.stuId}</td> <td>${ele.uname}</td> <td>${ele.age}</td> <td>${ele.gender}</td> <td>${ele.salary}</td> <td>${ele.city}</td> <td>${ele.time}</td> <td> <a href="javascript:" data-id='${index}'>删除</a> </td> </tr> ` }) // console.log(trArr) // (2)再用join将数组转换为字符串 // (3)把生成的字符串追加给tbody tbody.innerHTML = trArr.join('') // 显示共有几条数据 document.querySelector('.title span').innerHTML = arr.length } render() // 2.新增业务 // 2.1form表单注册提交事件,阻止默认行为 const info = document.querySelector('.info') const uname = document.querySelector('.uname') const age = document.querySelector('.age') const salary = document.querySelector('.salary') const city = document.querySelector('.city') const gender = document.querySelector('.gender') info.addEventListener('submit', function (e) { e.preventDefault() // 2.2非空判断 if (!uname.value || !age.value || !salary.value) { return alert('输入内容不能为空') } // 2.3 给arr数组追加对象,里面存储 表单获取过来的数据 arr.push({ stuId: arr.length ? arr[arr.length - 1].stuId + 1 : 1, uname: uname.value, age: age.value, gender: gender.value, salary: salary.value, city: city.value, time: new Date().toLocaleString() //可以显示'2099/9/9 08:08:08'这种格式 }) // 2.4渲染页面和重置表单(reset()方法) render() this.reset() //重置表单 // 3.5 把最新arr数组存入本地存储 localStorage.setItem('data', JSON.stringify(arr)) }) // 3.删除业务 // 3.1 采用事件委托形式,给tbody注册点击事件 tbody.addEventListener('click', function (e) { if (e.target.tagName === 'A') { // 3.2 得到当前点击的索引号。渲染数据时,动态给a链接添加自定义属性data-id console.log(e.target.dataset.id) // 确认框confirm 确认是否要真的删除 if (confirm('您确定要删除这条数据吗?')) { // 3.3 根据索引号,利用splice删除数组这条数据 arr.splice(e.target.dataset.id, 1) // 3.4 重新渲染页面 render() // 3.5 把最新arr数组存入本地存储 localStorage.setItem('data', JSON.stringify(arr)) } } }) </script> </body> </html>
用户名验证
<style> .error { color: red; background: url(images/error.png) no-repeat left center; } .right { color: green; background: url(images/right.png) no-repeat left center; } </style> <body> <input type="text"> <span></span> <script> // 1. 准备正则 const reg = /^[a-zA-Z0-9-_]{6,16}$/ const input = document.querySelector('input') const span = input.nextElementSibling input.addEventListener('blur', function () { // console.log(reg.test(this.value)) if (reg.test(this.value)) { span.innerHTML = '输入正确' //className可以覆盖类名 span.className = 'right' } else { span.innerHTML = '请输入6~16位的英文数字下划线' span.className = 'error' } }) </script> </body>
过滤敏感字
<body> <textarea name="" id="" cols="30" rows="10"></textarea> <button>发布</button> <div></div> <script> const tx = document.querySelector('textarea') const btn = document.querySelector('button') const div = document.querySelector('div') btn.addEventListener('click', function () { // console.log(tx.value) div.innerHTML = tx.value.replace(/激情|基情/g, '**') tx.value = '' }) </script> </body>
小兔鲜注册页面
<script> //立即执行函数 (function () { // 1.发送短信验证码模块 const code = document.querySelector('.code') let flag = true // 通过一个变量来控制 节流阀 // 1.1 点击事件 code.addEventListener('click', function () { if (flag) { // flag取反,不能第二次点击 flag = false let i = 5 code.innerHTML = `${i}秒后重新获取` let timerId = setInterval(function () { i-- // 这里不能用 this,定时器的调用者指向 window code.innerHTML = `${i}秒后重新获取` if (i === 0) { // 清除定时器 clearInterval(timerId) // 重新获取 code.innerHTML = `重新获取` // 到时间了,可以开启flag 即可以点击了 flag = true } }, 1000) } }) })(); // 2. 验证的是用户名 // 2.1 获取用户名表单 const username = document.querySelector('[name=username]') // 2.2 使用change事件 内容发生变化的时候触发change事件 username.addEventListener('change', verifyName) // 2.3 封装 verifyName 函数 function verifyName() { //这块必须用nextElementSibling 直接获取它的下一个兄弟 const span = username.nextElementSibling // 2.4 定义规则 用户名 const reg = /^[a-zA-Z0-9-_]{6,10}$/ if (!reg.test(username.value)) { span.innerText = '输入不合法,请输入6~10位' return false } // 2.5 合法的 清空span // 要写在上面 写在下面return结束函数,运行不到。 span.innerText = '' return true } // 3. 验证的是手机号 // 3.1 获取手机表单 const phone = document.querySelector('[name=phone]') // 3.2 使用change事件 值发生变化的时候 phone.addEventListener('change', verifyPhone) // 3.3 封装 verifyPhone 函数 function verifyPhone() { const span = phone.nextElementSibling // 3.4 定义规则 手机号 实际开发直接复制过来 const reg = /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/ if (!reg.test(phone.value)) { span.innerText = '输入不合法,请输入正确的11位手机号' return false } // 3.5 合法的 清空span span.innerText = '' return true } // 4. 验证的是验证码 // 4.1 获取验证码表单 const codeInput = document.querySelector('[name=code]') // 4.2 使用change事件 值发生变化的时候 codeInput.addEventListener('change', verifyCode) // 4.3 封装 verifyCode 函数 function verifyCode() { const span = codeInput.nextElementSibling // 4.4 定义规则 手机号 const reg = /^\d{6}$/ if (!reg.test(codeInput.value)) { span.innerText = '输入不合法,请输入6位数字' return false } // 4.5 合法的 清空span span.innerText = '' return true } // 5. 验证的是密码框 // 5.1 获取密码框表单 const password = document.querySelector('[name=password]') // 5.2 使用change事件 值发生变化的时候 password.addEventListener('change', verifyPwd) // 5.3 封装 verifyPwd 函数 function verifyPwd() { const span = password.nextElementSibling // 5.4 定义规则 手机号 const reg = /^[a-zA-Z0-9-_]{6,20}$/ if (!reg.test(password.value)) { span.innerText = '输入不合法,请输入6~20位数字' return false } // 5.5 合法的 清空span span.innerText = '' return true } // 6. 密码的再次验证 // 6.1 获取再次验证表单 const confirm = document.querySelector('[name=confirm]') // 6.2 使用change事件 值发生变化的时候 confirm.addEventListener('change', verifyConfirm) // 6.3 封装 verifyConfirm 函数 function verifyConfirm() { const span = confirm.nextElementSibling // 6.4 当前表单的值不等于密码框的值 就是错误的 if (confirm.value !== password.value) { span.innerText = '两次密码输入不一致' return false } // 6.5 合法的 清空span span.innerText = '' return true } // 7. 同意模块 const queren = document.querySelector('.icon-queren') queren.addEventListener('click', function () { // 切换类 toggle 原来有的就删除,没有的就添加。 this.classList.toggle('icon-queren2') }) // 8.表单提交模块 const form = document.querySelector('form') form.addEventListener('submit', function (e) { // 判断是否勾选同意模块 ,如果有 icon-queren2说明就勾选了,否则没勾选 //classList.contains()检查是否有这个类 if (!queren.classList.contains('icon-queren2')) { alert('请勾选同意协议') // return 中止程序,但不阻止提交 所以要阻止提交 e.preventDefault() } // 依次判断上面的每个框框是否通过,只有有一个没有通过就阻止 // 因为每一个都要判断 所以要分开写 如果用 || 只会显示第一个不通过的错误信息 if (!verifyName()) e.preventDefault() if (!verifyPhone()) e.preventDefault() if (!verifyCode()) e.preventDefault() if (!verifyPwd()) e.preventDefault() if (!verifyConfirm()) e.preventDefault() }) </script>
小兔鲜登录页面
<script> // 1. tab栏切换 事件委托 const tab_nav = document.querySelector('.tab-nav') const pane = document.querySelectorAll('.tab-pane') // 1.1 事件监听 tab_nav.addEventListener('click', function (e) { if (e.target.tagName === 'A') { // 取消上一个active tab_nav.querySelector('.active').classList.remove('active') // 当前元素添加active e.target.classList.add('active') // 先干掉所有人 for循环 for (let i = 0; i < pane.length; i++) { pane[i].style.display = 'none' } // 让对应序号的 pane 显示 pane[e.target.dataset.id].style.display = 'block' } }) // 点击提交模块 const form = document.querySelector('form') const agree = document.querySelector('[name=agree]') const username = document.querySelector('[name=username]') form.addEventListener('submit', function (e) { e.preventDefault() // 判断是否勾选同意协议 if (!agree.checked) { return alert('请勾选同意按钮') } // 记录用户名到本地存储 localStorage.setItem('xtx-uname', username.value) // 跳转到首页 location.href = './小兔鲜index.html' }) </script>
小兔鲜首页页面
<script> // 1. 获取第一个小li const li1 = document.querySelector('.xtx_navs li:first-child') const li2 = li1.nextElementSibling // 2.最好做个渲染函数 因为退出登录需要重新渲染 function render() { // 2.1 读取本地存储的用户名 const uname = localStorage.getItem('xtx-uname') // console.log(uname); if (uname) { li1.innerHTML = `<a href="javascript:;"><i class="iconfont icon-user"> ${uname}</i></a>` li2.innerHTML = `<a href="javascript:;">退出登录</a>` } else { li1.innerHTML = `<a href="./小兔鲜login.html">请先登录</a>` li2.innerHTML = `<a href="./小兔鲜register.html">免费注册</a>` } } render() // 调用函数 // 2.点击退出登录模块 li2.addEventListener('click', function () { // 删除本地存储的数据 localStorage.removeItem('xtx-uname') // 重新渲染 render() }) </script>
放大镜效果
<script> // 1. 获取三个盒子 // 2. 小盒子 图片切换效果 const small = document.querySelector('.small') // 中盒子 const middle = document.querySelector('.middle') // 大盒子 const large = document.querySelector('.large') // 2. 事件委托 // mouseenter 没有冒泡,因此不能实现事件委托,需要使用 mouseover 通过事件冒泡触发 small small.addEventListener('mouseover', function (e) { if (e.target.tagName === 'IMG') { // 排他思想 干掉以前的active this.querySelector('.active').classList.remove('active') // 当前元素的爸爸添加 active e.target.parentNode.classList.add('active') // 拿到当前小图片的src // 让中等盒子里面的图片,src更换为小图片的src middle.querySelector('img').src = e.target.src // 大盒子更换背景图片 large.style.backgroundImage = `url(${e.target.src})` } }) // 3.鼠标经过中等盒子,显示隐藏大盒子 middle.addEventListener('mouseenter', show) middle.addEventListener('mouseleave', hide) // 防止多次触发的时候显示不出来 timeId等于0也可以 let timeId = null // 显示函数 显示大盒子 function show() { // 先清除定时器 clearTimeout(timeId) large.style.display = 'block' } // 隐藏函数 隐藏大盒子 function hide() { timeId = setTimeout(function () { large.style.display = 'none' }, 200) } // 4.鼠标经过大盒子,显示隐藏大盒子 large.addEventListener('mouseenter', show) large.addEventListener('mouseleave', hide) // 5.鼠标经过中等盒子,显示隐藏 黑色遮罩层 const layer = document.querySelector('.layer') middle.addEventListener('mouseenter', function () { layer.style.display = 'block' }) middle.addEventListener('mouseleave', function () { layer.style.display = 'none' }) // 6.移动黑色遮罩盒子 middle.addEventListener('mousemove', function (e) { // 鼠标在middle 盒子里面的坐标 = 鼠标在页面中的坐标 - middle 中等盒子的坐标 // middle 中等盒子的坐标 使用 getBoundingClientRect() 来获取相当于可视区的盒子坐标,不用 offsetLeft 和 offsetTop,因为这两个属性容易被带有定位的父级影响 // 鼠标在页面中的坐标 // console.log(e.pageX); // middle 中等盒子的坐标 // console.log(middle.getBoundingClientRect().left); let x = e.pageX - middle.getBoundingClientRect().left - document.documentElement.scrollLeft let y = e.pageY - middle.getBoundingClientRect().top - document.documentElement.scrollTop // console.log(x, y); // 黑色遮罩移动在 middle 盒子内限制移动的距离 if (x >= 0 && x <= 400 && y >= 0 && y <= 400) { // 黑色盒子不是一直移动的 // 声明2个变量 黑色盒子移动的 mx my 变量 let mx = 0, my = 0 if (x < 100) mx = 0 if (x >= 100 && x <= 300) mx = x - 100 if (x > 300) mx = 200 if (y < 100) my = 0 if (y >= 100 && y <= 300) my = y - 100 if (y > 300) my = 200 layer.style.left = mx + 'px' layer.style.top = my + 'px' // 大盒子的背景图片要跟随中等盒子移动 存在的关系是 2倍 // 负的原因鼠标往右移动,图片应该往左走 large.style.backgroundPositionX = -2 * mx + 'px' large.style.backgroundPositionY = -2 * my + 'px' } }) </script>
// mouseenter 没有冒泡,因此不能实现事件委托,需要使用 mouseover 通过事件冒泡触发 small
small.addEventListener('mouseover', function (e) { if (e.target.tagName === 'IMG') { // 排他思想 干掉以前的active this.querySelector('.active').classList.remove('active') // 当前元素的爸爸添加 active e.target.parentNode.classList.add('active') // 拿到当前小图片的src // 让中等盒子里面的图片,src更换为小图片的src middle.querySelector('img').src = e.target.src // 大盒子更换背景图片 large.style.backgroundImage = `url(${e.target.src})` } }) // 3.鼠标经过中等盒子,显示隐藏大盒子 middle.addEventListener('mouseenter', show) middle.addEventListener('mouseleave', hide) // 防止多次触发的时候显示不出来 timeId等于0也可以 let timeId = null // 显示函数 显示大盒子 function show() { // 先清除定时器 clearTimeout(timeId) large.style.display = 'block' } // 隐藏函数 隐藏大盒子 function hide() { timeId = setTimeout(function () { large.style.display = 'none' }, 200) } // 4.鼠标经过大盒子,显示隐藏大盒子 large.addEventListener('mouseenter', show) large.addEventListener('mouseleave', hide) // 5.鼠标经过中等盒子,显示隐藏 黑色遮罩层 const layer = document.querySelector('.layer') middle.addEventListener('mouseenter', function () { layer.style.display = 'block' }) middle.addEventListener('mouseleave', function () { layer.style.display = 'none' }) // 6.移动黑色遮罩盒子 middle.addEventListener('mousemove', function (e) { // 鼠标在middle 盒子里面的坐标 = 鼠标在页面中的坐标 - middle 中等盒子的坐标 // middle 中等盒子的坐标 使用 getBoundingClientRect() 来获取相当于可视区的盒子坐标,不用 offsetLeft 和 offsetTop,因为这两个属性容易被带有定位的父级影响 // 鼠标在页面中的坐标 // console.log(e.pageX); // middle 中等盒子的坐标 // console.log(middle.getBoundingClientRect().left); let x = e.pageX - middle.getBoundingClientRect().left - document.documentElement.scrollLeft let y = e.pageY - middle.getBoundingClientRect().top - document.documentElement.scrollTop // console.log(x, y); // 黑色遮罩移动在 middle 盒子内限制移动的距离 if (x >= 0 && x <= 400 && y >= 0 && y <= 400) { // 黑色盒子不是一直移动的 // 声明2个变量 黑色盒子移动的 mx my 变量 let mx = 0, my = 0 if (x < 100) mx = 0 if (x >= 100 && x <= 300) mx = x - 100 if (x > 300) mx = 200 if (y < 100) my = 0 if (y >= 100 && y <= 300) my = y - 100 if (y > 300) my = 200 layer.style.left = mx + 'px' layer.style.top = my + 'px' // 大盒子的背景图片要跟随中等盒子移动 存在的关系是 2倍 // 负的原因鼠标往右移动,图片应该往左走 large.style.backgroundPositionX = -2 * mx + 'px' large.style.backgroundPositionY = -2 * my + 'px' } }) </script>