当前位置: 首页 > article >正文

十二、正则表达式、元字符、替换修饰符、手势和对话框插件、字符串截取

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)) // true
    console.log(reg1.test(str2)) // false
    console.log(reg1.test(str3)) // false

    console.log(reg2.test(str1)) // true
    console.log(reg2.test(str2)) // false
    console.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)) // true

    console.log(reg2.test(str1)) // true
    console.log(reg2.test(str2)) // false

    console.log(reg3.test(str1)) // false
    console.log(reg3.test(str2)) // true

    console.log(reg4.test(str2)) // false
    console.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('')) // t
    console.log(reg1.test('钱')) // t
    console.log(reg1.test('111')) // f
    console.log('-------------------')

    // +:重复>=1 次
    const reg2 = /^钱+$/
    console.log(reg2.test('')) // f
    console.log(reg2.test('钱')) // t
    console.log(reg2.test('钱钱')) // t
    console.log('-------------------')

    // ?:重复0次或1次
    const reg3 = /^钱?$/
    console.log(reg3.test('')) // t
    console.log(reg3.test('钱')) // t
    console.log(reg3.test('钱钱')) // f
    console.log('-------------------')

    // {n}:重复n次
    const reg4 = /^钱{3}$/
    console.log(reg4.test('钱钱')) // f
    console.log(reg4.test('钱钱钱')) // t
    console.log('-------------------')

    // {n,}:重复>=n 次
    const reg5 = /^钱{3,}$/
    console.log(reg5.test('钱钱')) // f
    console.log(reg5.test('钱钱钱')) // t
    console.log(reg5.test('钱钱钱钱')) // t
    console.log('-------------------')

    // {n,m}:重复n~m 次(包含n,m) 逗号左右两侧千万不要出现空格
    const reg6 = /^钱{3,5}$/
    console.log(reg6.test('钱钱')) // f
    console.log(reg6.test('钱钱钱')) // t
    console.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. 多选1
    const reg1 = /[abc]/
    console.log(reg1.test('a')) // true
    console.log(reg1.test('ac')) // true
    console.log(reg1.test('cd')) // true
    console.log(reg1.test('de')) // false
    console.log('--------------')

    // 2. 连字符
    /* 
      ➢ [a-z] 表示 a 到 z 26个英文字母都可以
      ➢ [a-zA-Z] 表示大小写都可以
      ➢ [0-9] 表示 0~9 的数字都可以
    */
    const reg2 = /[a-f]/
    console.log(reg2.test('a')) // true
    console.log(reg2.test('ac')) // true
    console.log(reg2.test('ch')) // true
    console.log(reg2.test('hj')) // false
    console.log('--------------')

    // 3. 取反符
    const reg3 = /[^abc]/
    console.log(reg3.test('a')) // false
    console.log(reg3.test('ac')) // false
    console.log(reg3.test('cd')) // true
    console.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')) // true
    console.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>
        &times;
      </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 } = item
        return `
          <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.value
      let addTel = tel.value

      if (!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, '小红')) // t
    console.log(REG(regUsername, '红')) // t
    console.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,
          } = el
          return `
            <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 = str

      swipefn()
    }
    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>


http://www.kler.cn/a/415663.html

相关文章:

  • FRU文件
  • uniapp在App端定义全局弹窗,当打开关闭弹窗会触发onShow、onHide生命周期怎么解决?
  • [巅峰极客 2021]签到
  • 网安瞭望台第4期:nuclei最新poc分享
  • 【OpenGL】延迟着色和G缓冲
  • pcb元器件选型与焊接测试时的一些个人经验
  • 面向多用户场景的恢复机制驱动的无线组密钥生成协议
  • LLM: softMax function and temperature
  • 可编程网络在分布式深度学习通信瓶颈控制中的应用与未来展望
  • Android RIL面试题及参考答案
  • 【系统架构设计师】真题论文: 论数据访问层设计技术及其应用(包括解题思路和素材)
  • Ubantu系统非root用户安装docker教程
  • c++ 程序来计算三角形的面积(Program to find area of a triangle)
  • 【Unity-父节点】
  • 点云3DHarris角点检测算法推导
  • TsingtaoAI具身智能高校实训方案通过华为昇腾技术认证
  • C++开源游戏项目OpenTTD(运输大亨)源码的编译和运行
  • 基于Redis内核的热key统计实现方案|得物技术
  • 彻底理解quadtree四叉树、Octree八叉树 —— 点云的空间划分的标准做法
  • Vue.js 指令详解:v-bind, v-html, v-once, v-on, v-if, v-else-if, v-else 和 v-model
  • 音视频入门基础:MPEG2-TS专题(9)——FFmpeg源码中,解码TS Header的实现
  • wareshark分析mysql协议的数据包
  • 【Jenkins】docker 部署 Jenkins 踩坑笔记
  • 微信小程序:实现定时拍照与自动上传功能攻略——静音版
  • 【C++】深入探讨基础输入输出及类型转换问题
  • cesium 3Dtiles变量