十二、正则表达式、元字符、替换修饰符、手势和对话框插件、字符串截取
1. 正则表达式
1.1 基本使用
<!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><!-- 正则表达式(Regular Expression)是一种字符串匹配的模式(规则)⚫ 使用场景:➢ 例如验证表单:手机号表单要求用户只能输入11位的数字 (匹配)➢ 过滤掉页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)--><script>// 1. 定义规则 其中/ /是正则表达式字面量;正则表达式也是对象const reg1 = /JS/const reg2 = new RegExp('JS')let str1 = 'JS学习'let str2 = 'TS学习'let str3 = '学习'// 2. 使用正则 test()方法 用来查看正则表达式与指定的字符串是否匹配,返回布尔型数据console.log(reg1.test(str1)) // trueconsole.log(reg1.test(str2)) // falseconsole.log(reg1.test(str3)) // falseconsole.log(reg2.test(str1)) // trueconsole.log(reg2.test(str2)) // falseconsole.log(reg2.test(str3)) // false</script>
</body></html>
1.2 元字符
1.2.1 边界符
<!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><!-- 普通字符:普通字符只能够匹配字符串中与它们相同的字符元字符(特殊字符):是一些具有特殊含义的字符,极大提高了灵活性和强大的匹配功能(边界符 量词 范围 字符类)--><!-- 边界符: 定义位置规则,必须用什么开头,用什么结尾^ 开始 ; $ 结束 ; ^和$在一起,表示必须是精确匹配--><script>const reg1 = /JS/const reg2 = /^JS/const reg3 = /JS$/const reg4 = /^JS$/let str1 = 'JS学习'let str2 = '学习JS'let str3 = 'JS'console.log(reg1.test(str1)) // trueconsole.log(reg2.test(str1)) // trueconsole.log(reg2.test(str2)) // falseconsole.log(reg3.test(str1)) // falseconsole.log(reg3.test(str2)) // trueconsole.log(reg4.test(str2)) // falseconsole.log(reg4.test(str3)) // true</script>
</body></html>
1.2.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>
</head><body><!-- 量词:用来设定某个模式重复次数 --><script>// 有开始结束,精确匹配// *:重复>=0 次const reg1 = /^钱*$/console.log(reg1.test('')) // tconsole.log(reg1.test('钱')) // tconsole.log(reg1.test('111')) // fconsole.log('-------------------')// +:重复>=1 次const reg2 = /^钱+$/console.log(reg2.test('')) // fconsole.log(reg2.test('钱')) // tconsole.log(reg2.test('钱钱')) // tconsole.log('-------------------')// ?:重复0次或1次const reg3 = /^钱?$/console.log(reg3.test('')) // tconsole.log(reg3.test('钱')) // tconsole.log(reg3.test('钱钱')) // fconsole.log('-------------------')// {n}:重复n次const reg4 = /^钱{3}$/console.log(reg4.test('钱钱')) // fconsole.log(reg4.test('钱钱钱')) // tconsole.log('-------------------')// {n,}:重复>=n 次const reg5 = /^钱{3,}$/console.log(reg5.test('钱钱')) // fconsole.log(reg5.test('钱钱钱')) // tconsole.log(reg5.test('钱钱钱钱')) // tconsole.log('-------------------')// {n,m}:重复n~m 次(包含n,m) 逗号左右两侧千万不要出现空格const reg6 = /^钱{3,5}$/console.log(reg6.test('钱钱')) // fconsole.log(reg6.test('钱钱钱')) // tconsole.log(reg6.test('钱钱钱钱钱')) // t</script>
</body></html>
1.2.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>
</head><body><!-- 范围:表示字符的范围,定义的规则限定在某个范围,比如只能是英文字母,或者数字等等,用 [] 表示范围[abc] 匹配包含的单个字符。也就是只有 a || b || c 这三个单字符返回true,可以理解为多选1[a-z] 连字符。来指定字符范围。[a-z] 表示 a 到 z 26个英文字母 [^abc] 取反符。[^a-z] 匹配除了小写字母以外的字符--><script>// 单个字符// 1. 多选1const reg1 = /[abc]/console.log(reg1.test('a')) // trueconsole.log(reg1.test('ac')) // trueconsole.log(reg1.test('cd')) // trueconsole.log(reg1.test('de')) // falseconsole.log('--------------')// 2. 连字符/* ➢ [a-z] 表示 a 到 z 26个英文字母都可以➢ [a-zA-Z] 表示大小写都可以➢ [0-9] 表示 0~9 的数字都可以*/const reg2 = /[a-f]/console.log(reg2.test('a')) // trueconsole.log(reg2.test('ac')) // trueconsole.log(reg2.test('ch')) // trueconsole.log(reg2.test('hj')) // falseconsole.log('--------------')// 3. 取反符const reg3 = /[^abc]/console.log(reg3.test('a')) // falseconsole.log(reg3.test('ac')) // falseconsole.log(reg3.test('cd')) // trueconsole.log(reg3.test('de')) // true</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>dt,dd {margin: 0;position: relative;}dl {display: flex;width: 600px;height: 30px;line-height: 30px;}dl dt {margin-right: 5px;}dl input {width: 269px;height: 28px;padding-left: 5px;border: 1px solid #ccc;outline: none;background: transparent;line-height: 30px;border-radius: 5px;}.tip {display: none;position: relative;width: 220px;height: 30px;margin-left: 15px;border: 1px solid #f59fb1;color: #d93c3c;text-align: center;font-size: 14px;background-color: #fff2f5;border-radius: 5px;}.tip::before {content: '';position: absolute;top: 50%;left: -6px;width: 10px;height: 10px;background-color: #fff2f5;border-left: 1px solid #f59fb1;border-bottom: 1px solid #f59fb1;transform: translateY(-50%) rotate(45deg);}span {position: absolute;top: 9px;right: 10px;width: 15px;height: 15px;}.right {background: url(./images/right.png) no-repeat;}.wrong {background: url(./images/error1.png) no-repeat;}</style>
</head><body><dl><dt>用户名:</dt><dd><input type="text" class="uname"><span></span></dd><dd class="tip">输入6~16位数字字母-_组成</dd></dl><!-- 用户名验证案例需求:用户名要求用户英文字母,数字,下划线或者短横线组成,并且用户名长度为 6~16 位 /^[a-zA-Z0-9_-]{6-16}$/--><script>const ipt = document.querySelector('.uname')const rORw = document.querySelector('span')const tip = document.querySelector('.tip')/* 拓展补充:➢ blur 事件:当元素失去焦点时触发(不论表单元素的值是否发生改变)➢ change 事件:元素失去焦点并且表单元素的值发生改变才会触发*/const reg = /^[a-zA-Z0-9-_]{6,16}$/ipt.addEventListener('change', function () {if (reg.test(this.value)) {/* rORw.classList.add('right')rORw.classList.remove('wrong') */// span只能有一个类名,right或wrong,直接className替换即可rORw.className = 'right'tip.style.display = 'none'} else {/* rORw.classList.remove('right')rORw.classList.add('wrong') */rORw.className = 'wrong'tip.style.display = 'block'}})</script>
</body></html>
1.2.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><!-- 字符类:某些常见模式的简写方式,区分字母和数字\d 匹配0-9之间的任一数字,相当于[0-9]\D 匹配所有0-9以外的字符,相当于[^0-9]\w 匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_]\W 除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_]\s 匹配空格(包括换行符、制表符、空格符等),相等于[\t\r\n\v\f]\S 匹配非空格的字符,相当于[^\t\r\n\v\f] --><script>// 日期格式(简易 不规范)const reg = /^\d{4}-\d{1,2}-\d{1,2}$/console.log(reg.test('2024-11-26')) // trueconsole.log(reg.test('2025-1-1')) // true</script>
</body></html>
1.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>
</head><body><!-- 替换和修饰符replace 替换方法,可以完成字符的替换字符串.replace(/正则表达式/, '替换的文本')修饰符约束正则执行的某些细节行为,如是否区分大小写、是否支持多行匹配等/表达式/修饰符➢ i 是单词 ignore 的缩写,正则匹配时字母不区分大小写➢ g 是单词 global 的缩写,匹配所有满足正则表达式的结果--><script>const str = '欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'// 懒惰模式(默认),只匹配第一个,后面忽略const newStr1 = str.replace(/前端/, '鸿蒙')// replace 返回一个新的字符串,不修改原字符串console.log(str) // 欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神console.log(newStr1) // 欢迎大家学习鸿蒙,相信大家一定能学好前端,都成为前端大神// g 匹配所有满足正则表达式的结果const newStr2 = str.replace(/前端/g, '鸿蒙')console.log(newStr2) // 欢迎大家学习鸿蒙,相信大家一定能学好鸿蒙,都成为鸿蒙大神</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>.wrapper {width: 840px;height: 420px;background: url(./images/bg01.jpg) no-repeat center / cover;padding: 100px 250px;box-sizing: border-box;}.wrapper strong {font-size: 50px;}.wrapper span {color: #b10e0d;}</style>
</head><body><div class="wrapper"><strong>年会抽奖</strong><h1>获奖手机号:<span class="phone">???</span></h1></div><!-- 隐藏手机号中间四位案例 --><script>let tel = '13866668888'// 把手机号利用正则利用小括号划分为三部分const reg = /^(\d{3})(\d{4})(\d{4})$/// 在replace中,$1 对应第一个小括号内容,依次类推let str1 = tel.replace(reg, '$1****$3')// ${} -- 模板字符串${变量或表达式}// 字符串重复使用:字符串.repeat(次数) 实现let str2 = tel.replace(reg, `$1${'*'.repeat(4)}$3`)document.querySelector('.phone').innerHTML = str1</script>
</body></html>
2. JS插件
2.1 AlloyFinger 手势插件
<!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>AlloyFinger手势插件</title><style>.nav {width: 200px;height: 40px;border: 3px solid pink;}.item {width: 250px;height: 40px;line-height: 40px;background-color: skyblue;transition: all .3s;}.active {transform: translateX(-50px);}</style>
</head><body><div class="nav"><div class="item">AlloyFinger是腾讯AlloyTeam 开发</div></div><!-- AlloyFinger 是腾讯 AlloyTeam 团队开源的超轻量级 Web 手势插件,为元素注册各种手势事件 --><!-- 将AlloyFinger库引入当前文件 --><!-- 配置new AlloyFinger(element, { // element 是给哪个元素做滑动事件swipe: function (e) {// 滑动的时候要做的事情 e.direction 可以判断上下左右滑动 Left Right 等}})--><script src="./alloy_finger.js"></script><script>const item = document.querySelector('.item')new AlloyFinger(item, {swipe: function (e) {if (e.direction === 'Left') {item.classList.add('active')} else if (e.direction === 'Right') {item.classList.remove('active')}},// 手指触摸touchStart: function () {console.log('touchStart')},// 手指移动touchMove: function () {console.log('touchMove')},// 手指移开touchEnd: function () {console.log('touchEnd')}})</script>
</body></html>
2.2 M端事件
<!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: 300px;height: 300px;background-color: pink;}</style>
</head><body><div class="box"></div><!-- M端(移动端)有自己独特的地方。比如触屏事件 touch(也称触摸事件)。touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。触屏touch事件touchstart 手指触摸到一个DOM元素时触发touchmove 手指在一个DOM元素上滑动时触发touchend 手指从一个DOM元素上移开时触发--><script>const box = document.querySelector('.box')box.addEventListener('touchstart', function () {console.log('touchstart')})box.addEventListener('touchmove', function () {console.log('touchmove')})box.addEventListener('touchend', function () {console.log('touchend')})</script>
</body></html>
2.3 a11y-dialog 对话框插件
<body><!-- 按钮 --><div class="btns"><button class="btn btn1">添加</button></div><!-- a11y --><!-- 1. 准备对话框容器 --><div class="dialog-container" id="dialog" aria-hidden="true"><!-- 2. 底部蒙层 --><div class="dialog-overlay" data-a11y-dialog-hide></div><!-- 3. 对话框结构 --><div class="dialog-content"><!-- 4. 关闭按钮 --><button type="button" class="dialog-close" data-a11y-dialog-hide>×</button><!-- 5. 标题 --><h1>测试对话框</h1><!-- 6. 内容 --><p>好看的对话框</p></div></div><!-- <script src="https://cdn.jsdelivr.net/npm/a11y-dialog@8/dist/a11y-dialog.min.js"></script> --><script src="./a11y-dialog.js"></script><script>const btn1 = document.querySelector('.btn1')// 获取对话框DOM容器const element = document.querySelector('#dialog')// 实例化对话框const dialog = new A11yDialog(element)btn1.addEventListener('click', function () {// 实例对话框调用 show 方法可以显示对话框dialog.show()})</script>
</body>
3. 字符串截取
<script>const str = '我们都是前端大神啊'// 字符串截取// 1. substring// 最后一个字符console.log(str.substring(str.length - 1)) // 啊// 第一个字符console.log(str.substring(0, 1)) // 我// 2. str[] 字符串也有索引,console.log(str[0]) // 我</script>
4. 综合案例_移动端通讯录
<!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="./iconfont/iconfont.css" /><link rel="stylesheet" href="./index.css" />
</head><body><div class="address-header">通讯录<i class="iconfont icon-tianjiayonghu"></i></div><div class="address-book"><!-- 添加item 核心区域--><!-- <div class="item"><p class="circle">华</p><p class="name">刘德华</p><p class="tel">15300588305</p><a class="del" href="javascript:;"><i class="iconfont icon-shanchutianchong" data-index="0"></i></a></div> --></div><button id="add" class="btn-add">添加联系人</button><!-- 模态框-添加联系人 --><div class="dialog-container" id="modal" aria-hidden="true" aria-labelledby="my-dialog-title"aria-describedby="my-dialog-description"><div class="dialog-overlay" data-a11y-dialog-hide></div><div class="dialog-content" role="document"><h1 id="my-dialog-title" class="title">添加联系人<button type="button" aria-label="Close this dialog window" class="el-dialog__headerbtn dialog-close"data-a11y-dialog-hide>取消</button></h1><!-- 联系人表单 --><div class="address-footer"><input id="name" type="text" placeholder="请输入姓名" /><input id="tel" type="text" placeholder="请输入手机号" /><button class="btn-ok" id="btnOK">确认</button></div></div></div><!-- 引入手势插件 --><script src="./js/alloy_finger.js"></script><!-- 引入弹窗插件 --><script src="./js/a11y-dialog.js"></script><script>// 本地存储let arr = JSON.parse(localStorage.getItem('contacts')) || []// 初始化数据/* let arr = [{ name: '周杰伦', tel: '13411112222' },{ name: '刘德华', tel: '13511112222' },{ name: '张学友', tel: '13711112222' },{ name: '岳云鹏', tel: '13911112222' },{ name: '迪丽热巴', tel: '13911112222' }] */const addressBook = document.querySelector('.address-book')// 渲染业务function render(data = arr) {let str = data.map((item, index) => {const { name, tel } = itemreturn `<div class="item"><p class="circle">${name.substring(name.length - 1)}</p><p class="name">${name}</p><p class="tel">${tel}</p><a class="del" href="javascript:;"><i class="iconfont icon-shanchutianchong" data-index="${index}"></i></a></div>`}).join('')addressBook.innerHTML = str/* 调用滑动功能每次 render 函数被调用后都会被执行,确保对新生成的 .item 元素进行了正确的事件绑定。 */swipe()}render()// 滑动业务// 滑动业务事件委托做不了,e.target值不确定 p div? --> forEach做// 要在渲染的时候准备好滑动功能等待用户滑动 -- 定义滑动函数,渲染函数中调用function swipe() {// forEach 遍历添加事件监听// 获取items元素若放到顶部,此时render函数未调用,HTML未填充item元素,获取元素失败 --> 滑动功能实现失败const items = document.querySelectorAll('.address-book .item')items.forEach(item => {new AlloyFinger(item, {swipe: function (e) {// console.log(e)if (e.direction === 'Left') {// 排他// 1. 页面打开默认有自带active类名,下行代码可行;默认无active找不到元素返回为空,控制台classList报错// document.querySelector('.address-book .active').classList.remove('active')// 2. css选择器书写错误 item和active同级类名,找不到item下的active符合条件的元素// document.querySelector('.item .active')?.classList.remove('active')const active = document.querySelector('.address-book .active')// 3.1 正确写法一 if判断/* if (active) {active.classList.remove('active')} */// 3.2 正确写法二 ?可选// active?.classList.remove('active')// 3.3 正确写法三 逻辑中断active && active.classList.remove('active')item.classList.add('active')} else if (e.direction === 'Right') {item.classList.remove('active')}}})})}// 删除业务 事件委托addressBook.addEventListener('click', function (e) {// console.log(e.target.dataset.index)if (e.target.classList.contains('icon-shanchutianchong')) {// confirm() 弹窗 返回值为布尔型let isDel = confirm('确定要删除嘛?')if (isDel) {arr.splice(e.target.dataset.index, 1)localStorage.setItem('contacts', JSON.stringify(arr))render()} else {document.querySelector('.active').classList.remove('active')}}})// 新增业务const btnAdd = document.querySelector('.btn-add')// 获取对话框DOM容器const modal = document.querySelector('#modal')// 实例化对话框const dialog = new A11yDialog(modal)btnAdd.addEventListener('click', function () {dialog.show()})const btnOK = document.querySelector('#btnOK')const uname = document.querySelector('#name')const tel = document.querySelector('#tel')btnOK.addEventListener('click', function () {// 验证数据合法?let unameReg = /^(?:[\u4e00-\u9fa5·]{2,16})$/let telReg = /^(?:(?:\+|00)86)?1[3-9]\d{9}$/let addName = uname.valuelet addTel = tel.valueif (!addName.trim() || !addTel.trim()) {alert('不能为空')return}if (!unameReg.test(addName)) {alert('姓名输入错误')return}if (!telReg.test(addTel)) {alert('电话输入错误')return}arr.unshift({ name: addName, tel: addTel })localStorage.setItem('contacts', JSON.stringify(arr))render()// 关闭添加联系人页面dialog.hide()uname.value = ''tel.value = ''})</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"><title>Document</title><link rel="stylesheet" href="index.css"></head><body><header><h1><img src="https://bm.ruankao.org.cn/asset/image/public/logo.png" alt=""><span>全国计算机技术与软件专业技术资格(水平)考试</span><span class="address">当前考区:北京</span></h1><div><span class="hello">xxx,您好!</span></div></header><main><section><h3>基本信息</h3><form action="#"><div class="form-item is-required"><label for="username">姓名:</label><div class="form-item-content"><input class="hm-input" type="text" id="username"><!-- <div class="form-error hide">用户名校验不通过,请输入1-4位的汉字</div> --><div class="form-error">用户名校验不通过,请输入1-4位的汉字</div></div></div><div class="form-item is-required"><label for="idcard">身份证:</label><div class="form-item-content"><input class="hm-input" type="text" id="idcard"><!-- <div class="form-error hide">请输入合法的身份证格式</div> --><div class="form-error">请输入合法的身份证格式</div></div></div><div class="form-item is-required"><label for="age">年龄:</label><div class="form-item-content"><input class="hm-input" type="text" id="age"><!-- <div class="form-error hide">请输入数字</div> --><div class="form-error">请输入数字</div></div></div><div class="form-item is-required"><label for="mobile">手机号:</label><div class="form-item-content"><input class="hm-input" type="text" id="mobile"><!-- <div class="form-error hide">请输入合法的手机号</div> --><div class="form-error">请输入合法的手机号</div></div></div><button class="submit">提交</button></form></section></main><!-- 需求如下:点击提交时,对表单进行数据格式校验:校验不通过,显示错误提示校验通过,跳转到成功页面--><script>const form = document.querySelector('form')const username = document.querySelector('#username')const idcard = document.querySelector('#idcard')const age = document.querySelector('#age')const mobile = document.querySelector('#mobile')// 正则const regUsername = /^(?:[\u4e00-\u9fa5]{1,4})$/const regIdcard = /^\d{6}((((((19|20)\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(((19|20)\d{2})(0[13578]|1[02])31)|((19|20)\d{2})02(0[1-9]|1\d|2[0-8])|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))0229))\d{3})|((((\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|((\d{2})(0[13578]|1[02])31)|((\d{2})02(0[1-9]|1\d|2[0-8]))|(([13579][26]|[2468][048]|0[048])0229))\d{2}))(\d|X|x)$/const regAge = /^\d{1,2}$/const regMobile = /^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[1589]))\d{8}$/function REG(reg, el) {return reg.test(el.trim())}/* console.log(REG(regUsername, '小红')) // tconsole.log(REG(regUsername, '红')) // tconsole.log(REG(regUsername, '12352')) // f */form.addEventListener('submit', function (e) {if (REG(regUsername, username.value)) {// nextElementSibling 获取节点的下一个兄弟节点username.nextElementSibling.classList.add('hide')}if (REG(regIdcard, idcard.value)) {idcard.nextElementSibling.classList.add('hide')}if (REG(regAge, age.value)) {age.nextElementSibling.classList.add('hide')}if (REG(regMobile, mobile.value)) {mobile.nextElementSibling.classList.add('hide')}// console.log(document.querySelectorAll('.hide'))// console.log(document.querySelectorAll('.hide').length) // '4'// console.log(document.querySelectorAll('.hide').length == '4')// 阻止表单默认行为e.preventDefault()if (document.querySelectorAll('.hide').length == '4') {// console.log('success')location.href = './success.html'}})</script>
</body></html>
5.2 仿outlook邮箱
<!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="./index.css"><link rel="stylesheet" href="./fonts/iconfont.css">
</head><body><header><span class="iconfont icon-hanbaobao"></span><span>收件箱</span><img src="./imgs/default-avatar.png" alt=""></header><ul class="mail-list"><!-- <li class="unread"><div class="group"><div class="status">标记已读</div><article><img src="./imgs/default-avatar.png" alt=""><div class="mail-info"><div><span class="from">Jack</span><time>2023/10/1</time></div><p>您好, 您之所以会收到此邮件,是因为我们正在更新 Microsoft 服务协议,该协议适用于您所使用的一个或多个 Microsoft产品或服务。我们之所以进行这些更新,是为了阐明我们的条款并确保这些条款仍对您保持透明。</p></div></article></div></li> --></ul><!-- <script src="https://unpkg.com/alloyfinger@0.1.16/alloy_finger.js"></script> --><script src="../alloy_finger.js"></script><script src="data.js"></script><script>const list = document.querySelector(".mail-list")function render(data = mails) {let str = data.map((el, index) => {const {from: { username, avatar },time,content,readStatus,} = elreturn `<li class="unread"><div class="group"><div class="status">标记已读</div><article><img src="${avatar}" alt=""><div class="mail-info"><div><span class="from">${username}</span><time>${time}</time></div><p>${content}/p></div></article></div></li>`}).join("")list.innerHTML = strswipefn()}render()// 滑动发生时 内容内标签变化 需再次渲染可实现滑动 封装滑动功能函数 渲染函数内调用function swipefn() {// 新增需求:向右滑动,出现操作区块,点击可修改邮件的阅读状态const lis = document.querySelectorAll(".mail-list li")// previousElementSibling 上一个兄弟节点lis.forEach((item) => {console.log(item.tagName) // LI// 查找子节点的子节点const status = item.children[0].children[0]// console.log(status)new AlloyFinger(item, {// swipe: function (e) {// console.log(e.target)if (e.direction === "Right") {item.classList.toggle('active')item.classList.contains('read')? status.innerHTML = '标记未读': status.innerHTML = '标记已读'}},touchStart: function (e) {if (e.target.classList.contains('status')) {item.classList.toggle('active')item.classList.toggle('read')status.innerHTML = '标记未读'}}})})}</script>
</body></html>
相关文章:
十二、正则表达式、元字符、替换修饰符、手势和对话框插件、字符串截取
1. 正则表达式 1.1 基本使用 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title&g…...
【信息系统项目管理师】第3章:信息系统治理 考点梳理
文章目录 3.1 IT 治理3.1.1 IT治理基础3.1.2 IT治理体系3.1.3 IT治理任务3.1.4 IT治理方法与标准 3.2 IT 审计3.2.1 IT审计基础3.2.2 审计方法与技术3.2.3 审计流程3.2.4 审计内容 3.1 IT 治理 IT治理起到重要的统筹、评估、指导和监督作用。 信息技术审计(IT审计)作为与IT治…...
实现对图片或者视频增加隐藏水印和提取水印
好久好久没有写博客了,最近看见一个很有意思的文章:小心你的电脑被窃听,就是说在一些公司,截图都会存在水印,方便溯源,然后出于技术的好奇,我在github上搜了一下,还真有相关的github…...
uniapp配置全局消息提醒
1.H5使用根标签插入dom的方式实现。 2.app端使用plus.nativeObj.View的方式绘制实现 H5端app端 H5端 创建组件orderAlert.vue <template><div class"view"><div class"content" v-if"visible"><div class"message&q…...
卸载snap docker一直卡住:Save data of snap “docker“ in automatic snapshot set #3
在卸载 Snap 安装的 Docker 时卡住,通常是因为 Snap 在执行卸载时会先尝试保存一些快照(自动或手动创建的),并且该过程可能因某些原因而卡住。为了解决这个问题,你可以按照以下步骤强制删除 Snap 安装的 Docker&#x…...
python学习——字典元素的访问和遍历
在Python中,访问和遍历字典元素的方法如下: 文章目录 访问字典元素1. 使用键来访问值2. 使用 get() 方法 遍历字典元素1. 遍历字典的键2. 遍历字典的值3. 遍历字典的键和值4. 使用列表推导式来创建新的列表 实操 访问字典元素 1. 使用键来访问值 # 创…...
数据结构基础之《(9)—归并排序》
一、什么是归并排序 1、整体是递归,左边排好序右边排好序merge让整体有序 2、让其整体有序的过程里用了排外序方法 3、利用master公式来求解时间复杂度 4、当然可以用非递归实现 二、归并排序说明 1、首先有一个f函数 void f(arr, L, R) 说明:在arr上…...
【深度学习】各种卷积—卷积、反卷积、空洞卷积、可分离卷积、分组卷积
在全连接神经网络中,每个神经元都和上一层的所有神经元彼此连接,这会导致网络的参数量非常大,难以实现复杂数据的处理。为了改善这种情况,卷积神经网络应运而生。 一、卷积 在信号处理中,卷积被定义为一个函数经过翻转…...
远程视频验证如何改变商业安全
如今,商业企业面临着无数的安全挑战。尽管企业的形态和规模各不相同——从餐厅、店面和办公楼到工业地产和购物中心——但诸如入室盗窃、盗窃、破坏和人身攻击等威胁让安全主管时刻保持警惕。 虽然传统的监控摄像头网络帮助组织扩大了其态势感知能力,但…...
电脑启动需要经历哪些过程?
传统BIOS启动流程 1. BIOS BIOS 启动,BIOS程序是烧进主板自带的ROM里的,所以无硬盘也可以启动。BIOS先进行自检,检查内存、显卡、磁盘等关键设备是否存在功能异常,会有蜂鸣器汇报错误,无错误自检飞快结束。 硬件自检…...
纯Go语言开发人脸检测、瞳孔/眼睛定位与面部特征检测插件-助力GoFly快速开发框架
前言 开发纯go插件的原因是因为目前 Go 生态系统中几乎所有现有的人脸检测解决方案都是纯粹绑定到一些 C/C 库,如 OpenCV 或 dlib,但通过 cgo 调用 C 程序会引入巨大的延迟,并在性能方面产生显著的权衡。…...
postman使用正则表达式提取数据实战篇!
之前篇章中postman多接口关联使用的是通过JSON提取器的方式进行提取。 除了JSON提取器提取数据外还可通过另一种方式——正则表达式来提取数据。 1、使用正则表达式提取器实现接口关联,match匹配 正则匹配表达式将需要提取的字段key:value都放入表达式中ÿ…...
ipmitool使用详解(三)-解决各种dell、hp服务器无法ipmitool连接问题
报错 [root@localhost ~]# ipmitool -H 10.1.2.41 -I lan -U admin -P "password123" lan print 1 Get Session Challenge command failed Error: Unable to establish LAN session Error: Unable to establish IPMI v1.5 / RMCP session [root@localhost ~]# ipmit…...
AWS EC2设置用户名密码登录
使用AWS EC2 设置用户名密码登录 步骤 1: 访问控制台 登录到AWS管理控制台。导航至 EC2 Dashboard。在左侧导航栏中选择 Instances。选择需要配置的实例。使用 EC2 Instance Connect 访问实例控制台。 步骤 2: 切换到 root 用户 打开终端或命令行工具,通过SSH连…...
BurpSuite安装教程(详细!!附带下载链接)
声明 学习内容来自 B 站UP主泷羽sec,如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负。 ✍🏻作者简介:致…...
MIPS寄存器文件设计实验
今天写MIPS寄存器文件设计实验,同时复习一下MIPS这块地方 实验要求: 一、寄存器的作用 想象一下,你正在厨房准备做一顿大餐。你需要用到各种食材和工具,比如刀、锅、砧板,还有食材本身,比如肉、菜、调料等…...
uniapp使用扩展组件uni-data-select出现的问题汇总
前言 不知道大家有没有学习过我的这门课程那,《uniCloud云开发Vue3版本官方推荐用法》,这么课程已经得到了官方推荐,想要快速上手unicloud的小伙伴们,可以学习一下这么课程哦,不要忘了给一键三连呀。 在录制这门课程…...
反向代理模块开发
1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求,然后将请求转发给内部网络上的服务器,将从服务器上得到的结果返回给客户端,此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说,反向代理就相当于…...
海康面阵、线阵、读码器及3D相机接线说明
为帮助用户快速了解和配置海康系列设备的接线方式,本文将针对海康面阵相机、线阵相机、读码器和3D相机的主要接口及接线方法进行全面整理和说明。 一、海康面阵相机接线说明 海康面阵相机使用6-pin P7接口,其功能设计包括电源输入、光耦隔离信号输入输出…...
AI与ArcGIS Pro的地理空间分析和可视化
AI思维已经成为一种必备的能力,ArcGIS Pro3的卓越性能与ChatGPT的智能交互相结合,将会为您打造了一个全新的工作流程! 那么如何将火热的ChatGPT与ArcGIS Pro3相结合,使我们无需自己进行复杂的编程,通过强大的ChatGPT辅助我们完成地…...
详解HTML5语言
文章目录 前言任务一 认识HTML5任务描述:知识一 HTML5基础知识 任务二 HTML 5语义元素任务描述:知识一 HTML5新增结构元素知识二 HTML5文本语义元素 总结 前言 HTML5是一个新的网络标准,现在仍处于发展阶段。目标是取代现有的HTML 4.01和XHT…...
docker compose一键启动ES集群和kibana
集群启用了XPACK后,只有第一次可以启动成功。要是宕机了。就启动不了了。(除非删除data目录所有数据)生产环境 启用了后 建议配置 自定义证书。 services:es01:image: "docker.elastic.co/elasticsearch/elasticsearch:7.17.25"co…...
遗传算法与深度学习实战(25)——使用Keras构建卷积神经网络
遗传算法与深度学习实战(25)——使用Keras构建卷积神经网络 0. 前言1. 卷积神经网络基本概念1.1 卷积1.2 步幅1.3 填充1.4 激活函数1.5 池化 2. 使用 Keras 构建卷积神经网络3. CNN 层的问题4. 模型泛化小结系列链接 0. 前言 卷积神经网络 (Convolution…...
pytest+allure生成报告显示loading和404
pytestallure执行测试脚本后,通常会在电脑的磁盘上建立一个临时文件夹,里面存放allure测试报告,但是这个测试报告index.html文件单独去打开,却显示loading和404, 这个时候就要用一些办法来解决这个报告显示的问题了。 用命令产生…...
为何划分 Vue 项目结构组件?划分结构和组件解决了什么问题?为什么要这么做?
在一个大型 Vue 项目中,合理的目录结构和组件划分至关重要。良好的结构可以提高开发效率,减少维护成本,并使得团队合作更加顺畅。下面我将详细讲解如何在 Vue 项目中进行目录结构和组件划分,并结合实际项目代码示例进行说明。 1. 为什么要划分结构和组件? 1.1 提高可维护…...
springboot中使用mongodb完成评论功能
pom文件中引入 <!-- mongodb --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> yml中配置连接 data:mongodb:uri: mongodb://admin:1234561…...
Dubbo的RPC泛化调用
目录 一、RPC泛化调用的应用场景 二、Dubbo RPC泛化调用的实现原理 三、Dubbo RPC泛化调用的实现步骤 四、示例代码 五、泛化调用怎么发现提供该接口的服务及服务的IP和端口? Dubbo的RPC泛化调用是一种在调用方没有服务方提供的API的情况下,对服务方…...
【k8s深入理解之 Scheme】全面理解 Scheme 的注册机制、内外部版本、自动转换函数、默认填充函数、Options等机制
参考 【k8s基础篇】k8s scheme3 之序列化_基于schema进行序列化-CSDN博客【k8s基础篇】k8s scheme4 之资源数据结构与资源注册_kubernetes 的scheam-CSDN博客常见问题答疑 【k8s深入理解之 Scheme 补充-1】理解 Scheme 中资源的注册以及 GVK 和 go 结构体的映射-CSDN博客【k8s深…...
接口性能优化宝典:解决性能瓶颈的策略与实践
目录 一、直面索引 (一)索引优化的常见场景 (二)如何检查索引的使用情况 (三)如何避免索引失效 (四)强制选择索引 二、提升 SQL 执行效率 (一)避免不必…...
雨晨 Windows Server 2025 数据中心 极简 26311.5000
文件: 雨晨 Windows Server 2025 数据中心 极简 26311.5000 install.esd 大小: 1740910278 字节 修改时间: 2024年11月29日, 星期五, 19:00:20 MD5: 5B946B9DED569E04917E804B25A0F736 SHA1: E78BB430B3E0397F6ACFEB821CF85EA7CFB5A00F CRC32: B3F76BD7 常规制作旨在测试YCDIS…...
wordpress 站内信插件/网站搭建软件
摘要:flowable Asynchronous History,flowable异步处理,flowable实战 介绍 上周,我们发布了即将发布的Flowable6.3 版本的性能基准测试结果(flowable6.3功能以及性能基准测试报告)。这篇文章的结论很简单:与之前的版本相比&#…...
深圳网站建设服务商万创网/免费外贸接单平台
五、接下来的目录迁移设置,这个没什么用,不用管。六、再之后是密码设置,这项建议正常模式下设置一下密码,防止别人使用你的电脑,不小心进入正常模式,结果他的操作就会全部保存下来,设置个密码安…...
校园网站建设案例/百度关键词优化查询
题目链接:hdu 5105 Math Problem 题目大意:给定a。b,c,d。l,r。表示有一个函数f(x)|a∗x3b∗x2c∗xd|(L≤x≤R),求函数最大值。 解题思路:考虑极点就可以,将函数求导后得到f′(x)0的…...
网站增加导航栏/百度推广怎么登陆
嵌入式Linux下NAND flash上根文件系统构建嵌入式Linux下NAND flash上根文件系统构建摘要:针对嵌入式Linux操作系统,通常选择NAND Flash烧录根文件系统的情况。说明了常用嵌入式文件系统的类型及NANDflash的特点;通过在三星的ARM9 2410S平台上…...
男的女的做那个的视频网站/活动推广软文范例
简介:KubeSphere是一个灵活的轻量级容器PaaS平台,通过了CNCF一致性认证,100%开源,由社区驱动与开发。KubeSphere可以部署并运行在任何基础架构以及所有版本兼容的Kubernetes集群之上,包括虚拟机、物理机、数据中心、公有云和混合云…...
wordpress内网访问不了/怎么进行网络营销
1,迪杰斯特拉算法介绍迪杰斯特拉算法是典型最短路径算法,用于计算图或网中某个特定顶点到其他所有顶点的最短路径。主要特点是以起始点为中心向外,层层扩展,直到扩展覆盖所有顶点。2,迪杰斯特拉算法思想设G(V,E)为一个…...