十、事件类型(鼠标事件、焦点.. 、键盘.. 、文本.. 、滚动..)、事件对象、事件流(事件捕获、事件冒泡、阻止冒泡和默认行为、事件委托)

1. 事件类型

1.1 鼠标事件

1.1.1 click 鼠标点击

1.1.2 mouseenter 鼠标进入

1.1.3 mouseleave 鼠标离开

<!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>.box {width: 200px;height: 200px;background-color: pink;}</style>
</head><body><div class="box">div 盒子</div><!-- 鼠标事件click 鼠标点击mouseenter 鼠标进入mouseleave 鼠标离开 --><script>const box = document.querySelector('.box')box.addEventListener('mouseenter', function () {console.log('mouseenter')})box.addEventListener('mouseleave', function () {console.log('mouseleave')})</script>
</body></html>

1.2 焦点事件

1.2.1 focus 获得焦点

1.2.2 blur 失去焦点

<!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>/* css选择器 → 属性选择器 */[type=text] {width: 245px;height: 50px;padding-left: 20px;border: 1px solid #ccc;font-size: 17px;outline: none;}</style>
</head><body><input type="text" class="inp1" value="原本value"><input type="text" class="inp2"><!-- 焦点事件focus 获得焦点blur 失去焦点--><script>const inp1 = document.querySelector('.inp1')const inp2 = document.querySelector('.inp2')inp1.addEventListener('focus', function () {console.log('focus')})inp1.addEventListener('blur', function () {console.log('blur')console.log(inp1.value)})</script>
</body></html>

案例1_小米搜索框显示隐藏案例

<!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>* {margin: 0;padding: 0;box-sizing: border-box;}ul {list-style: none;}.mi {position: relative;width: 223px;margin: 100px auto;}.mi .search-text {width: 223px;height: 48px;padding: 0 10px;font-size: 14px;line-height: 48px;border: 1px solid #e0e0e0;outline: none;}/* 搜索框边框颜色 */.mi .search {border: 1px solid #ff6700;}/* 下拉菜单 */.result-list {/* 先隐藏下拉菜单 */display: none;position: absolute;left: 0;top: 48px;width: 223px;border: 1px solid #ff6700;border-top: 0;background: #fff;}.result-list a {display: block;padding: 6px 15px;font-size: 12px;color: #424242;text-decoration: none;}.result-list a:hover {background-color: #eee;}</style></head><body><div class="mi"><input type="search" placeholder="小米笔记本" class="search-text"><ul class="result-list"><li><a href="#">全部商品</a></li><li><a href="#">小米11</a></li><li><a href="#">小米10S</a></li><li><a href="#">小米笔记本</a></li><li><a href="#">小米手机</a></li><li><a href="#">黑鲨4</a></li><li><a href="#">空调</a></li></ul></div><script>const searchText = document.querySelector('.search-text')const list = document.querySelector('.result-list')// 获得焦点:输入框的边框颜色变橙色search类;子菜单显示出来// display:none;none是隐藏;block(块级)searchText.addEventListener('focus', function () {this.classList.add('search')list.style.display = 'block'})// 失去焦点:输入框的边框颜色变灰色;子菜单隐藏起来searchText.addEventListener('blur', function () {this.classList.remove('search')list.style.display = 'none'})</script>
</body></html>

1.3 键盘事件

1.3.1 keydown 键盘按下

1.3.2 keyup 键盘抬起

1.4 文本事件 input

<!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>textarea {width: 300px;height: 30px;padding: 10px;border-color: transparent;outline: none;resize: none;background: #f5f5f5;border-radius: 4px;}</style>
</head><body><!-- input 不换行 --><textarea id="tx" placeholder="发一条友善的评论" rows="2"></textarea><!-- 键盘事件keydown 键盘按下keyup 键盘抬起文本事件 input 当表单value 被修改时触发执行顺序:keydown → input → keyup--><script>const tx = document.querySelector('#tx')tx.addEventListener('keydown', function () {console.log('键盘按下')})tx.addEventListener('input', function () {console.log('input')})tx.addEventListener('keyup', function () {console.log('键盘抬起')})</script>
</body></html>

案例2_统计用户输入字数

<!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>...</style>
</head><body><div class="wrapper"><i class="avatar"></i><!-- maxlength 输入的最大字符数 --><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">清风徐来</p><p class="text">大家都辛苦啦,感谢各位大大的努力,能圆满完成真是太好了[笑哭][支持]</p><p class="time">2099-10-10 20:29:21</p></div></div></div><!-- 统计用户输入字数需求:用户输入文字,可以计算用户输入的字数分析:①:文本域获得焦点则显示统计 total 盒子,失去焦点则隐藏统计 total 盒子②:文本域输入内容,使用input事件,不断取得字符长度(文本域.value.length )③:把获得字符长度赋值给 total 字数统计盒子--><script>const tx = document.querySelector('#tx')const total = document.querySelector('.total')tx.addEventListener('focus', function () {total.style.opacity = 1})tx.addEventListener('input', function () {let num = tx.value.lengthtotal.innerHTML = `${num}/200字`})tx.addEventListener('blur', function () {total.style.opacity = 0})</script>
</body></html>

1.5 滚动事件 scroll

<!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>body {height: 3000px;}a {position: fixed;right: 10px;bottom: 10px;}</style>
</head><body><a href="#">返回顶部</a><!-- 滚动事件scroll 当元素或页面滚动时触发 --><script>// 监听整个页面滚动,window.addEventListener('scroll', function () { })// (监听某个元素的内部滚动直接给某个元素加即可)window.addEventListener('scroll', function () {// document.documentElement 获取html元素// document.body 获取body元素// scrollTop 获取被卷入的头部 scrollTop和scrollLeft可读写console.log(document.documentElement.scrollTop)})const btn = document.querySelector('a')btn.addEventListener('click', function () {// 页面滚动是 html元素 滚动 document.documentElement.scrollTop = 0})</script>
</body></html>

案例3_xtx返回顶部

  <!-- 返回顶部 --><div class="xtx-elevator"><ul class="xtx-elevator-list"><li><a href="javascript:;" id="backTop"><i class="sprites"></i>顶部</a></li></ul></div><script>const elevator = document.querySelector('.xtx-elevator')html = document.documentElementwindow.addEventListener('scroll', function () {if (html.scrollTop >= 1000) {elevator.style.display = 'block'} else {elevator.style.display = 'none'}})elevator.addEventListener('click', function () {html.scrollTop = 0})</script>

2. 事件对象

<!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>.box {width: 200px;height: 200px;margin-bottom: 20px;background-color: pink;}textarea {width: 300px;height: 30px;padding: 10px;border-color: transparent;outline: none;resize: none;background: #f5f5f5;border-radius: 4px;}</style>
</head><body><div class="box"></div><textarea id="tx" placeholder="发一条友善的评论" rows="2"></textarea><!-- 事件对象:包含事件触发时的相关信息,包含属性和方法注册事件中,回调函数的第一个参数就是事件对象一般命名为event、ev、e--><!-- 事件对象-常见属性offsetX(number):事件发生时,鼠标相对于事件源的x坐标offsetY(number):事件发生时,鼠标相对于事件源的y坐标target(object):事件源对象key(string):如果是键盘相关事件,则事件对象中包含该属性,表示键盘事件发生时,按下的是什么键。'Enter'回车键--><script>const box = document.querySelector('.box')box.addEventListener('click', function (event) {console.log(event)})const tx = document.querySelector('#tx')tx.addEventListener('keydown', function (event) {console.log(event.key)})</script>
</body></html>

案例4_回车发布评论

<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">清风徐来</p><p class="text">大家都辛苦啦,感谢各位大大的努力,能圆满完成真是太好了[笑哭][支持]</p><p class="time">2099-10-10 20:29:21</p></div></div></div><!-- 需求:按下回车键,可以发布评论功能:①:按下回车,可以显示评论信息,并且评论内容显示到对应位置②:输入完毕,文本域清空内容,并且字数复原为 0--><script>const tx = document.querySelector('#tx')const list = document.querySelector('.list')const btn = document.querySelector('button')btn.addEventListener('click', function () {list.innerHTML = `<div class="item" style="display: flex;"><i class="avatar"></i><div class="info"><p class="name">清风徐来</p><p class="text">${tx.value}</p><p class="time">2099-10-10 20:29:21</p></div></div>`tx.value = ''})tx.addEventListener('keydown', function (e) {if (e.key === 'Enter') {btn.click()}})</script>
</body>

3. 事件流

3.1 事件捕获

3.2 事件冒泡

3.3 阻止冒泡

<!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>.father {margin: 100px auto;width: 300px;height: 300px;background-color: skyblue;}.son {margin: 80px auto;width: 100px;height: 100px;background-color: pink;}</style>
</head><body><div class="father">父盒子<div class="son">子盒子</div></div><!-- 事件流指的是事件完整执行过程中的流动路径,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段事件捕获:当一个元素的事件被触发时,会从DOM的根元素开始依次调用同名事件 (从外到里)addEventListener第三个参数传入 true 代表是捕获阶段触发(很少使用),若传入false代表冒泡阶段触发,默认就是 false事件冒泡: 当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。事件冒泡是默认存在的,实际工作都是使用事件冒泡为主(子到父)阻止冒泡:若想把事件就限制在当前元素内,就需要阻止事件冒泡事件对象.stopPropagation()--><script>const father = document.querySelector('.father')const son = document.querySelector('.son')document.body.addEventListener('click', function (event) {console.log('body')})father.addEventListener('click', function (event) {console.log('father')})son.addEventListener('click', function (event) {console.log('son')event.stopPropagation()})</script>
</body></html>

3.4 鼠标经过/离开事件的区别

<!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>.father {margin: 100px auto;width: 300px;height: 300px;background-color: skyblue;}.son {margin: 80px auto;width: 100px;height: 100px;background-color: pink;}</style>
</head><body><div class="father">父盒子<div class="son">子盒子</div></div><!-- mouseover 和 mouseout 会有冒泡mouseenter 和 mouseleave 没有冒泡 (常用)--><script>const father = document.querySelector('.father')const son = document.querySelector('.son')father.addEventListener('mouseenter', function (event) {console.log('father')})son.addEventListener('mouseenter', function (event) {console.log('son')})/* father.addEventListener('mouseover', function (event) {console.log('father')})son.addEventListener('mouseover', function (event) {console.log('son')}) */</script>
</body></html>

3.5 阻止默认行为

<!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><body><!-- form 表单区域 可以提交数据 action提交地址 --><form action="">姓名: <input type="text" name="username"><button>提交</button></form><a href="http://www.baidu.com">点击跳转</a><!-- 阻止默认行为:阻止元素发生默认的行为例如:当点击提交按钮时阻止对表单的提交,阻止链接的跳转等等 事件对象.preventDefault()--><script>const a = document.querySelector('a')a.addEventListener('click', function (e) {e.preventDefault()})// 表单的提交事件 → form submitconst form = document.querySelector('form')form.addEventListener('submit', function (e) {console.log('触发form')// 阻止默认行为e.preventDefault()})</script>
</body></html>

3.6 事件委托

<!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><link rel="stylesheet" href="./index.css"><script src="./data.js"></script>
</head><body><div class="container"><button type="button" class="btn add" id="btn-add"><span>添加员工</span></button><table class="order"><thead><tr><th>头像</th><th>姓名</th><th>工号</th><th>入职时间</th><th>操作</th></tr></thead><tbody><tr><td><span class="username">管</span></td><td>管理员</td><td>10000</td><td>2022-10-24</td><td><button class="btn edit">编辑</button><button class="btn del">删除</button></td></tr><tr><td><span class="username">孙</span></td><td>孙彩</td><td>10000</td><td>2022-09-24</td><td><button class="btn edit">编辑</button><button class="btn del">删除</button></td></tr><tr><td><span class="username">罗</span></td><td>罗晓晓</td><td>10002</td><td>2022-08-24</td><td><button class="btn edit">编辑</button><button class="btn del">删除</button></td></tr></tbody></table></div><!-- 事件委托(Event Delegation):也称为事件委派、事件代理将原本需要注册在子元素的事件委托给父元素,让父元素担当事件监听的职务优点:减少注册次数,可以提高程序性能; 动态生成的元素也能触发事件事件委托其实是利用事件冒泡的特点给父元素注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事件--><script>// 需求: 点击每个删除按钮,都会弹出询问框确认是否删除const tbody = document.querySelector('tbody')tbody.addEventListener('click', function (e) {// 事件对象.target.classList.contains() 可以判断真正触发事件的元素是否包含指定类名if (e.target.classList.contains('del')) {console.log('del')}if (e.target.classList.contains('edit')) {console.log('edit')}})// 新增功能(素材代码,课上无需实现,课上只需讲解事件委托代码即可)document.querySelector('#btn-add').addEventListener('click', function () {// 随机用户名const uname = createRandomName()// 随机工号const workNum = createWorkNum()// 新增一行内容tbody.innerHTML += `<tr><td><span class="username">${uname[0]}</span></td><td>${uname}</td><td>${workNum}</td><td>2021-03-13</td><td><button class="btn edit">编辑</button><button class="btn del">删除</button></td></tr>`})</script>
</body></html>

案例5_价格筛选

<!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>...</style>
</head><body><!-- 筛选链接 --><div class="filter"><a class="tab" data-index="1" href="javascript:;">0-100元</a><a class="tab" data-index="2" href="javascript:;">100-300元</a><a class="tab" data-index="3" href="javascript:;">300元以上</a><a class="tab" href="javascript:;">全部区间</a></div><!-- 渲染盒子 --><div class="list"><!-- <div class="item"><img src="" alt=""><p class="name"></p><p class="price"></p></div> --></div><script>// 初始化数据const goodsList = [{id: '4001172',name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',price: '289.00',picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',},]// 渲染商品列表function render(arr) {const str = arr.map(item => {const { name, price, picture } = itemreturn `<div class="item"><img src="${picture}" alt=""><p class="name">${name}</p><p class="price">${price}</p></div>`}).join('')document.querySelector('.list').innerHTML = str}render(goodsList)// 筛选功能const filter = document.querySelector('.filter')filter.addEventListener('click', function (e) {// console.log(e)// console.log(e.target)// console.log(e.target.dataset)let index = e.target.dataset.index// 0-100元if (index == 1) {// console.log(11)const newArr = goodsList.filter(el => {return el.price <= 100})render(newArr)} else if (index == 2) {const newArr = goodsList.filter(el => {return el.price <= 300})render(newArr)} else if (index == 3) {const newArr = goodsList.filter(el => {return el.price > 300})render(newArr)} else {render(goodsList)}})</script>
</body></html>

4. 移除事件监听

<!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><body><button class="L2">L2事件</button><button class="L0">L0事件</button><!-- 移除事件监听, 移除事件处理函数,也称为解绑事件--><!-- 两种注册事件的区别⚫ 传统on注册(L0)➢ 同一个对象,后面注册的事件会覆盖前面注册(同名事件)➢ 直接使用null覆盖偶就可以实现事件的解绑➢ 只有冒泡阶段,没有捕获阶段⚫ 事件监听注册(L2)➢ 语法: addEventListener(事件类型, 事件处理函数, 是否使用捕获)➢ 后面注册的事件不会覆盖前面注册的事件(同名事件)➢ 必须使用removeEventListener(事件类型, 事件处理函数, 获取捕获或者冒泡阶段)实现事件解绑➢ 可以通过第三个参数去确定是在冒泡或者捕获阶段执行➢ 匿名函数无法被解绑--><script>const L2 = document.querySelector('.L2')const L0 = document.querySelector('.L0')/* L2.addEventListener('click', function () {console.log('L2')}) *//* 移除L2事件监听addEventListener方式注册,必须使用:removeEventListener移除注意:匿名函数无法解绑*/function fn() {console.log('L2')}L2.addEventListener('click', fn)L2.removeEventListener('click', fn)/* 移除L0事件监听on事件方式,直接使用null覆盖偶就可以实现事件的解绑*/L0.onclick = function () {console.log('L0')}L0.onclick = null</script>
</body></html>

5. 作业

5.1 顺丰快递单号查询

<!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>Document</title><style>* {margin: 0;padding: 0;}.search {position: relative;width: 178px;margin: 100px;}.sf {height: 30px;padding-left: 10px;outline: none;}.con {display: none;position: absolute;top: -43px;min-width: 178px;max-width: 440px;/* 让连续的数字自动换行 */word-wrap: break-word;border: 1px solid rgba(0, 0, 0, .2);box-shadow: 0 2px 4px rgba(0, 0, 0, .2);padding: 5px;font-size: 18px;line-height: 20px;color: #333;}.con::before {content: '';width: 10px;height: 10px;position: absolute;top: 25px;left: 18px;border-left: 1px solid rgba(0, 0, 0, .2);border-bottom: 1px solid rgba(0, 0, 0, .2);background-color: #fff;transform: rotate(-45deg);}</style>
</head><body><div class="search"><div class="con"></div><input type="text" placeholder="请输入您的快递单号" class="sf"></div><!-- 需求如下:输入框获得焦点,如果没有值需要隐藏放大框输入框焦去焦点,隐藏放大框输入框中输入内容,没有值就隐藏放大框,有值就显示放大框,并将输入内容显示在放大框中--><script>const ipt = document.querySelector('.sf')const con = document.querySelector('.con')let num = 0ipt.addEventListener('focus', function () {// console.log(ipt.value)// if (this.value !== '') {if (num > 0) {con.style.display = 'block'}})ipt.addEventListener('blur', function () {con.style.display = 'none'})ipt.addEventListener('input', function () {num = ipt.value.lengthif (num > 0) {con.style.display = 'block'con.innerText = ipt.value} else {con.style.display = 'none'}})</script>
</body>

5.2 小米密码框

<!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>.mi-form {display: table;width: 356px;height: 60px;border-radius: 4px;border: 1px solid rgba(0, 0, 0, 0);background-color: #f9f9f9;}.mi-control {position: relative;display: table-cell;width: 294px;}.mi-input {box-sizing: border-box;width: 100%;height: 60px;border: 0;padding: 30px 20px 10px;outline: none;background: none;appearance: none;font-size: 17px;font-family: "Noto Color Emoji";color: #333;line-height: 20px;}.mi-control label {user-select: none;position: absolute;top: 20px;left: 20px;height: 20px;font-weight: 400;font-size: 17px;color: rgba(0, 0, 0, .4);line-height: 20px;transition: top .15s cubic-bezier(.4, 0, .2, 1), font-size .15s cubic-bezier(.4, 0, .2, 1), color .15s cubic-bezier(.4, 0, .2, 1);text-overflow: ellipsis;white-space: nowrap;overflow: hidden;}.mi-control label.active {top: 6px;font-size: 12px;color: #aaa;}.mi-password {display: table-cell;width: 60px;color: rgba(0, 0, 0, .85);font-size: 14px;vertical-align: middle;background: url(./images/close.png) center/30px 30px no-repeat;cursor: pointer;/* 防止选中文字 防止点击选中文本框的文字 */user-select: none;}.mi-password.active {background-image: url(./images/open.png);}</style>
</head><body><div class="mi-form"><div class="mi-control"><input type="password" class="mi-input"><label>密码</label></div><div class="mi-password"></div></div><!-- 输入框获得焦点,文字移动到输入框上面输入框失焦且输入框无内容,文字跑下来点击图标动态切换图标以及输入框的类型--><script>const ipt = document.querySelector('.mi-input')const label = document.querySelector('label')const password = document.querySelector('.mi-password')let pwClick = falseipt.addEventListener('focus', function () {label.classList.add('active')})ipt.addEventListener('blur', function () {if (ipt.value == '') {label.classList.remove('active')}})password.addEventListener('click', function () {pwClick = !pwClick/* if (pwClick) {ipt.type = 'text'this.style.backgroundImage = url('./images/close.png')} else {ipt.type = 'password'this.style.backgroundImage = url('./images/open.png')} */password.classList.toggle('active')ipt.type = pwClick ? 'text' : 'password'})</script>
</body></html>

5.3 掘金快捷导航

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><link rel="stylesheet" href="./fonts/iconfont.css"><style>* {margin: 0;padding: 0;box-sizing: border-box;}body {background-color: #f4f5f5;}ul {list-style: none;}nav {padding-top: 16px;padding-bottom: 24px;background: #3f7ef7;display: flex;align-items: center;justify-content: center;}nav .txt {background-color: #588ff8;padding: 0px 11px 0 4px;color: white;height: 26px;font-size: 14px;border-radius: 13px;margin: 0 5px;display: flex;align-items: center;justify-content: center;}.search {background-color: #3f7ef7;text-align: center;padding-top: 24px;margin: 0 auto;}.search-wrapper {margin: 0 auto;width: 40%;position: relative;}input {padding-left: 60px;width: 100%;height: 40px;border: none;outline: none;border-radius: 4px;}header {width: 1440px;height: 54px;margin: 0 auto;}header img {width: 1440px;height: 54px;display: block;}.web-icon {width: 28px;height: 28px;position: absolute;top: 6px;left: 6px;}.web-icon img {width: 100%;height: 100%;display: block;}.triangle {position: absolute;top: 12px;left: 38px;width: 16px;height: 16px;line-height: 16px;color: #c3c8d0;font-size: 12px;transition: all .3s;cursor: pointer;}.triangle.active {transform: rotate(180deg);}.txt .iconfont {width: 20px;height: 20px;border-radius: 10px;color: white;background-color: black;text-align: center;line-height: 20px;margin-right: 6px;}.icon-github {color: white;background-color: black;}.nav-list {width: 100%;margin-top: 10px;background-color: #fff;padding: 8px;border-radius: 4px;position: absolute;left: 0;top: 40px;display: none;}.nav-list.show {display: block;backdrop-filter: blur(20px);}.item {float: left;width: 90px;height: 90px;display: flex;flex-direction: column;justify-content: center;align-items: center;margin-right: 8px;margin-bottom: 8px;position: relative;}.item.checked::after {content: '✓';display: block;position: absolute;right: 2px;top: 2px;width: 14px;height: 14px;border-radius: 50%;background-color: #3f7ef7;color: white;font-size: 12px;}.item:hover {background-color: #eaf3fe;}.item:hover span {color: #3f7ef7;}.item.checked {background-color: #eaf3fe;color: #3f7ef7;}.item img {width: 36px;height: 36px;pointer-events: none;}.item span {font-size: 12px;margin-top: 8px;color: rgb(29, 33, 41);pointer-events: none;}</style>
</head><body><header><img src="./imgs/juejin.png" alt=""></header><div class="search"><div class="search-wrapper"><input type="text" id="ipt" placeholder="输入关键词 | tab键切换搜索引擎"><div class="web-icon"><img src="./imgs/chrome.png" class="curr-nav" alt=""></div><!-- 三角 --><span class="triangle iconfont icon-xiangxia"></span><ul class="nav-list"><li class="item checked" data-src="./imgs/chrome.png"><img src="./imgs/chrome.png" alt=""><span>谷歌</span></li><li class="item" data-src="./imgs/toutiao.png"><img src="./imgs/toutiao.png" alt=""><span>头条</span></li><li class="item" data-src="./imgs/baidu.png"><img src="./imgs/baidu.png" alt=""><span>百度</span></li><li class="item" data-src="./imgs/bing.png"><img src="./imgs/bing.png" alt=""><span>必应</span></li><li class="item" data-src="./imgs/github.png"><img src="./imgs/github.png" alt=""><span>github</span></li><li class="item" data-src="./imgs/npm.png"><img src="./imgs/npm.png" alt=""><span>npm</span></li><li class="item" data-src="./imgs/stack.png"><img src="./imgs/stack.png" alt=""><span>stack overflow</span></li></ul></div></div><nav><span class="txt"><span>+</span>xxx</span></nav><!-- 新增需求:点击某个导航选项,隐藏下拉导航列表,同时将当前展示的导航项切换成点击的导航项按tab键也能够切换当前的导航项,同时,如果下拉导航列表是显示状态,能看到选中的样式切换--><script>const triangle = document.querySelector('.triangle')const list = document.querySelector('.nav-list')const webIcon = document.querySelector('.web-icon')/* 在浏览器中,当HTML文档被加载时,所有带有id属性的元素会自动在全局作用域(通常是window对象)中创建一个对应的属性。这意味着,如果你有一个id为ipt的元素,理论上你可以通过window.ipt来访问这个元素。然而,这种做法并不推荐,因为它依赖于全局作用域,可能会导致命名冲突和代码难以维护。*/// const ipt = document.querySelector('#ipt')const items = document.querySelectorAll('.item')const currNav = document.querySelector('.curr-nav')triangle.addEventListener('click', function () {list.classList.toggle('show')triangle.classList.toggle('active')})list.addEventListener('click', function (e) {// 点到item才会触发界面变换if (e.target.classList.contains('item')) {// webIcon.innerHTML = `<img src="${e.target.dataset.src}" class="curr-nav" alt="">`currNav.src = e.target.dataset.srcdocument.querySelector('.checked')?.classList.remove('checked')e.target.classList.add('checked')list.classList.toggle('show')triangle.classList.toggle('active')}})/* 按tab键切换导航项核心思路:用一个变量记录导航索引位置并监听键盘按下事件,当键盘按下时,索引变量加1;当索引变量超出范围时,重置索引变量的值为02.1 定义变量记录当前展示导航的索引2.2 按键判断2.3 让input聚焦2.4 记录索引加12.5 边界判断2.6 更新导航图片2.7 修改导航列表中选中项的类名*/let num = 0/* ipt.addEventListener('keydown', function (e) {if (e.key == 'Enter') {// console.log(e.key)// console.log(items.length)// console.log(`num ${num}`)// num++ 先赋值再自增,增加数据未保存,num一直为0// num = num < items.length - 1 ? num++ : 0// ++num 可以成功实现// num = num < items.length - 1 ? ++num : 0num < items.length - 1 ? num += 1 : num = 0webIcon.innerHTML = `<img src="${items[num].dataset.src}" class="curr-nav" alt="">`document.querySelector('.checked')?.classList.remove('checked')items[num].classList.add('checked')// console.log(items[num])}}) */document.addEventListener('keydown', function (e) {if (e.key != 'Tab') return// 阻止默认行为e.preventDefault()// input 聚焦ipt.focus()num < items.length - 1 ? num += 1 : num = 0currNav.src = items[num].dataset.src// webIcon.innerHTML = `<img src="${items[num].dataset.src}" class="curr-nav" alt="">`document.querySelector('.checked')?.classList.remove('checked')items[num].classList.add('checked')})</script>
</body></html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/62181.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wireshark基础

免责声明&#xff1a; 笔记的只是方便各位师傅学习知识&#xff0c;以下代码、网站只涉及学习内容&#xff0c;其他的都与本人无关&#xff0c;切莫逾越法律红线&#xff0c;否则后果自负。 泷羽sec官网&#xff1a;https://longyusec.com/ 泷羽sec B站地址&#xff1a;https:/…

单例模式入门

单例模式是一种创建型设计模式&#xff0c; 让你能够保证一个类只有一个实例&#xff0c; 并提供一个访问该实例的全局节点。 它的运作方式是这样的&#xff1a; 如果你创建了一个对象&#xff0c; 同时过一会儿后你决定再创建一个新对象&#xff0c; 此时你会获得之前已创建的…

圆域函数的傅里叶变换和傅里叶逆变换

空域圆域函数的傅里叶变换 空域圆域函数&#xff08;也称为空间中的圆形区域函数&#xff09;通常指的是在二维空间中&#xff0c;以原点为中心、半径为 a a a的圆内取值为1&#xff0c;圆外取值为0的函数。这种函数可以表示为&#xff1a; f ( x , y ) { 1 if x 2 y 2 ≤ …

【大模型】深度解析 NLP 模型5大评估指标及 应用案例:从 BLEU、ROUGE、PPL 到METEOR、BERTScore

在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;无论是机器翻译、文本生成&#xff0c;还是问答系统开发&#xff0c;模型性能评估指标始终是开发者绕不开的工具。BLEU、ROUGE、PPL&#xff08;困惑度&#xff09;、METEOR 和 BERTScore 是五个最具代表性的指标&am…

黑马程序员Java项目实战《苍穹外卖》Day01

苍穹外卖-day01 课程内容 软件开发整体介绍苍穹外卖项目介绍开发环境搭建导入接口文档Swagger 项目整体效果展示&#xff1a; ​ 管理端-外卖商家使用 ​ 用户端-点餐用户使用 当我们完成该项目的学习&#xff0c;可以培养以下能力&#xff1a; 1. 软件开发整体介绍 作为一…

Java高级特性 - IO流

第1关 什么是IO流 BC,C 第2关 字节流-输入输出 第3关 字符流 - 输入输出 第4关 复制文件

BERT 详解

BERT简介 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;是由 Google 在 2018 年提出的一种预训练语言模型。BERT 在自然语言处理&#xff08;NLP&#xff09;领域取得了重大突破&#xff0c;因为它能够有效地捕捉文本的上下文信息&am…

LLM大模型意图识别:分类算法lora训练案例

参考&#xff1a; https://blog.csdn.net/weixin_42357472/article/details/141134380 &#xff08;LLaMA-Factory 微调训练&#xff09; https://modelscope.cn/competition/54/summary?seasonId56 https://github.com/coggle-club/notebooks/blob/main/notebooks/llm/RAG-BM…

(计算机网络)期末

计算机网络概述 物理层 信源就是发送方 信宿就是接收方 串行通信--一次只发一个单位的数据&#xff08;串行输入&#xff09; 并行通信--一次可以传输多个单位的数据 光纤--利用光的反射进行传输 传输之前&#xff0c;要对信源进行一个编码&#xff0c;收到信息之后要进行一个…

Rk3588 onnx转rknn,出现 No module named ‘rknn‘

一、操作步骤&#xff1a; rk3588 需要将yolo11 的模型onnx转rknn。 https://github.com/airockchip/rknn_model_zoo/tree/main/examples/yolo11 这个是用yolo11训练的模型&#xff0c;有80种类型。 完整下载下来后&#xff0c;在按文档描述下载模型下来&#xff1a; 然后进…

DDR3与MIG IP核详解(一)

一、ddr3(全称第三代双倍速率同步动态随机存储器)&#xff1a; 1、特点&#xff1a;1&#xff1a;掉电无法保存数据&#xff0c;需要周期性的刷新。2:时钟上升沿和下降沿都会传输数据。 3&#xff1a;突发传输&#xff0c;突发长度 Burst Length一般为…

多模态和大模型原理

一、图文匹配原理 Clip 通过图像编码器和照片编码器将两者区分成N项&#xff0c;然后让它们相互内积&#xff0c;能够匹配得上的则内积值为1&#xff0c;不能够匹配上的则内积为-1&#xff0c;也就是负样本&#xff0c;如上图&#xff0c;除了对角线的正样本&#xff0c;周围…

15 go语言(golang) - 并发编程goroutine原理及数据安全

底层原理 Go 的 goroutine 是一种轻量级的线程实现&#xff0c;允许我们在程序中并发地执行函数。与传统的操作系统线程相比&#xff0c;goroutine 更加高效和易于使用。 轻量级调度 用户态调度&#xff1a;Go 运行时提供了自己的调度器&#xff0c;这意味着 goroutine 的创建…

Flink细粒度的资源管理

Apache Flink致力于为所有应用程序自动导出合理的默认资源需求。对于希望根据其特定场景微调其资源消耗的用户,Flink提供了细粒度的资源管理。这里我们就来看下细粒度的资源管理如何使用。(注意该功能目前仅对DataStream API有用) 1. 适用场景 使用细粒度的资源管理的可能…

《操作系统 - 清华大学》5 -5:缺页异常

文章目录 1. 缺页异常的处理流程2.在何处保存未被映射的页&#xff1f;3. 虚拟内存性能 1. 缺页异常的处理流程 缺页中断的处理过程: CPU读内存单元&#xff0c;在TLB中根据其虚拟地址匹配物理地址&#xff0c;未命中&#xff0c;读页表; 由于页表项的存在位为0&#xff0c;CP…

Linux-NFS

文章目录 NASNFSNFS配置 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Linux专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月27日12点50分 NAS 网络接入存储 共享存储文件存储 NAS设备包括 NAS引擎一个或多个网络接口一个操作系统…

OpenHarmony属性信息怎么修改?触觉智能RK3566鸿蒙开发板来演示

本文介绍在开源鸿蒙OpenHarmony系统下&#xff0c;修改产品属性信息的方法&#xff0c;触觉智能Purple Pi OH鸿蒙开发板演示&#xff0c;搭载了瑞芯微RK3566四核处理器&#xff0c;Laval鸿蒙社区推荐开发板&#xff0c;已适配全新OpenHarmony5.0 Release系统&#xff0c;感兴趣…

杰发科技AC7803——不同晶振频率时钟的配置

计算公式 PLL_POSDIV [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62] PLL_PREDIV_1 1 2 4 USE_XTAL 24M SYSCLK_FREQ 64M SYSCLK_DIVIDER 1 VCO USE_XTAL*…

面向对象进阶-抽象类

抽象方法 将共性行为&#xff08;方法&#xff09;抽取到父类&#xff0c;由于每个子类执行内容不一样&#xff0c;在父类不能确定具体的方法体&#xff0c;该方法可以定义为抽象方法。 抽象类&#xff1a;如果一个类中存在抽象方法&#xff0c;那么该 类必须声明为抽象类。…

【数据结构专栏】二叉搜索树(Binary Search Tree)的剖析?

文章目录 &#x1f9e8;前言1、二叉搜索树的基本概念&#xff1f;2、二叉搜索树的节点结构组成&#xff1f;3、二叉搜索树的插入操作&#xff1f;4、二叉搜索树的删除操作&#xff1f;5、二叉搜索树的遍历&#xff1f;6、二叉搜索树的性能分析&#xff1f;&#x1f389;完整代码…