活动公告

系统通知
05-18 21:22
系统通知
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

掌握正则表达式与JavaScriptDOM操作打造高效动态网页从基础到实战提升前端开发技能

SunJu_FaceMall

3万

主题

2860

科技点

3万

积分

白金月票

碾压王

积分
32872

塔罗立华奏

<font color=白金月票" /> 发表于 2025-9-11 02:10:01 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1. 引言

在现代前端开发中,正则表达式和JavaScript DOM操作是两项核心技能,它们能够帮助开发者创建高效、动态且用户友好的网页。正则表达式提供了强大的文本模式匹配和处理能力,而DOM操作则允许我们动态地修改网页内容和结构。掌握这两项技术并学会将它们结合使用,可以极大地提升前端开发效率和用户体验。

本文将从基础概念开始,逐步深入到实际应用场景,通过详细的代码示例和实战案例,帮助读者全面理解并掌握正则表达式与JavaScript DOM操作的结合使用,从而提升前端开发技能。

2. 正则表达式基础

2.1 什么是正则表达式

正则表达式(Regular Expression,简称regex或regexp)是一种用于描述字符串模式的强大工具。它由一系列特殊字符和普通字符组成,可以用来检查字符串是否符合某种模式、提取符合模式的部分或替换字符串中的特定部分。

2.2 正则表达式的基本语法

在JavaScript中,可以通过两种方式创建正则表达式:
  1. // 使用字面量
  2. const pattern1 = /pattern/flags;
  3. // 使用构造函数
  4. const pattern2 = new RegExp('pattern', 'flags');
复制代码

• .:匹配除换行符以外的任何单个字符
• \d:匹配任何数字(等同于[0-9])
• \D:匹配任何非数字字符(等同于[^0-9])
• \w:匹配任何字母数字字符(等同于[a-zA-Z0-9_])
• \W:匹配任何非字母数字字符(等同于[^a-zA-Z0-9_])
• \s:匹配任何空白字符(包括空格、制表符、换行符等)
• \S:匹配任何非空白字符

• *:匹配前面的元素零次或多次
• +:匹配前面的元素一次或多次
• ?:匹配前面的元素零次或一次
• {n}:匹配前面的元素恰好n次
• {n,}:匹配前面的元素至少n次
• {n,m}:匹配前面的元素至少n次,至多m次

• ^:匹配字符串的开始
• $:匹配字符串的结束
• \b:匹配单词边界
• \B:匹配非单词边界

• [abc]:匹配a、b或c中的任意一个字符
• [^abc]:匹配除a、b、c以外的任何字符
• [a-z]:匹配a到z之间的任何小写字母
• [A-Z]:匹配A到Z之间的任何大写字母
• [0-9]:匹配0到9之间的任何数字

2.3 常用的正则表达式模式

以下是一些常用的正则表达式模式示例:
  1. // 邮箱验证
  2. const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
  3. // 手机号验证(简单版)
  4. const phoneRegex = /^1[3-9]\d{9}$/;
  5. // URL验证
  6. const urlRegex = /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/;
  7. // 身份证号验证(简单版)
  8. const idCardRegex = /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;
  9. // 密码强度验证(至少包含一个大写字母、一个小写字母、一个数字和一个特殊字符,长度至少8位)
  10. const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
复制代码

2.4 JavaScript中的正则表达式方法

JavaScript提供了多种使用正则表达式的方法:
  1. // test():测试字符串是否匹配模式,返回true或false
  2. const pattern = /hello/;
  3. console.log(pattern.test('hello world')); // true
  4. // exec():在字符串中执行匹配搜索,返回结果数组或null
  5. const pattern = /(\d+)\.(\d+)\.(\d+)/;
  6. const version = 'Version: 2.5.10';
  7. const result = pattern.exec(version);
  8. console.log(result);
  9. // 输出: ["2.5.10", "2", "5", "10", index: 9, input: "Version: 2.5.10", groups: undefined]
复制代码
  1. // match():在字符串中查找匹配,返回结果数组或null
  2. const text = 'The price is $123.45';
  3. const result = text.match(/\d+\.\d+/);
  4. console.log(result); // ["123.45", index: 12, input: "The price is $123.45", groups: undefined]
  5. // search():在字符串中查找匹配,返回匹配位置的索引,否则返回-1
  6. const text = 'Hello world';
  7. console.log(text.search(/world/)); // 6
  8. // replace():替换匹配的子串
  9. const text = 'Hello world';
  10. console.log(text.replace(/world/, 'JavaScript')); // "Hello JavaScript"
  11. // split():使用匹配的子串作为分隔符来分割字符串
  12. const text = 'apple,banana,orange';
  13. console.log(text.split(/,/)); // ["apple", "banana", "orange"]
复制代码

3. JavaScript DOM操作基础

3.1 DOM的概念和结构

文档对象模型(Document Object Model,简称DOM)是HTML和XML文档的编程接口。它将文档表示为一个节点树,其中每个节点代表文档的一部分(如元素、属性、文本等)。

DOM树的结构如下:
  1. document
  2. └── html
  3.     ├── head
  4.     │   ├── title
  5.     │   ├── meta
  6.     │   └── link
  7.     └── body
  8.         ├── header
  9.         ├── nav
  10.         ├── main
  11.         │   ├── h1
  12.         │   ├── p
  13.         │   └── div
  14.         └── footer
复制代码

3.2 选择DOM元素的方法

JavaScript提供了多种选择DOM元素的方法:
  1. // 通过ID选择元素
  2. const elementById = document.getElementById('myId');
  3. // 通过类名选择元素(返回HTMLCollection)
  4. const elementsByClass = document.getElementsByClassName('myClass');
  5. // 通过标签名选择元素(返回HTMLCollection)
  6. const elementsByTag = document.getElementsByTagName('div');
  7. // 通过CSS选择器选择单个元素
  8. const elementByQuery = document.querySelector('#myId .myClass');
  9. // 通过CSS选择器选择多个元素(返回NodeList)
  10. const elementsByQueryAll = document.querySelectorAll('div.myClass');
复制代码

3.3 修改DOM元素
  1. // 获取元素
  2. const element = document.getElementById('myElement');
  3. // 修改文本内容
  4. element.textContent = '新的文本内容';
  5. // 修改HTML内容
  6. element.innerHTML = '<strong>加粗的文本</strong>';
  7. // 修改属性
  8. element.setAttribute('class', 'new-class');
  9. element.id = 'newId';
  10. // 修改样式
  11. element.style.color = 'red';
  12. element.style.fontSize = '16px';
复制代码
  1. const element = document.getElementById('myElement');
  2. // 添加类
  3. element.classList.add('active');
  4. // 移除类
  5. element.classList.remove('inactive');
  6. // 切换类(如果存在则移除,不存在则添加)
  7. element.classList.toggle('highlight');
  8. // 检查是否包含某个类
  9. if (element.classList.contains('active')) {
  10.     console.log('元素具有active类');
  11. }
复制代码

3.4 创建和删除DOM元素
  1. // 创建新元素
  2. const newDiv = document.createElement('div');
  3. newDiv.id = 'newDiv';
  4. newDiv.className = 'container';
  5. newDiv.textContent = '这是一个新创建的div';
  6. // 添加到DOM中
  7. document.body.appendChild(newDiv);
  8. // 创建文本节点
  9. const textNode = document.createTextNode('这是一个文本节点');
  10. newDiv.appendChild(textNode);
  11. // 删除元素
  12. const elementToRemove = document.getElementById('elementToRemove');
  13. elementToRemove.parentNode.removeChild(elementToRemove);
  14. // 替换元素
  15. const oldElement = document.getElementById('oldElement');
  16. const newElement = document.createElement('div');
  17. newElement.textContent = '新元素';
  18. oldElement.parentNode.replaceChild(newElement, oldElement);
复制代码

3.5 事件处理
  1. // 获取元素
  2. const button = document.getElementById('myButton');
  3. // 添加事件监听器
  4. button.addEventListener('click', function(event) {
  5.     console.log('按钮被点击了');
  6.     console.log('事件对象:', event);
  7. });
  8. // 使用箭头函数
  9. button.addEventListener('click', (event) => {
  10.     console.log('按钮被点击了(箭头函数)');
  11. });
  12. // 移除事件监听器
  13. function handleClick(event) {
  14.     console.log('处理点击事件');
  15. }
  16. button.addEventListener('click', handleClick);
  17. // button.removeEventListener('click', handleClick);
  18. // 事件委托
  19. document.addEventListener('click', function(event) {
  20.     if (event.target.matches('.button')) {
  21.         console.log('某个按钮被点击了');
  22.     }
  23. });
复制代码

4. 结合正则表达式和DOM操作

4.1 表单验证

正则表达式和DOM操作结合最常见的应用场景之一是表单验证。以下是一个完整的表单验证示例:
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>表单验证示例</title>
  7.     <style>
  8.         body {
  9.             font-family: Arial, sans-serif;
  10.             max-width: 600px;
  11.             margin: 0 auto;
  12.             padding: 20px;
  13.         }
  14.         .form-group {
  15.             margin-bottom: 15px;
  16.         }
  17.         label {
  18.             display: block;
  19.             margin-bottom: 5px;
  20.             font-weight: bold;
  21.         }
  22.         input {
  23.             width: 100%;
  24.             padding: 8px;
  25.             box-sizing: border-box;
  26.             border: 1px solid #ddd;
  27.             border-radius: 4px;
  28.         }
  29.         input:focus {
  30.             outline: none;
  31.             border-color: #4CAF50;
  32.         }
  33.         .error {
  34.             color: red;
  35.             font-size: 12px;
  36.             margin-top: 5px;
  37.             display: none;
  38.         }
  39.         input.invalid {
  40.             border-color: red;
  41.         }
  42.         button {
  43.             background-color: #4CAF50;
  44.             color: white;
  45.             padding: 10px 15px;
  46.             border: none;
  47.             border-radius: 4px;
  48.             cursor: pointer;
  49.         }
  50.         button:hover {
  51.             background-color: #45a049;
  52.         }
  53.         .success-message {
  54.             display: none;
  55.             background-color: #dff0d8;
  56.             color: #3c763d;
  57.             padding: 10px;
  58.             margin-top: 20px;
  59.             border-radius: 4px;
  60.         }
  61.     </style>
  62. </head>
  63. <body>
  64.     <h1>注册表单</h1>
  65.     <form id="registrationForm">
  66.         <div class="form-group">
  67.             <label for="username">用户名:</label>
  68.             <input type="text" id="username" name="username">
  69.             <div id="usernameError" class="error">用户名必须是4-16个字母、数字或下划线</div>
  70.         </div>
  71.         
  72.         <div class="form-group">
  73.             <label for="email">邮箱:</label>
  74.             <input type="email" id="email" name="email">
  75.             <div id="emailError" class="error">请输入有效的邮箱地址</div>
  76.         </div>
  77.         
  78.         <div class="form-group">
  79.             <label for="phone">手机号:</label>
  80.             <input type="tel" id="phone" name="phone">
  81.             <div id="phoneError" class="error">请输入有效的11位手机号</div>
  82.         </div>
  83.         
  84.         <div class="form-group">
  85.             <label for="password">密码:</label>
  86.             <input type="password" id="password" name="password">
  87.             <div id="passwordError" class="error">密码必须至少8位,包含大小写字母、数字和特殊字符</div>
  88.         </div>
  89.         
  90.         <div class="form-group">
  91.             <label for="confirmPassword">确认密码:</label>
  92.             <input type="password" id="confirmPassword" name="confirmPassword">
  93.             <div id="confirmPasswordError" class="error">两次输入的密码不一致</div>
  94.         </div>
  95.         
  96.         <button type="submit">注册</button>
  97.     </form>
  98.    
  99.     <div id="successMessage" class="success-message">
  100.         注册成功!
  101.     </div>
  102.     <script>
  103.         // 获取表单和输入元素
  104.         const form = document.getElementById('registrationForm');
  105.         const usernameInput = document.getElementById('username');
  106.         const emailInput = document.getElementById('email');
  107.         const phoneInput = document.getElementById('phone');
  108.         const passwordInput = document.getElementById('password');
  109.         const confirmPasswordInput = document.getElementById('confirmPassword');
  110.         
  111.         // 获取错误消息元素
  112.         const usernameError = document.getElementById('usernameError');
  113.         const emailError = document.getElementById('emailError');
  114.         const phoneError = document.getElementById('phoneError');
  115.         const passwordError = document.getElementById('passwordError');
  116.         const confirmPasswordError = document.getElementById('confirmPasswordError');
  117.         
  118.         // 获取成功消息元素
  119.         const successMessage = document.getElementById('successMessage');
  120.         
  121.         // 定义正则表达式
  122.         const usernameRegex = /^[a-zA-Z0-9_]{4,16}$/;
  123.         const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
  124.         const phoneRegex = /^1[3-9]\d{9}$/;
  125.         const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
  126.         
  127.         // 验证函数
  128.         function validateUsername() {
  129.             const isValid = usernameRegex.test(usernameInput.value);
  130.             if (!isValid) {
  131.                 usernameInput.classList.add('invalid');
  132.                 usernameError.style.display = 'block';
  133.             } else {
  134.                 usernameInput.classList.remove('invalid');
  135.                 usernameError.style.display = 'none';
  136.             }
  137.             return isValid;
  138.         }
  139.         
  140.         function validateEmail() {
  141.             const isValid = emailRegex.test(emailInput.value);
  142.             if (!isValid) {
  143.                 emailInput.classList.add('invalid');
  144.                 emailError.style.display = 'block';
  145.             } else {
  146.                 emailInput.classList.remove('invalid');
  147.                 emailError.style.display = 'none';
  148.             }
  149.             return isValid;
  150.         }
  151.         
  152.         function validatePhone() {
  153.             const isValid = phoneRegex.test(phoneInput.value);
  154.             if (!isValid) {
  155.                 phoneInput.classList.add('invalid');
  156.                 phoneError.style.display = 'block';
  157.             } else {
  158.                 phoneInput.classList.remove('invalid');
  159.                 phoneError.style.display = 'none';
  160.             }
  161.             return isValid;
  162.         }
  163.         
  164.         function validatePassword() {
  165.             const isValid = passwordRegex.test(passwordInput.value);
  166.             if (!isValid) {
  167.                 passwordInput.classList.add('invalid');
  168.                 passwordError.style.display = 'block';
  169.             } else {
  170.                 passwordInput.classList.remove('invalid');
  171.                 passwordError.style.display = 'none';
  172.             }
  173.             return isValid;
  174.         }
  175.         
  176.         function validateConfirmPassword() {
  177.             const isValid = passwordInput.value === confirmPasswordInput.value;
  178.             if (!isValid) {
  179.                 confirmPasswordInput.classList.add('invalid');
  180.                 confirmPasswordError.style.display = 'block';
  181.             } else {
  182.                 confirmPasswordInput.classList.remove('invalid');
  183.                 confirmPasswordError.style.display = 'none';
  184.             }
  185.             return isValid;
  186.         }
  187.         
  188.         // 添加输入事件监听器
  189.         usernameInput.addEventListener('input', validateUsername);
  190.         emailInput.addEventListener('input', validateEmail);
  191.         phoneInput.addEventListener('input', validatePhone);
  192.         passwordInput.addEventListener('input', validatePassword);
  193.         confirmPasswordInput.addEventListener('input', validateConfirmPassword);
  194.         
  195.         // 添加表单提交事件监听器
  196.         form.addEventListener('submit', function(event) {
  197.             event.preventDefault();
  198.             
  199.             // 验证所有字段
  200.             const isUsernameValid = validateUsername();
  201.             const isEmailValid = validateEmail();
  202.             const isPhoneValid = validatePhone();
  203.             const isPasswordValid = validatePassword();
  204.             const isConfirmPasswordValid = validateConfirmPassword();
  205.             
  206.             // 如果所有字段都有效,显示成功消息
  207.             if (isUsernameValid && isEmailValid && isPhoneValid && isPasswordValid && isConfirmPasswordValid) {
  208.                 form.style.display = 'none';
  209.                 successMessage.style.display = 'block';
  210.             }
  211.         });
  212.     </script>
  213. </body>
  214. </html>
复制代码

4.2 动态内容搜索和过滤

正则表达式和DOM操作结合的另一个常见应用是动态内容搜索和过滤。以下是一个实时搜索和过滤列表项的示例:
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>动态搜索和过滤</title>
  7.     <style>
  8.         body {
  9.             font-family: Arial, sans-serif;
  10.             max-width: 800px;
  11.             margin: 0 auto;
  12.             padding: 20px;
  13.         }
  14.         .search-container {
  15.             margin-bottom: 20px;
  16.         }
  17.         .search-box {
  18.             width: 100%;
  19.             padding: 10px;
  20.             font-size: 16px;
  21.             border: 1px solid #ddd;
  22.             border-radius: 4px;
  23.             box-sizing: border-box;
  24.         }
  25.         .search-options {
  26.             margin-top: 10px;
  27.             display: flex;
  28.             gap: 15px;
  29.         }
  30.         .search-option {
  31.             display: flex;
  32.             align-items: center;
  33.         }
  34.         .search-option input {
  35.             margin-right: 5px;
  36.         }
  37.         .item-list {
  38.             list-style-type: none;
  39.             padding: 0;
  40.         }
  41.         .item {
  42.             padding: 15px;
  43.             border-bottom: 1px solid #eee;
  44.             display: flex;
  45.             align-items: center;
  46.         }
  47.         .item:last-child {
  48.             border-bottom: none;
  49.         }
  50.         .item-icon {
  51.             width: 50px;
  52.             height: 50px;
  53.             background-color: #4CAF50;
  54.             border-radius: 50%;
  55.             display: flex;
  56.             align-items: center;
  57.             justify-content: center;
  58.             color: white;
  59.             font-weight: bold;
  60.             margin-right: 15px;
  61.         }
  62.         .item-content {
  63.             flex: 1;
  64.         }
  65.         .item-title {
  66.             font-weight: bold;
  67.             margin-bottom: 5px;
  68.         }
  69.         .item-description {
  70.             color: #666;
  71.             font-size: 14px;
  72.         }
  73.         .highlight {
  74.             background-color: yellow;
  75.             font-weight: bold;
  76.         }
  77.         .no-results {
  78.             text-align: center;
  79.             padding: 20px;
  80.             color: #666;
  81.             display: none;
  82.         }
  83.     </style>
  84. </head>
  85. <body>
  86.     <h1>联系人列表</h1>
  87.    
  88.     <div class="search-container">
  89.         <input type="text" id="searchInput" class="search-box" placeholder="搜索联系人...">
  90.         <div class="search-options">
  91.             <div class="search-option">
  92.                 <input type="checkbox" id="caseSensitive" name="caseSensitive">
  93.                 <label for="caseSensitive">区分大小写</label>
  94.             </div>
  95.             <div class="search-option">
  96.                 <input type="checkbox" id="wholeWord" name="wholeWord">
  97.                 <label for="wholeWord">全词匹配</label>
  98.             </div>
  99.             <div class="search-option">
  100.                 <input type="checkbox" id="useRegex" name="useRegex">
  101.                 <label for="useRegex">使用正则表达式</label>
  102.             </div>
  103.         </div>
  104.     </div>
  105.    
  106.     <ul id="itemList" class="item-list">
  107.         <li class="item" data-name="张三" data-phone="13800138000" data-email="zhangsan@example.com">
  108.             <div class="item-icon">张</div>
  109.             <div class="item-content">
  110.                 <div class="item-title">张三</div>
  111.                 <div class="item-description">电话: 13800138000 | 邮箱: zhangsan@example.com</div>
  112.             </div>
  113.         </li>
  114.         <li class="item" data-name="李四" data-phone="13900139000" data-email="lisi@example.com">
  115.             <div class="item-icon">李</div>
  116.             <div class="item-content">
  117.                 <div class="item-title">李四</div>
  118.                 <div class="item-description">电话: 13900139000 | 邮箱: lisi@example.com</div>
  119.             </div>
  120.         </li>
  121.         <li class="item" data-name="王五" data-phone="13700137000" data-email="wangwu@example.com">
  122.             <div class="item-icon">王</div>
  123.             <div class="item-content">
  124.                 <div class="item-title">王五</div>
  125.                 <div class="item-description">电话: 13700137000 | 邮箱: wangwu@example.com</div>
  126.             </div>
  127.         </li>
  128.         <li class="item" data-name="赵六" data-phone="13600136000" data-email="zhaoliu@example.com">
  129.             <div class="item-icon">赵</div>
  130.             <div class="item-content">
  131.                 <div class="item-title">赵六</div>
  132.                 <div class="item-description">电话: 13600136000 | 邮箱: zhaoliu@example.com</div>
  133.             </div>
  134.         </li>
  135.         <li class="item" data-name="钱七" data-phone="13500135000" data-email="qianqi@example.com">
  136.             <div class="item-icon">钱</div>
  137.             <div class="item-content">
  138.                 <div class="item-title">钱七</div>
  139.                 <div class="item-description">电话: 13500135000 | 邮箱: qianqi@example.com</div>
  140.             </div>
  141.         </li>
  142.     </ul>
  143.    
  144.     <div id="noResults" class="no-results">
  145.         没有找到匹配的联系人
  146.     </div>
  147.     <script>
  148.         // 获取DOM元素
  149.         const searchInput = document.getElementById('searchInput');
  150.         const caseSensitiveCheckbox = document.getElementById('caseSensitive');
  151.         const wholeWordCheckbox = document.getElementById('wholeWord');
  152.         const useRegexCheckbox = document.getElementById('useRegex');
  153.         const itemList = document.getElementById('itemList');
  154.         const items = itemList.querySelectorAll('.item');
  155.         const noResults = document.getElementById('noResults');
  156.         
  157.         // 搜索函数
  158.         function performSearch() {
  159.             const searchTerm = searchInput.value.trim();
  160.             const caseSensitive = caseSensitiveCheckbox.checked;
  161.             const wholeWord = wholeWordCheckbox.checked;
  162.             const useRegex = useRegexCheckbox.checked;
  163.             
  164.             let hasResults = false;
  165.             
  166.             // 如果搜索词为空,显示所有项目
  167.             if (searchTerm === '') {
  168.                 items.forEach(item => {
  169.                     item.style.display = 'flex';
  170.                     // 移除所有高亮
  171.                     removeHighlights(item);
  172.                 });
  173.                 noResults.style.display = 'none';
  174.                 return;
  175.             }
  176.             
  177.             // 构建正则表达式
  178.             let pattern;
  179.             try {
  180.                 if (useRegex) {
  181.                     // 使用用户提供的正则表达式
  182.                     pattern = new RegExp(searchTerm, caseSensitive ? 'g' : 'gi');
  183.                 } else {
  184.                     // 构建基于搜索词的正则表达式
  185.                     let escapedTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  186.                     if (wholeWord) {
  187.                         pattern = new RegExp(`\\b${escapedTerm}\\b`, caseSensitive ? 'g' : 'gi');
  188.                     } else {
  189.                         pattern = new RegExp(escapedTerm, caseSensitive ? 'g' : 'gi');
  190.                     }
  191.                 }
  192.                
  193.                 // 遍历所有项目
  194.                 items.forEach(item => {
  195.                     const name = item.getAttribute('data-name');
  196.                     const phone = item.getAttribute('data-phone');
  197.                     const email = item.getAttribute('data-email');
  198.                     const titleElement = item.querySelector('.item-title');
  199.                     const descriptionElement = item.querySelector('.item-description');
  200.                     
  201.                     // 检查是否匹配
  202.                     const nameMatch = pattern.test(name);
  203.                     pattern.lastIndex = 0; // 重置正则表达式的lastIndex
  204.                     const phoneMatch = pattern.test(phone);
  205.                     pattern.lastIndex = 0;
  206.                     const emailMatch = pattern.test(email);
  207.                     pattern.lastIndex = 0;
  208.                     
  209.                     if (nameMatch || phoneMatch || emailMatch) {
  210.                         // 显示匹配的项目
  211.                         item.style.display = 'flex';
  212.                         hasResults = true;
  213.                         
  214.                         // 移除之前的高亮
  215.                         removeHighlights(item);
  216.                         
  217.                         // 添加新的高亮
  218.                         if (nameMatch) {
  219.                             highlightText(titleElement, pattern);
  220.                         }
  221.                         if (phoneMatch || emailMatch) {
  222.                             highlightText(descriptionElement, pattern);
  223.                         }
  224.                     } else {
  225.                         // 隐藏不匹配的项目
  226.                         item.style.display = 'none';
  227.                     }
  228.                 });
  229.                
  230.                 // 显示或隐藏"无结果"消息
  231.                 noResults.style.display = hasResults ? 'none' : 'block';
  232.                
  233.             } catch (error) {
  234.                 // 处理正则表达式错误
  235.                 console.error('正则表达式错误:', error);
  236.                 items.forEach(item => {
  237.                     item.style.display = 'flex';
  238.                     removeHighlights(item);
  239.                 });
  240.                 noResults.style.display = 'none';
  241.             }
  242.         }
  243.         
  244.         // 高亮文本函数
  245.         function highlightText(element, regex) {
  246.             const text = element.textContent;
  247.             const matches = text.match(regex);
  248.             
  249.             if (matches) {
  250.                 let highlightedText = text;
  251.                 matches.forEach(match => {
  252.                     // 使用正则表达式全局替换匹配的文本
  253.                     highlightedText = highlightedText.replace(regex, '<span class="highlight">$&</span>');
  254.                 });
  255.                 element.innerHTML = highlightedText;
  256.             }
  257.         }
  258.         
  259.         // 移除高亮函数
  260.         function removeHighlights(item) {
  261.             const highlights = item.querySelectorAll('.highlight');
  262.             highlights.forEach(highlight => {
  263.                 const parent = highlight.parentNode;
  264.                 parent.replaceChild(document.createTextNode(highlight.textContent), highlight);
  265.                 parent.normalize();
  266.             });
  267.         }
  268.         
  269.         // 添加事件监听器
  270.         searchInput.addEventListener('input', performSearch);
  271.         caseSensitiveCheckbox.addEventListener('change', performSearch);
  272.         wholeWordCheckbox.addEventListener('change', performSearch);
  273.         useRegexCheckbox.addEventListener('change', performSearch);
  274.     </script>
  275. </body>
  276. </html>
复制代码

4.3 文本处理和格式化

正则表达式和DOM操作结合还可以用于文本处理和格式化。以下是一个文本格式化工具的示例:
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>文本格式化工具</title>
  7.     <style>
  8.         body {
  9.             font-family: Arial, sans-serif;
  10.             max-width: 800px;
  11.             margin: 0 auto;
  12.             padding: 20px;
  13.         }
  14.         h1 {
  15.             text-align: center;
  16.         }
  17.         .container {
  18.             display: flex;
  19.             flex-direction: column;
  20.             gap: 20px;
  21.         }
  22.         .section {
  23.             border: 1px solid #ddd;
  24.             border-radius: 5px;
  25.             padding: 15px;
  26.         }
  27.         .section-title {
  28.             font-weight: bold;
  29.             margin-bottom: 10px;
  30.             color: #333;
  31.         }
  32.         textarea {
  33.             width: 100%;
  34.             height: 150px;
  35.             padding: 10px;
  36.             border: 1px solid #ddd;
  37.             border-radius: 4px;
  38.             resize: vertical;
  39.             font-family: inherit;
  40.         }
  41.         .buttons {
  42.             display: flex;
  43.             flex-wrap: wrap;
  44.             gap: 10px;
  45.             margin-top: 10px;
  46.         }
  47.         button {
  48.             padding: 8px 12px;
  49.             background-color: #4CAF50;
  50.             color: white;
  51.             border: none;
  52.             border-radius: 4px;
  53.             cursor: pointer;
  54.             font-size: 14px;
  55.         }
  56.         button:hover {
  57.             background-color: #45a049;
  58.         }
  59.         .options {
  60.             display: flex;
  61.             flex-wrap: wrap;
  62.             gap: 15px;
  63.             margin-top: 10px;
  64.         }
  65.         .option {
  66.             display: flex;
  67.             align-items: center;
  68.         }
  69.         .option input {
  70.             margin-right: 5px;
  71.         }
  72.         .custom-regex {
  73.             margin-top: 10px;
  74.         }
  75.         .custom-regex input {
  76.             width: 100%;
  77.             padding: 8px;
  78.             border: 1px solid #ddd;
  79.             border-radius: 4px;
  80.         }
  81.     </style>
  82. </head>
  83. <body>
  84.     <h1>文本格式化工具</h1>
  85.    
  86.     <div class="container">
  87.         <div class="section">
  88.             <div class="section-title">输入文本</div>
  89.             <textarea id="inputText" placeholder="在此输入要格式化的文本..."></textarea>
  90.         </div>
  91.         
  92.         <div class="section">
  93.             <div class="section-title">格式化选项</div>
  94.             <div class="buttons">
  95.                 <button id="removeExtraSpaces">移除多余空格</button>
  96.                 <button id="fixLineBreaks">修正换行</button>
  97.                 <button id="capitalizeSentences">句子首字母大写</button>
  98.                 <button id="removeSpecialChars">移除特殊字符</button>
  99.                 <button id="formatPhoneNumbers">格式化电话号码</button>
  100.                 <button id="formatEmails">格式化邮箱地址</button>
  101.                 <button id="extractUrls">提取URL</button>
  102.                 <button id="extractNumbers">提取数字</button>
  103.             </div>
  104.             
  105.             <div class="options">
  106.                 <div class="option">
  107.                     <input type="checkbox" id="globalReplace">
  108.                     <label for="globalReplace">全局替换</label>
  109.                 </div>
  110.                 <div class="option">
  111.                     <input type="checkbox" id="caseSensitive">
  112.                     <label for="caseSensitive">区分大小写</label>
  113.                 </div>
  114.             </div>
  115.             
  116.             <div class="custom-regex">
  117.                 <label for="customRegex">自定义正则表达式:</label>
  118.                 <input type="text" id="customRegex" placeholder="输入正则表达式">
  119.                 <button id="applyCustomRegex">应用</button>
  120.             </div>
  121.         </div>
  122.         
  123.         <div class="section">
  124.             <div class="section-title">格式化结果</div>
  125.             <textarea id="outputText" readonly placeholder="格式化结果将显示在这里..."></textarea>
  126.             <div class="buttons">
  127.                 <button id="copyResult">复制结果</button>
  128.                 <button id="clearAll">清除全部</button>
  129.             </div>
  130.         </div>
  131.     </div>
  132.     <script>
  133.         // 获取DOM元素
  134.         const inputText = document.getElementById('inputText');
  135.         const outputText = document.getElementById('outputText');
  136.         const globalReplaceCheckbox = document.getElementById('globalReplace');
  137.         const caseSensitiveCheckbox = document.getElementById('caseSensitive');
  138.         const customRegexInput = document.getElementById('customRegex');
  139.         
  140.         // 获取按钮
  141.         const removeExtraSpacesBtn = document.getElementById('removeExtraSpaces');
  142.         const fixLineBreaksBtn = document.getElementById('fixLineBreaks');
  143.         const capitalizeSentencesBtn = document.getElementById('capitalizeSentences');
  144.         const removeSpecialCharsBtn = document.getElementById('removeSpecialChars');
  145.         const formatPhoneNumbersBtn = document.getElementById('formatPhoneNumbers');
  146.         const formatEmailsBtn = document.getElementById('formatEmails');
  147.         const extractUrlsBtn = document.getElementById('extractUrls');
  148.         const extractNumbersBtn = document.getElementById('extractNumbers');
  149.         const applyCustomRegexBtn = document.getElementById('applyCustomRegex');
  150.         const copyResultBtn = document.getElementById('copyResult');
  151.         const clearAllBtn = document.getElementById('clearAll');
  152.         
  153.         // 获取标志
  154.         function getFlags() {
  155.             let flags = '';
  156.             if (globalReplaceCheckbox.checked) flags += 'g';
  157.             if (!caseSensitiveCheckbox.checked) flags += 'i';
  158.             return flags;
  159.         }
  160.         
  161.         // 应用正则表达式
  162.         function applyRegex(pattern, replacement, input = inputText.value) {
  163.             try {
  164.                 const regex = new RegExp(pattern, getFlags());
  165.                 return input.replace(regex, replacement);
  166.             } catch (error) {
  167.                 console.error('正则表达式错误:', error);
  168.                 return '正则表达式错误: ' + error.message;
  169.             }
  170.         }
  171.         
  172.         // 移除多余空格
  173.         removeExtraSpacesBtn.addEventListener('click', function() {
  174.             // 移除开头和结尾的空格
  175.             let result = inputText.value.trim();
  176.             // 将多个连续空格替换为单个空格
  177.             result = result.replace(/ +/g, ' ');
  178.             // 将多个连续换行符替换为单个换行符
  179.             result = result.replace(/\n+/g, '\n');
  180.             outputText.value = result;
  181.         });
  182.         
  183.         // 修正换行
  184.         fixLineBreaksBtn.addEventListener('click', function() {
  185.             // 将各种换行符统一为\n
  186.             let result = inputText.value.replace(/\r\n|\r/g, '\n');
  187.             // 确保段落之间只有一个空行
  188.             result = result.replace(/\n{3,}/g, '\n\n');
  189.             outputText.value = result;
  190.         });
  191.         
  192.         // 句子首字母大写
  193.         capitalizeSentencesBtn.addEventListener('click', function() {
  194.             let result = inputText.value.toLowerCase();
  195.             // 句子首字母大写
  196.             result = result.replace(/(^\w|\.\s*\w)/g, function(match) {
  197.                 return match.toUpperCase();
  198.             });
  199.             outputText.value = result;
  200.         });
  201.         
  202.         // 移除特殊字符
  203.         removeSpecialCharsBtn.addEventListener('click', function() {
  204.             // 保留字母、数字、中文、基本标点和空格
  205.             const result = applyRegex(/[^\w\s\u4e00-\u9fa5.,!?;:()\[\]{}'"\/\-]/g, '');
  206.             outputText.value = result;
  207.         });
  208.         
  209.         // 格式化电话号码
  210.         formatPhoneNumbersBtn.addEventListener('click', function() {
  211.             // 将连续的11位数字格式化为手机号格式
  212.             let result = applyRegex(/(\d{3})(\d{4})(\d{4})/g, '$1-$2-$3');
  213.             // 将连续的3-4位数字后跟7-8位数字格式化为座机格式
  214.             result = applyRegex(/(\d{3,4})(\d{7,8})/g, '$1-$2', result);
  215.             outputText.value = result;
  216.         });
  217.         
  218.         // 格式化邮箱地址
  219.         formatEmailsBtn.addEventListener('click', function() {
  220.             // 将邮箱地址转换为小写
  221.             const result = applyRegex(/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g, function(match) {
  222.                 return match.toLowerCase();
  223.             });
  224.             outputText.value = result;
  225.         });
  226.         
  227.         // 提取URL
  228.         extractUrlsBtn.addEventListener('click', function() {
  229.             // 提取URL
  230.             const urls = inputText.value.match(/https?:\/\/[^\s]+/g);
  231.             outputText.value = urls ? urls.join('\n') : '未找到URL';
  232.         });
  233.         
  234.         // 提取数字
  235.         extractNumbersBtn.addEventListener('click', function() {
  236.             // 提取所有数字
  237.             const numbers = inputText.value.match(/\d+\.?\d*/g);
  238.             outputText.value = numbers ? numbers.join('\n') : '未找到数字';
  239.         });
  240.         
  241.         // 应用自定义正则表达式
  242.         applyCustomRegexBtn.addEventListener('click', function() {
  243.             const pattern = customRegexInput.value.trim();
  244.             if (!pattern) {
  245.                 outputText.value = '请输入正则表达式';
  246.                 return;
  247.             }
  248.             
  249.             // 简单替换模式
  250.             const result = applyRegex(pattern, '');
  251.             outputText.value = result;
  252.         });
  253.         
  254.         // 复制结果
  255.         copyResultBtn.addEventListener('click', function() {
  256.             outputText.select();
  257.             document.execCommand('copy');
  258.             
  259.             // 临时更改按钮文本
  260.             const originalText = copyResultBtn.textContent;
  261.             copyResultBtn.textContent = '已复制!';
  262.             setTimeout(() => {
  263.                 copyResultBtn.textContent = originalText;
  264.             }, 2000);
  265.         });
  266.         
  267.         // 清除全部
  268.         clearAllBtn.addEventListener('click', function() {
  269.             inputText.value = '';
  270.             outputText.value = '';
  271.             customRegexInput.value = '';
  272.         });
  273.     </script>
  274. </body>
  275. </html>
复制代码

4.4 动态样式应用

正则表达式和DOM操作结合还可以用于动态样式应用。以下是一个根据内容模式动态应用样式的示例:
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>动态样式应用</title>
  7.     <style>
  8.         body {
  9.             font-family: Arial, sans-serif;
  10.             max-width: 800px;
  11.             margin: 0 auto;
  12.             padding: 20px;
  13.         }
  14.         h1 {
  15.             text-align: center;
  16.         }
  17.         .controls {
  18.             background-color: #f5f5f5;
  19.             padding: 15px;
  20.             border-radius: 5px;
  21.             margin-bottom: 20px;
  22.         }
  23.         .control-group {
  24.             margin-bottom: 15px;
  25.         }
  26.         .control-group label {
  27.             display: block;
  28.             margin-bottom: 5px;
  29.             font-weight: bold;
  30.         }
  31.         .control-group input, .control-group select {
  32.             width: 100%;
  33.             padding: 8px;
  34.             border: 1px solid #ddd;
  35.             border-radius: 4px;
  36.             box-sizing: border-box;
  37.         }
  38.         .button-group {
  39.             display: flex;
  40.             gap: 10px;
  41.             margin-top: 10px;
  42.         }
  43.         button {
  44.             padding: 8px 12px;
  45.             background-color: #4CAF50;
  46.             color: white;
  47.             border: none;
  48.             border-radius: 4px;
  49.             cursor: pointer;
  50.         }
  51.         button:hover {
  52.             background-color: #45a049;
  53.         }
  54.         .content-area {
  55.             border: 1px solid #ddd;
  56.             border-radius: 5px;
  57.             padding: 15px;
  58.             min-height: 200px;
  59.         }
  60.         .highlight {
  61.             background-color: yellow;
  62.             font-weight: bold;
  63.         }
  64.         .highlight-red {
  65.             background-color: #ffcccc;
  66.             color: #990000;
  67.         }
  68.         .highlight-green {
  69.             background-color: #ccffcc;
  70.             color: #006600;
  71.         }
  72.         .highlight-blue {
  73.             background-color: #ccccff;
  74.             color: #000099;
  75.         }
  76.         .underline {
  77.             text-decoration: underline;
  78.         }
  79.         .italic {
  80.             font-style: italic;
  81.         }
  82.         .bold {
  83.             font-weight: bold;
  84.         }
  85.         .uppercase {
  86.             text-transform: uppercase;
  87.         }
  88.         .lowercase {
  89.             text-transform: lowercase;
  90.         }
  91.         .message {
  92.             margin-top: 10px;
  93.             padding: 10px;
  94.             border-radius: 4px;
  95.             display: none;
  96.         }
  97.         .success {
  98.             background-color: #dff0d8;
  99.             color: #3c763d;
  100.         }
  101.         .error {
  102.             background-color: #f2dede;
  103.             color: #a94442;
  104.         }
  105.     </style>
  106. </head>
  107. <body>
  108.     <h1>动态样式应用工具</h1>
  109.    
  110.     <div class="controls">
  111.         <div class="control-group">
  112.             <label for="patternInput">模式 (正则表达式):</label>
  113.             <input type="text" id="patternInput" placeholder="输入正则表达式,例如: \d+">
  114.         </div>
  115.         
  116.         <div class="control-group">
  117.             <label for="styleSelect">应用样式:</label>
  118.             <select id="styleSelect">
  119.                 <option value="highlight">高亮 (黄色)</option>
  120.                 <option value="highlight-red">高亮 (红色)</option>
  121.                 <option value="highlight-green">高亮 (绿色)</option>
  122.                 <option value="highlight-blue">高亮 (蓝色)</option>
  123.                 <option value="underline">下划线</option>
  124.                 <option value="italic">斜体</option>
  125.                 <option value="bold">粗体</option>
  126.                 <option value="uppercase">大写</option>
  127.                 <option value="lowercase">小写</option>
  128.             </select>
  129.         </div>
  130.         
  131.         <div class="control-group">
  132.             <label>
  133.                 <input type="checkbox" id="caseSensitive"> 区分大小写
  134.             </label>
  135.         </div>
  136.         
  137.         <div class="button-group">
  138.             <button id="applyStyle">应用样式</button>
  139.             <button id="clearStyles">清除所有样式</button>
  140.             <button id="presetExample">使用示例</button>
  141.         </div>
  142.         
  143.         <div id="message" class="message"></div>
  144.     </div>
  145.    
  146.     <div class="content-area" id="contentArea">
  147.         <h2>示例文本</h2>
  148.         <p>这是一段示例文本,用于演示动态样式应用功能。您可以输入正则表达式来匹配文本中的特定模式,然后选择要应用的样式。</p>
  149.         <p>例如,您可以输入 <code>\d+</code> 来匹配所有的数字,然后选择"高亮 (黄色)"样式来高亮显示这些数字。</p>
  150.         <p>联系电话: 138-1234-5678 或 010-12345678</p>
  151.         <p>电子邮箱: example@example.com</p>
  152.         <p>网址: https://www.example.com</p>
  153.         <p>日期: 2023-05-15</p>
  154.         <p>价格: $19.99 或 ¥99.00</p>
  155.     </div>
  156.     <script>
  157.         // 获取DOM元素
  158.         const patternInput = document.getElementById('patternInput');
  159.         const styleSelect = document.getElementById('styleSelect');
  160.         const caseSensitiveCheckbox = document.getElementById('caseSensitive');
  161.         const contentArea = document.getElementById('contentArea');
  162.         const messageDiv = document.getElementById('message');
  163.         
  164.         // 获取按钮
  165.         const applyStyleBtn = document.getElementById('applyStyle');
  166.         const clearStylesBtn = document.getElementById('clearStyles');
  167.         const presetExampleBtn = document.getElementById('presetExample');
  168.         
  169.         // 显示消息
  170.         function showMessage(text, type) {
  171.             messageDiv.textContent = text;
  172.             messageDiv.className = 'message ' + type;
  173.             messageDiv.style.display = 'block';
  174.             
  175.             // 3秒后隐藏消息
  176.             setTimeout(() => {
  177.                 messageDiv.style.display = 'none';
  178.             }, 3000);
  179.         }
  180.         
  181.         // 应用样式
  182.         function applyStyle() {
  183.             const pattern = patternInput.value.trim();
  184.             if (!pattern) {
  185.                 showMessage('请输入正则表达式模式', 'error');
  186.                 return;
  187.             }
  188.             
  189.             const style = styleSelect.value;
  190.             const caseSensitive = caseSensitiveCheckbox.checked;
  191.             
  192.             try {
  193.                 // 创建正则表达式
  194.                 const flags = caseSensitive ? 'g' : 'gi';
  195.                 const regex = new RegExp(pattern, flags);
  196.                
  197.                 // 获取内容区域的所有文本节点
  198.                 const walker = document.createTreeWalker(
  199.                     contentArea,
  200.                     NodeFilter.SHOW_TEXT,
  201.                     null,
  202.                     false
  203.                 );
  204.                
  205.                 let node;
  206.                 const nodesToProcess = [];
  207.                
  208.                 // 收集所有文本节点
  209.                 while (node = walker.nextNode()) {
  210.                     // 跳过脚本和样式元素内的文本
  211.                     if (node.parentNode.tagName !== 'SCRIPT' && node.parentNode.tagName !== 'STYLE') {
  212.                         nodesToProcess.push(node);
  213.                     }
  214.                 }
  215.                
  216.                 // 处理每个文本节点
  217.                 nodesToProcess.forEach(textNode => {
  218.                     const text = textNode.textContent;
  219.                     let match;
  220.                     let lastIndex = 0;
  221.                     const fragment = document.createDocumentFragment();
  222.                     
  223.                     // 重置正则表达式的lastIndex
  224.                     regex.lastIndex = 0;
  225.                     
  226.                     while ((match = regex.exec(text)) !== null) {
  227.                         // 添加匹配前的文本
  228.                         if (match.index > lastIndex) {
  229.                             fragment.appendChild(document.createTextNode(text.substring(lastIndex, match.index)));
  230.                         }
  231.                         
  232.                         // 创建匹配文本的span并应用样式
  233.                         const span = document.createElement('span');
  234.                         span.className = style;
  235.                         span.textContent = match[0];
  236.                         fragment.appendChild(span);
  237.                         
  238.                         lastIndex = regex.lastIndex;
  239.                     }
  240.                     
  241.                     // 添加剩余的文本
  242.                     if (lastIndex < text.length) {
  243.                         fragment.appendChild(document.createTextNode(text.substring(lastIndex)));
  244.                     }
  245.                     
  246.                     // 替换原始文本节点
  247.                     if (fragment.childNodes.length > 1 || (fragment.childNodes.length === 1 && fragment.firstChild.nodeType !== Node.TEXT_NODE)) {
  248.                         textNode.parentNode.replaceChild(fragment, textNode);
  249.                     }
  250.                 });
  251.                
  252.                 showMessage('样式应用成功', 'success');
  253.             } catch (error) {
  254.                 showMessage('正则表达式错误: ' + error.message, 'error');
  255.                 console.error('正则表达式错误:', error);
  256.             }
  257.         }
  258.         
  259.         // 清除所有样式
  260.         function clearStyles() {
  261.             // 获取所有带有样式的span元素
  262.             const styledSpans = contentArea.querySelectorAll('span[class*="highlight"], span.underline, span.italic, span.bold, span.uppercase, span.lowercase');
  263.             
  264.             styledSpans.forEach(span => {
  265.                 const parent = span.parentNode;
  266.                
  267.                 // 用文本节点替换span元素
  268.                 parent.replaceChild(document.createTextNode(span.textContent), span);
  269.                
  270.                 // 合并相邻的文本节点
  271.                 parent.normalize();
  272.             });
  273.             
  274.             showMessage('已清除所有样式', 'success');
  275.         }
  276.         
  277.         // 使用示例
  278.         function usePresetExample() {
  279.             patternInput.value = '\\d+';  // 匹配数字
  280.             styleSelect.value = 'highlight-blue';  // 蓝色高亮
  281.             caseSensitiveCheckbox.checked = false;
  282.             
  283.             // 应用样式
  284.             applyStyle();
  285.         }
  286.         
  287.         // 添加事件监听器
  288.         applyStyleBtn.addEventListener('click', applyStyle);
  289.         clearStylesBtn.addEventListener('click', clearStyles);
  290.         presetExampleBtn.addEventListener('click', usePresetExample);
  291.         
  292.         // 添加回车键支持
  293.         patternInput.addEventListener('keypress', function(event) {
  294.             if (event.key === 'Enter') {
  295.                 applyStyle();
  296.             }
  297.         });
  298.     </script>
  299. </body>
  300. </html>
复制代码

5. 实战案例

5.1 实时表单验证

我们已经在前面的章节中展示了一个完整的表单验证示例。这个示例结合了正则表达式用于验证各种输入格式,以及DOM操作用于实时显示验证结果和错误消息。

5.2 动态搜索和过滤功能

同样,我们在前面也展示了一个实时搜索和过滤联系人列表的示例。这个示例使用了正则表达式来匹配搜索词,并通过DOM操作来动态显示或隐藏列表项,以及高亮显示匹配的文本。

5.3 内容高亮显示

让我们再看一个更复杂的内容高亮显示示例,它可以同时高亮多种不同类型的模式:
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>多模式内容高亮</title>
  7.     <style>
  8.         body {
  9.             font-family: Arial, sans-serif;
  10.             max-width: 900px;
  11.             margin: 0 auto;
  12.             padding: 20px;
  13.         }
  14.         h1 {
  15.             text-align: center;
  16.         }
  17.         .container {
  18.             display: flex;
  19.             flex-direction: column;
  20.             gap: 20px;
  21.         }
  22.         .panel {
  23.             border: 1px solid #ddd;
  24.             border-radius: 5px;
  25.             padding: 15px;
  26.         }
  27.         .panel-title {
  28.             font-weight: bold;
  29.             margin-bottom: 10px;
  30.             font-size: 18px;
  31.         }
  32.         .highlight-controls {
  33.             display: grid;
  34.             grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  35.             gap: 15px;
  36.         }
  37.         .highlight-control {
  38.             display: flex;
  39.             flex-direction: column;
  40.             gap: 5px;
  41.         }
  42.         .highlight-control label {
  43.             display: flex;
  44.             align-items: center;
  45.             gap: 5px;
  46.             font-weight: normal;
  47.         }
  48.         .highlight-control input[type="text"] {
  49.             padding: 5px;
  50.             border: 1px solid #ddd;
  51.             border-radius: 3px;
  52.         }
  53.         .highlight-control select {
  54.             padding: 5px;
  55.             border: 1px solid #ddd;
  56.             border-radius: 3px;
  57.         }
  58.         .color-picker {
  59.             display: flex;
  60.             gap: 5px;
  61.             align-items: center;
  62.         }
  63.         .color-picker input[type="color"] {
  64.             width: 30px;
  65.             height: 30px;
  66.             border: none;
  67.             border-radius: 3px;
  68.             cursor: pointer;
  69.         }
  70.         .content-area {
  71.             min-height: 300px;
  72.             padding: 15px;
  73.             border: 1px solid #ddd;
  74.             border-radius: 5px;
  75.             line-height: 1.6;
  76.         }
  77.         .button-group {
  78.             display: flex;
  79.             gap: 10px;
  80.             margin-top: 15px;
  81.         }
  82.         button {
  83.             padding: 8px 15px;
  84.             background-color: #4CAF50;
  85.             color: white;
  86.             border: none;
  87.             border-radius: 4px;
  88.             cursor: pointer;
  89.         }
  90.         button:hover {
  91.             background-color: #45a049;
  92.         }
  93.         button.secondary {
  94.             background-color: #2196F3;
  95.         }
  96.         button.secondary:hover {
  97.             background-color: #0b7dda;
  98.         }
  99.         .message {
  100.             margin-top: 10px;
  101.             padding: 10px;
  102.             border-radius: 4px;
  103.             display: none;
  104.         }
  105.         .success {
  106.             background-color: #dff0d8;
  107.             color: #3c763d;
  108.         }
  109.         .error {
  110.             background-color: #f2dede;
  111.             color: #a94442;
  112.         }
  113.         /* 高亮样式类 */
  114.         .highlight-yellow {
  115.             background-color: yellow;
  116.         }
  117.         .highlight-green {
  118.             background-color: #90EE90;
  119.         }
  120.         .highlight-blue {
  121.             background-color: #ADD8E6;
  122.         }
  123.         .highlight-red {
  124.             background-color: #FFB6C1;
  125.         }
  126.         .highlight-purple {
  127.             background-color: #D8BFD8;
  128.         }
  129.         .highlight-orange {
  130.             background-color: #FFD700;
  131.         }
  132.         .highlight-custom {
  133.             padding: 2px 4px;
  134.             border-radius: 3px;
  135.         }
  136.         .highlight-underline {
  137.             text-decoration: underline;
  138.             text-decoration-style: wavy;
  139.             text-decoration-color: red;
  140.         }
  141.         .highlight-bold {
  142.             font-weight: bold;
  143.         }
  144.         .highlight-italic {
  145.             font-style: italic;
  146.         }
  147.     </style>
  148. </head>
  149. <body>
  150.     <h1>多模式内容高亮工具</h1>
  151.    
  152.     <div class="container">
  153.         <div class="panel">
  154.             <div class="panel-title">高亮规则设置</div>
  155.             <div class="highlight-controls" id="highlightControls">
  156.                 <!-- 默认高亮规则 -->
  157.                 <div class="highlight-control">
  158.                     <label>
  159.                         <input type="checkbox" checked>
  160.                         <span>电子邮件</span>
  161.                     </label>
  162.                     <input type="text" value="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" readonly>
  163.                     <select class="highlight-style">
  164.                         <option value="highlight-blue">蓝色高亮</option>
  165.                         <option value="highlight-green">绿色高亮</option>
  166.                         <option value="highlight-yellow">黄色高亮</option>
  167.                         <option value="highlight-red">红色高亮</option>
  168.                         <option value="highlight-purple">紫色高亮</option>
  169.                         <option value="highlight-orange">橙色高亮</option>
  170.                         <option value="highlight-underline">下划线</option>
  171.                         <option value="highlight-bold">粗体</option>
  172.                         <option value="highlight-italic">斜体</option>
  173.                         <option value="highlight-custom">自定义颜色</option>
  174.                     </select>
  175.                     <div class="color-picker" style="display: none;">
  176.                         <input type="color" value="#FFFF00">
  177.                         <span>背景色</span>
  178.                     </div>
  179.                 </div>
  180.                
  181.                 <div class="highlight-control">
  182.                     <label>
  183.                         <input type="checkbox" checked>
  184.                         <span>电话号码</span>
  185.                     </label>
  186.                     <input type="text" value="(\d{3,4}-?)?\d{7,8}(?=-?\d{3,4})?|-?\d{3,4}-?\d{7,8}" readonly>
  187.                     <select class="highlight-style">
  188.                         <option value="highlight-blue">蓝色高亮</option>
  189.                         <option value="highlight-green" selected>绿色高亮</option>
  190.                         <option value="highlight-yellow">黄色高亮</option>
  191.                         <option value="highlight-red">红色高亮</option>
  192.                         <option value="highlight-purple">紫色高亮</option>
  193.                         <option value="highlight-orange">橙色高亮</option>
  194.                         <option value="highlight-underline">下划线</option>
  195.                         <option value="highlight-bold">粗体</option>
  196.                         <option value="highlight-italic">斜体</option>
  197.                         <option value="highlight-custom">自定义颜色</option>
  198.                     </select>
  199.                     <div class="color-picker" style="display: none;">
  200.                         <input type="color" value="#90EE90">
  201.                         <span>背景色</span>
  202.                     </div>
  203.                 </div>
  204.                
  205.                 <div class="highlight-control">
  206.                     <label>
  207.                         <input type="checkbox" checked>
  208.                         <span>网址</span>
  209.                     </label>
  210.                     <input type="text" value="https?:\/\/[^\s]+" readonly>
  211.                     <select class="highlight-style">
  212.                         <option value="highlight-blue">蓝色高亮</option>
  213.                         <option value="highlight-green">绿色高亮</option>
  214.                         <option value="highlight-yellow">黄色高亮</option>
  215.                         <option value="highlight-red">红色高亮</option>
  216.                         <option value="highlight-purple">紫色高亮</option>
  217.                         <option value="highlight-orange" selected>橙色高亮</option>
  218.                         <option value="highlight-underline">下划线</option>
  219.                         <option value="highlight-bold">粗体</option>
  220.                         <option value="highlight-italic">斜体</option>
  221.                         <option value="highlight-custom">自定义颜色</option>
  222.                     </select>
  223.                     <div class="color-picker" style="display: none;">
  224.                         <input type="color" value="#FFD700">
  225.                         <span>背景色</span>
  226.                     </div>
  227.                 </div>
  228.                
  229.                 <div class="highlight-control">
  230.                     <label>
  231.                         <input type="checkbox">
  232.                         <span>日期</span>
  233.                     </label>
  234.                     <input type="text" value="\d{4}-\d{2}-\d{2}|\d{2}/\d{2}/\d{4}">
  235.                     <select class="highlight-style">
  236.                         <option value="highlight-blue">蓝色高亮</option>
  237.                         <option value="highlight-green">绿色高亮</option>
  238.                         <option value="highlight-yellow">黄色高亮</option>
  239.                         <option value="highlight-red">红色高亮</option>
  240.                         <option value="highlight-purple" selected>紫色高亮</option>
  241.                         <option value="highlight-orange">橙色高亮</option>
  242.                         <option value="highlight-underline">下划线</option>
  243.                         <option value="highlight-bold">粗体</option>
  244.                         <option value="highlight-italic">斜体</option>
  245.                         <option value="highlight-custom">自定义颜色</option>
  246.                     </select>
  247.                     <div class="color-picker" style="display: none;">
  248.                         <input type="color" value="#D8BFD8">
  249.                         <span>背景色</span>
  250.                     </div>
  251.                 </div>
  252.             </div>
  253.             
  254.             <div class="button-group">
  255.                 <button id="addRule">添加规则</button>
  256.                 <button id="applyHighlights" class="secondary">应用高亮</button>
  257.                 <button id="clearHighlights">清除高亮</button>
  258.             </div>
  259.             
  260.             <div id="message" class="message"></div>
  261.         </div>
  262.         
  263.         <div class="panel">
  264.             <div class="panel-title">内容区域</div>
  265.             <div class="content-area" id="contentArea">
  266.                 <h2>联系我们</h2>
  267.                 <p>如果您有任何问题或建议,请通过以下方式联系我们:</p>
  268.                 <p>电子邮件:contact@example.com 或 support@example.org</p>
  269.                 <p>电话:010-12345678 或 13800138000</p>
  270.                 <p>访问我们的网站:https://www.example.com 或 http://blog.example.org</p>
  271.                 <p>办公时间:周一至周五,9:00-18:00</p>
  272.                 <p>地址:北京市朝阳区某某街道123号</p>
  273.                 <p>邮政编码:100020</p>
  274.                
  275.                 <h2>活动安排</h2>
  276.                 <p>2023-06-15:产品发布会</p>
  277.                 <p>2023/07/20:夏季促销活动</p>
  278.                 <p>2023-08-10:技术研讨会</p>
  279.                 <p>2023/09/05:秋季新品展示</p>
  280.                
  281.                 <h2>价格信息</h2>
  282.                 <p>标准版:$99.00</p>
  283.                 <p>专业版:¥199.00</p>
  284.                 <p>企业版:$299.00</p>
  285.                
  286.                 <h2>其他联系方式</h2>
  287.                 <p>QQ:123456789</p>
  288.                 <p>微信:example_company</p>
  289.                 <p>微博:@example公司</p>
  290.             </div>
  291.         </div>
  292.     </div>
  293.     <script>
  294.         // 获取DOM元素
  295.         const highlightControls = document.getElementById('highlightControls');
  296.         const contentArea = document.getElementById('contentArea');
  297.         const messageDiv = document.getElementById('message');
  298.         
  299.         // 获取按钮
  300.         const addRuleBtn = document.getElementById('addRule');
  301.         const applyHighlightsBtn = document.getElementById('applyHighlights');
  302.         const clearHighlightsBtn = document.getElementById('clearHighlights');
  303.         
  304.         // 显示消息
  305.         function showMessage(text, type) {
  306.             messageDiv.textContent = text;
  307.             messageDiv.className = 'message ' + type;
  308.             messageDiv.style.display = 'block';
  309.             
  310.             // 3秒后隐藏消息
  311.             setTimeout(() => {
  312.                 messageDiv.style.display = 'none';
  313.             }, 3000);
  314.         }
  315.         
  316.         // 添加高亮规则
  317.         function addHighlightRule(name = '', pattern = '', enabled = true, style = 'highlight-yellow', color = '#FFFF00') {
  318.             const ruleDiv = document.createElement('div');
  319.             ruleDiv.className = 'highlight-control';
  320.             
  321.             ruleDiv.innerHTML = `
  322.                 <label>
  323.                     <input type="checkbox" ${enabled ? 'checked' : ''}>
  324.                     <span>${name || '自定义规则'}</span>
  325.                 </label>
  326.                 <input type="text" value="${pattern}" placeholder="输入正则表达式">
  327.                 <select class="highlight-style">
  328.                     <option value="highlight-blue" ${style === 'highlight-blue' ? 'selected' : ''}>蓝色高亮</option>
  329.                     <option value="highlight-green" ${style === 'highlight-green' ? 'selected' : ''}>绿色高亮</option>
  330.                     <option value="highlight-yellow" ${style === 'highlight-yellow' ? 'selected' : ''}>黄色高亮</option>
  331.                     <option value="highlight-red" ${style === 'highlight-red' ? 'selected' : ''}>红色高亮</option>
  332.                     <option value="highlight-purple" ${style === 'highlight-purple' ? 'selected' : ''}>紫色高亮</option>
  333.                     <option value="highlight-orange" ${style === 'highlight-orange' ? 'selected' : ''}>橙色高亮</option>
  334.                     <option value="highlight-underline" ${style === 'highlight-underline' ? 'selected' : ''}>下划线</option>
  335.                     <option value="highlight-bold" ${style === 'highlight-bold' ? 'selected' : ''}>粗体</option>
  336.                     <option value="highlight-italic" ${style === 'highlight-italic' ? 'selected' : ''}>斜体</option>
  337.                     <option value="highlight-custom" ${style === 'highlight-custom' ? 'selected' : ''}>自定义颜色</option>
  338.                 </select>
  339.                 <div class="color-picker" style="display: ${style === 'highlight-custom' ? 'flex' : 'none'};">
  340.                     <input type="color" value="${color}">
  341.                     <span>背景色</span>
  342.                 </div>
  343.                 <button class="remove-rule" style="margin-top: 5px; padding: 3px 8px; background-color: #f44336;">删除</button>
  344.             `;
  345.             
  346.             highlightControls.appendChild(ruleDiv);
  347.             
  348.             // 添加事件监听器
  349.             const styleSelect = ruleDiv.querySelector('.highlight-style');
  350.             const colorPicker = ruleDiv.querySelector('.color-picker');
  351.             const removeBtn = ruleDiv.querySelector('.remove-rule');
  352.             
  353.             styleSelect.addEventListener('change', function() {
  354.                 colorPicker.style.display = this.value === 'highlight-custom' ? 'flex' : 'none';
  355.             });
  356.             
  357.             removeBtn.addEventListener('click', function() {
  358.                 ruleDiv.remove();
  359.             });
  360.         }
  361.         
  362.         // 应用高亮
  363.         function applyHighlights() {
  364.             // 清除现有高亮
  365.             clearHighlights(false);
  366.             
  367.             // 获取所有规则
  368.             const rules = [];
  369.             const ruleElements = highlightControls.querySelectorAll('.highlight-control');
  370.             
  371.             ruleElements.forEach(ruleElement => {
  372.                 const enabled = ruleElement.querySelector('input[type="checkbox"]').checked;
  373.                 if (!enabled) return;
  374.                
  375.                 const pattern = ruleElement.querySelector('input[type="text"]').value.trim();
  376.                 if (!pattern) return;
  377.                
  378.                 const style = ruleElement.querySelector('.highlight-style').value;
  379.                 const color = style === 'highlight-custom' ?
  380.                     ruleElement.querySelector('.color-picker input[type="color"]').value :
  381.                     '';
  382.                
  383.                 rules.push({
  384.                     pattern: pattern,
  385.                     style: style,
  386.                     color: color
  387.                 });
  388.             });
  389.             
  390.             if (rules.length === 0) {
  391.                 showMessage('没有启用的规则', 'error');
  392.                 return;
  393.             }
  394.             
  395.             try {
  396.                 // 获取内容区域的所有文本节点
  397.                 const walker = document.createTreeWalker(
  398.                     contentArea,
  399.                     NodeFilter.SHOW_TEXT,
  400.                     null,
  401.                     false
  402.                 );
  403.                
  404.                 let node;
  405.                 const nodesToProcess = [];
  406.                
  407.                 // 收集所有文本节点
  408.                 while (node = walker.nextNode()) {
  409.                     // 跳过脚本和样式元素内的文本
  410.                     if (node.parentNode.tagName !== 'SCRIPT' && node.parentNode.tagName !== 'STYLE') {
  411.                         nodesToProcess.push(node);
  412.                     }
  413.                 }
  414.                
  415.                 // 处理每个文本节点
  416.                 nodesToProcess.forEach(textNode => {
  417.                     const text = textNode.textContent;
  418.                     let matches = [];
  419.                     
  420.                     // 收集所有匹配
  421.                     rules.forEach(rule => {
  422.                         try {
  423.                             const regex = new RegExp(rule.pattern, 'gi');
  424.                             let match;
  425.                             while ((match = regex.exec(text)) !== null) {
  426.                                 matches.push({
  427.                                     text: match[0],
  428.                                     index: match.index,
  429.                                     length: match[0].length,
  430.                                     style: rule.style,
  431.                                     color: rule.color
  432.                                 });
  433.                             }
  434.                         } catch (error) {
  435.                             console.error('正则表达式错误:', error, '模式:', rule.pattern);
  436.                         }
  437.                     });
  438.                     
  439.                     // 按索引排序匹配
  440.                     matches.sort((a, b) => a.index - b.index);
  441.                     
  442.                     // 如果没有匹配,跳过此节点
  443.                     if (matches.length === 0) return;
  444.                     
  445.                     // 创建文档片段
  446.                     const fragment = document.createDocumentFragment();
  447.                     let lastIndex = 0;
  448.                     
  449.                     // 处理匹配
  450.                     matches.forEach(match => {
  451.                         // 添加匹配前的文本
  452.                         if (match.index > lastIndex) {
  453.                             fragment.appendChild(document.createTextNode(text.substring(lastIndex, match.index)));
  454.                         }
  455.                         
  456.                         // 创建匹配文本的span并应用样式
  457.                         const span = document.createElement('span');
  458.                         span.className = match.style;
  459.                         if (match.style === 'highlight-custom') {
  460.                             span.style.backgroundColor = match.color;
  461.                         }
  462.                         span.textContent = match.text;
  463.                         fragment.appendChild(span);
  464.                         
  465.                         lastIndex = match.index + match.length;
  466.                     });
  467.                     
  468.                     // 添加剩余的文本
  469.                     if (lastIndex < text.length) {
  470.                         fragment.appendChild(document.createTextNode(text.substring(lastIndex)));
  471.                     }
  472.                     
  473.                     // 替换原始文本节点
  474.                     textNode.parentNode.replaceChild(fragment, textNode);
  475.                 });
  476.                
  477.                 showMessage(`成功应用了 ${rules.length} 个高亮规则`, 'success');
  478.             } catch (error) {
  479.                 showMessage('应用高亮时出错: ' + error.message, 'error');
  480.                 console.error('应用高亮时出错:', error);
  481.             }
  482.         }
  483.         
  484.         // 清除高亮
  485.         function clearHighlights(showMessage = true) {
  486.             // 获取所有带有高亮样式的span元素
  487.             const highlightedSpans = contentArea.querySelectorAll('span[class*="highlight"]');
  488.             
  489.             highlightedSpans.forEach(span => {
  490.                 const parent = span.parentNode;
  491.                
  492.                 // 用文本节点替换span元素
  493.                 parent.replaceChild(document.createTextNode(span.textContent), span);
  494.                
  495.                 // 合并相邻的文本节点
  496.                 parent.normalize();
  497.             });
  498.             
  499.             if (showMessage) {
  500.                 showMessage('已清除所有高亮', 'success');
  501.             }
  502.         }
  503.         
  504.         // 添加事件监听器
  505.         addRuleBtn.addEventListener('click', function() {
  506.             addHighlightRule();
  507.         });
  508.         
  509.         applyHighlightsBtn.addEventListener('click', applyHighlights);
  510.         clearHighlightsBtn.addEventListener('click', () => clearHighlights(true));
  511.         
  512.         // 为现有的样式选择器添加事件监听器
  513.         document.querySelectorAll('.highlight-control').forEach(control => {
  514.             const styleSelect = control.querySelector('.highlight-style');
  515.             const colorPicker = control.querySelector('.color-picker');
  516.             
  517.             if (styleSelect && colorPicker) {
  518.                 styleSelect.addEventListener('change', function() {
  519.                     colorPicker.style.display = this.value === 'highlight-custom' ? 'flex' : 'none';
  520.                 });
  521.             }
  522.             
  523.             const removeBtn = control.querySelector('.remove-rule');
  524.             if (removeBtn) {
  525.                 removeBtn.addEventListener('click', function() {
  526.                     control.remove();
  527.                 });
  528.             }
  529.         });
  530.     </script>
  531. </body>
  532. </html>
复制代码

5.4 数据格式化和展示

以下是一个数据格式化和展示的示例,它使用正则表达式来解析和格式化不同类型的数据:
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>数据格式化和展示</title>
  7.     <style>
  8.         body {
  9.             font-family: Arial, sans-serif;
  10.             max-width: 1000px;
  11.             margin: 0 auto;
  12.             padding: 20px;
  13.         }
  14.         h1 {
  15.             text-align: center;
  16.         }
  17.         .container {
  18.             display: flex;
  19.             flex-direction: column;
  20.             gap: 20px;
  21.         }
  22.         .panel {
  23.             border: 1px solid #ddd;
  24.             border-radius: 5px;
  25.             padding: 15px;
  26.         }
  27.         .panel-title {
  28.             font-weight: bold;
  29.             margin-bottom: 10px;
  30.             font-size: 18px;
  31.         }
  32.         .input-group {
  33.             margin-bottom: 15px;
  34.         }
  35.         .input-group label {
  36.             display: block;
  37.             margin-bottom: 5px;
  38.             font-weight: bold;
  39.         }
  40.         textarea {
  41.             width: 100%;
  42.             height: 150px;
  43.             padding: 10px;
  44.             border: 1px solid #ddd;
  45.             border-radius: 4px;
  46.             resize: vertical;
  47.             font-family: inherit;
  48.         }
  49.         .button-group {
  50.             display: flex;
  51.             gap: 10px;
  52.             margin-top: 10px;
  53.         }
  54.         button {
  55.             padding: 8px 15px;
  56.             background-color: #4CAF50;
  57.             color: white;
  58.             border: none;
  59.             border-radius: 4px;
  60.             cursor: pointer;
  61.         }
  62.         button:hover {
  63.             background-color: #45a049;
  64.         }
  65.         button.secondary {
  66.             background-color: #2196F3;
  67.         }
  68.         button.secondary:hover {
  69.             background-color: #0b7dda;
  70.         }
  71.         .tabs {
  72.             display: flex;
  73.             border-bottom: 1px solid #ddd;
  74.             margin-bottom: 15px;
  75.         }
  76.         .tab {
  77.             padding: 10px 15px;
  78.             cursor: pointer;
  79.             border: 1px solid transparent;
  80.             border-bottom: none;
  81.             border-radius: 4px 4px 0 0;
  82.             margin-right: 5px;
  83.             background-color: #f1f1f1;
  84.         }
  85.         .tab.active {
  86.             background-color: white;
  87.             border-color: #ddd;
  88.             border-bottom-color: white;
  89.             margin-bottom: -1px;
  90.             font-weight: bold;
  91.         }
  92.         .tab-content {
  93.             display: none;
  94.         }
  95.         .tab-content.active {
  96.             display: block;
  97.         }
  98.         table {
  99.             width: 100%;
  100.             border-collapse: collapse;
  101.             margin-top: 10px;
  102.         }
  103.         table, th, td {
  104.             border: 1px solid #ddd;
  105.         }
  106.         th, td {
  107.             padding: 8px;
  108.             text-align: left;
  109.         }
  110.         th {
  111.             background-color: #f2f2f2;
  112.         }
  113.         tr:nth-child(even) {
  114.             background-color: #f9f9f9;
  115.         }
  116.         .data-card {
  117.             border: 1px solid #ddd;
  118.             border-radius: 5px;
  119.             padding: 15px;
  120.             margin-bottom: 15px;
  121.             background-color: #f9f9f9;
  122.         }
  123.         .data-card h3 {
  124.             margin-top: 0;
  125.             color: #333;
  126.         }
  127.         .data-card .data-item {
  128.             margin-bottom: 8px;
  129.         }
  130.         .data-card .data-label {
  131.             font-weight: bold;
  132.             display: inline-block;
  133.             width: 120px;
  134.         }
  135.         .message {
  136.             margin-top: 10px;
  137.             padding: 10px;
  138.             border-radius: 4px;
  139.             display: none;
  140.         }
  141.         .success {
  142.             background-color: #dff0d8;
  143.             color: #3c763d;
  144.         }
  145.         .error {
  146.             background-color: #f2dede;
  147.             color: #a94442;
  148.         }
  149.         .no-data {
  150.             text-align: center;
  151.             padding: 20px;
  152.             color: #666;
  153.         }
  154.     </style>
  155. </head>
  156. <body>
  157.     <h1>数据格式化和展示工具</h1>
  158.    
  159.     <div class="container">
  160.         <div class="panel">
  161.             <div class="panel-title">输入数据</div>
  162.             <div class="input-group">
  163.                 <label for="inputData">输入原始数据 (支持多种格式):</label>
  164.                 <textarea id="inputData" placeholder="在此输入要格式化的数据,例如:
  165. 姓名: 张三, 年龄: 30, 邮箱: zhangsan@example.com, 电话: 13800138000
  166. 姓名: 李四, 年龄: 25, 邮箱: lisi@example.com, 电话: 13900139000
  167. 姓名: 王五, 年龄: 35, 邮箱: wangwu@example.com, 电话: 13700137000"></textarea>
  168.             </div>
  169.             <div class="button-group">
  170.                 <button id="parseData">解析数据</button>
  171.                 <button id="clearData" class="secondary">清除数据</button>
  172.                 <button id="loadSample" class="secondary">加载示例数据</button>
  173.             </div>
  174.             <div id="message" class="message"></div>
  175.         </div>
  176.         
  177.         <div class="panel">
  178.             <div class="panel-title">格式化结果</div>
  179.             <div class="tabs">
  180.                 <div class="tab active" data-tab="table">表格视图</div>
  181.                 <div class="tab" data-tab="cards">卡片视图</div>
  182.                 <div class="tab" data-tab="json">JSON视图</div>
  183.             </div>
  184.             
  185.             <div id="tableTab" class="tab-content active">
  186.                 <div id="tableContainer">
  187.                     <div class="no-data">暂无数据,请先输入并解析数据</div>
  188.                 </div>
  189.             </div>
  190.             
  191.             <div id="cardsTab" class="tab-content">
  192.                 <div id="cardsContainer">
  193.                     <div class="no-data">暂无数据,请先输入并解析数据</div>
  194.                 </div>
  195.             </div>
  196.             
  197.             <div id="jsonTab" class="tab-content">
  198.                 <div class="input-group">
  199.                     <label for="jsonOutput">JSON格式数据:</label>
  200.                     <textarea id="jsonOutput" readonly placeholder="JSON格式的数据将显示在这里..."></textarea>
  201.                 </div>
  202.             </div>
  203.         </div>
  204.     </div>
  205.     <script>
  206.         // 获取DOM元素
  207.         const inputData = document.getElementById('inputData');
  208.         const messageDiv = document.getElementById('message');
  209.         const tableContainer = document.getElementById('tableContainer');
  210.         const cardsContainer = document.getElementById('cardsContainer');
  211.         const jsonOutput = document.getElementById('jsonOutput');
  212.         
  213.         // 获取按钮
  214.         const parseDataBtn = document.getElementById('parseData');
  215.         const clearDataBtn = document.getElementById('clearData');
  216.         const loadSampleBtn = document.getElementById('loadSample');
  217.         
  218.         // 获取标签页
  219.         const tabs = document.querySelectorAll('.tab');
  220.         const tabContents = document.querySelectorAll('.tab-content');
  221.         
  222.         // 存储解析后的数据
  223.         let parsedData = [];
  224.         
  225.         // 显示消息
  226.         function showMessage(text, type) {
  227.             messageDiv.textContent = text;
  228.             messageDiv.className = 'message ' + type;
  229.             messageDiv.style.display = 'block';
  230.             
  231.             // 3秒后隐藏消息
  232.             setTimeout(() => {
  233.                 messageDiv.style.display = 'none';
  234.             }, 3000);
  235.         }
  236.         
  237.         // 标签页切换
  238.         tabs.forEach(tab => {
  239.             tab.addEventListener('click', function() {
  240.                 const tabId = this.getAttribute('data-tab');
  241.                
  242.                 // 移除所有活动状态
  243.                 tabs.forEach(t => t.classList.remove('active'));
  244.                 tabContents.forEach(c => c.classList.remove('active'));
  245.                
  246.                 // 添加当前活动状态
  247.                 this.classList.add('active');
  248.                 document.getElementById(tabId + 'Tab').classList.add('active');
  249.             });
  250.         });
  251.         
  252.         // 解析数据
  253.         function parseData() {
  254.             const input = inputData.value.trim();
  255.             if (!input) {
  256.                 showMessage('请输入数据', 'error');
  257.                 return;
  258.             }
  259.             
  260.             try {
  261.                 // 尝试解析不同格式的数据
  262.                 parsedData = [];
  263.                
  264.                 // 尝试解析键值对格式 (例如: 姓名: 张三, 年龄: 30)
  265.                 if (input.includes(':') && (input.includes(',') || input.includes('\n'))) {
  266.                     parseKeyValueFormat(input);
  267.                 }
  268.                 // 尝试解析CSV格式
  269.                 else if (input.includes(',')) {
  270.                     parseCSVFormat(input);
  271.                 }
  272.                 // 尝试解析JSON格式
  273.                 else if (input.startsWith('[') || input.startsWith('{')) {
  274.                     parseJSONFormat(input);
  275.                 }
  276.                 // 尝试解析每行一个记录的格式
  277.                 else if (input.includes('\n')) {
  278.                     parseLineFormat(input);
  279.                 }
  280.                 else {
  281.                     showMessage('无法识别的数据格式', 'error');
  282.                     return;
  283.                 }
  284.                
  285.                 if (parsedData.length === 0) {
  286.                     showMessage('未能解析出有效数据', 'error');
  287.                     return;
  288.                 }
  289.                
  290.                 // 显示解析结果
  291.                 displayData();
  292.                 showMessage(`成功解析了 ${parsedData.length} 条记录`, 'success');
  293.                
  294.             } catch (error) {
  295.                 showMessage('解析数据时出错: ' + error.message, 'error');
  296.                 console.error('解析数据时出错:', error);
  297.             }
  298.         }
  299.         
  300.         // 解析键值对格式
  301.         function parseKeyValueFormat(input) {
  302.             const lines = input.split('\n');
  303.             let currentRecord = {};
  304.             
  305.             lines.forEach(line => {
  306.                 line = line.trim();
  307.                 if (!line) return;
  308.                
  309.                 // 使用正则表达式匹配键值对
  310.                 const keyValuePairs = line.match(/([^:,\s]+)\s*:\s*([^,]+)/g);
  311.                
  312.                 if (keyValuePairs) {
  313.                     // 如果是新记录,保存上一条记录
  314.                     if (Object.keys(currentRecord).length > 0) {
  315.                         parsedData.push(currentRecord);
  316.                         currentRecord = {};
  317.                     }
  318.                     
  319.                     // 解析键值对
  320.                     keyValuePairs.forEach(pair => {
  321.                         const match = pair.match(/([^:,\s]+)\s*:\s*([^,]+)/);
  322.                         if (match) {
  323.                             const key = match[1].trim();
  324.                             const value = match[2].trim();
  325.                            
  326.                             // 尝试转换数值
  327.                             if (/^\d+$/.test(value)) {
  328.                                 currentRecord[key] = parseInt(value, 10);
  329.                             } else if (/^\d+\.\d+$/.test(value)) {
  330.                                 currentRecord[key] = parseFloat(value);
  331.                             } else {
  332.                                 currentRecord[key] = value;
  333.                             }
  334.                         }
  335.                     });
  336.                 }
  337.             });
  338.             
  339.             // 添加最后一条记录
  340.             if (Object.keys(currentRecord).length > 0) {
  341.                 parsedData.push(currentRecord);
  342.             }
  343.         }
  344.         
  345.         // 解析CSV格式
  346.         function parseCSVFormat(input) {
  347.             const lines = input.split('\n');
  348.             if (lines.length < 2) return;
  349.             
  350.             // 解析标题行
  351.             const headers = lines[0].split(',').map(h => h.trim());
  352.             
  353.             // 解析数据行
  354.             for (let i = 1; i < lines.length; i++) {
  355.                 const line = lines[i].trim();
  356.                 if (!line) continue;
  357.                
  358.                 const values = line.split(',').map(v => v.trim());
  359.                 if (values.length !== headers.length) continue;
  360.                
  361.                 const record = {};
  362.                 headers.forEach((header, index) => {
  363.                     const value = values[index];
  364.                     
  365.                     // 尝试转换数值
  366.                     if (/^\d+$/.test(value)) {
  367.                         record[header] = parseInt(value, 10);
  368.                     } else if (/^\d+\.\d+$/.test(value)) {
  369.                         record[header] = parseFloat(value);
  370.                     } else {
  371.                         record[header] = value;
  372.                     }
  373.                 });
  374.                
  375.                 parsedData.push(record);
  376.             }
  377.         }
  378.         
  379.         // 解析JSON格式
  380.         function parseJSONFormat(input) {
  381.             const data = JSON.parse(input);
  382.             
  383.             if (Array.isArray(data)) {
  384.                 parsedData = data;
  385.             } else if (typeof data === 'object') {
  386.                 parsedData = [data];
  387.             }
  388.         }
  389.         
  390.         // 解析每行一个记录的格式
  391.         function parseLineFormat(input) {
  392.             const lines = input.split('\n');
  393.             
  394.             lines.forEach(line => {
  395.                 line = line.trim();
  396.                 if (!line) return;
  397.                
  398.                 // 尝试提取常见数据类型
  399.                 const record = {};
  400.                
  401.                 // 提取电子邮件
  402.                 const emailMatch = line.match(/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/);
  403.                 if (emailMatch) {
  404.                     record['邮箱'] = emailMatch[0];
  405.                 }
  406.                
  407.                 // 提取电话号码
  408.                 const phoneMatch = line.match(/(\d{3,4}-?)?\d{7,8}(?=-?\d{3,4})?|-?\d{3,4}-?\d{7,8}/);
  409.                 if (phoneMatch) {
  410.                     record['电话'] = phoneMatch[0];
  411.                 }
  412.                
  413.                 // 提取日期
  414.                 const dateMatch = line.match(/(\d{4}-\d{2}-\d{2}|\d{2}\/\d{2}\/\d{4})/);
  415.                 if (dateMatch) {
  416.                     record['日期'] = dateMatch[0];
  417.                 }
  418.                
  419.                 // 提取URL
  420.                 const urlMatch = line.match(/(https?:\/\/[^\s]+)/);
  421.                 if (urlMatch) {
  422.                     record['网址'] = urlMatch[0];
  423.                 }
  424.                
  425.                 // 提取数字
  426.                 const numberMatches = line.match(/\d+\.?\d*/g);
  427.                 if (numberMatches) {
  428.                     numberMatches.forEach((num, index) => {
  429.                         const key = index === 0 ? '数值' : `数值${index + 1}`;
  430.                         if (num.includes('.')) {
  431.                             record[key] = parseFloat(num);
  432.                         } else {
  433.                             record[key] = parseInt(num, 10);
  434.                         }
  435.                     });
  436.                 }
  437.                
  438.                 // 如果没有提取到任何数据,将整行作为内容
  439.                 if (Object.keys(record).length === 0) {
  440.                     record['内容'] = line;
  441.                 }
  442.                
  443.                 parsedData.push(record);
  444.             });
  445.         }
  446.         
  447.         // 显示数据
  448.         function displayData() {
  449.             // 显示表格视图
  450.             displayTableView();
  451.             
  452.             // 显示卡片视图
  453.             displayCardsView();
  454.             
  455.             // 显示JSON视图
  456.             displayJSONView();
  457.         }
  458.         
  459.         // 显示表格视图
  460.         function displayTableView() {
  461.             if (parsedData.length === 0) {
  462.                 tableContainer.innerHTML = '<div class="no-data">暂无数据</div>';
  463.                 return;
  464.             }
  465.             
  466.             // 获取所有可能的列
  467.             const columns = new Set();
  468.             parsedData.forEach(record => {
  469.                 Object.keys(record).forEach(key => columns.add(key));
  470.             });
  471.             
  472.             // 创建表格
  473.             let tableHTML = '<table><thead><tr>';
  474.             Array.from(columns).forEach(column => {
  475.                 tableHTML += `<th>${column}</th>`;
  476.             });
  477.             tableHTML += '</tr></thead><tbody>';
  478.             
  479.             // 添加数据行
  480.             parsedData.forEach(record => {
  481.                 tableHTML += '<tr>';
  482.                 Array.from(columns).forEach(column => {
  483.                     const value = record[column] !== undefined ? record[column] : '';
  484.                     tableHTML += `<td>${value}</td>`;
  485.                 });
  486.                 tableHTML += '</tr>';
  487.             });
  488.             
  489.             tableHTML += '</tbody></table>';
  490.             tableContainer.innerHTML = tableHTML;
  491.         }
  492.         
  493.         // 显示卡片视图
  494.         function displayCardsView() {
  495.             if (parsedData.length === 0) {
  496.                 cardsContainer.innerHTML = '<div class="no-data">暂无数据</div>';
  497.                 return;
  498.             }
  499.             
  500.             let cardsHTML = '';
  501.             
  502.             parsedData.forEach((record, index) => {
  503.                 cardsHTML += '<div class="data-card">';
  504.                 cardsHTML += `<h3>记录 ${index + 1}</h3>`;
  505.                
  506.                 Object.keys(record).forEach(key => {
  507.                     cardsHTML += `<div class="data-item">`;
  508.                     cardsHTML += `<span class="data-label">${key}:</span>`;
  509.                     cardsHTML += `<span>${record[key]}</span>`;
  510.                     cardsHTML += `</div>`;
  511.                 });
  512.                
  513.                 cardsHTML += '</div>';
  514.             });
  515.             
  516.             cardsContainer.innerHTML = cardsHTML;
  517.         }
  518.         
  519.         // 显示JSON视图
  520.         function displayJSONView() {
  521.             if (parsedData.length === 0) {
  522.                 jsonOutput.value = '';
  523.                 return;
  524.             }
  525.             
  526.             try {
  527.                 const jsonString = JSON.stringify(parsedData, null, 2);
  528.                 jsonOutput.value = jsonString;
  529.             } catch (error) {
  530.                 jsonOutput.value = 'JSON序列化错误: ' + error.message;
  531.             }
  532.         }
  533.         
  534.         // 清除数据
  535.         function clearData() {
  536.             inputData.value = '';
  537.             parsedData = [];
  538.             tableContainer.innerHTML = '<div class="no-data">暂无数据,请先输入并解析数据</div>';
  539.             cardsContainer.innerHTML = '<div class="no-data">暂无数据,请先输入并解析数据</div>';
  540.             jsonOutput.value = '';
  541.             showMessage('数据已清除', 'success');
  542.         }
  543.         
  544.         // 加载示例数据
  545.         function loadSampleData() {
  546.             const sampleData = `姓名: 张三, 年龄: 30, 邮箱: zhangsan@example.com, 电话: 13800138000, 部门: 技术部
  547. 姓名: 李四, 年龄: 25, 邮箱: lisi@example.com, 电话: 13900139000, 部门: 市场部
  548. 姓名: 王五, 年龄: 35, 邮箱: wangwu@example.com, 电话: 13700137000, 部门: 人事部
  549. 姓名: 赵六, 年龄: 28, 邮箱: zhaoliu@example.com, 电话: 13600136000, 部门: 财务部
  550. 姓名: 钱七, 年龄: 32, 邮箱: qianqi@example.com, 电话: 13500135000, 部门: 技术部`;
  551.             
  552.             inputData.value = sampleData;
  553.             showMessage('示例数据已加载', 'success');
  554.         }
  555.         
  556.         // 添加事件监听器
  557.         parseDataBtn.addEventListener('click', parseData);
  558.         clearDataBtn.addEventListener('click', clearData);
  559.         loadSampleBtn.addEventListener('click', loadSampleData);
  560.     </script>
  561. </body>
  562. </html>
复制代码

6. 性能优化和最佳实践

6.1 正则表达式性能优化

正则表达式虽然强大,但如果使用不当可能会导致性能问题。以下是一些优化正则表达式性能的最佳实践:

贪婪匹配(使用*和+量词)会尝试匹配尽可能多的字符,这可能导致大量的回溯操作。在可能的情况下,使用惰性匹配(*?和+?)或更精确的匹配模式。
  1. // 不推荐的贪婪匹配
  2. const html = '<div>内容1</div><div>内容2</div>';
  3. const matches = html.match(/<div>.*<\/div>/g); // 匹配整个字符串
  4. // 推荐的惰性匹配
  5. const matches = html.match(/<div>.*?<\/div>/g); // 分别匹配两个div
复制代码

字符类(如[abc])通常比选择(如(a|b|c))更高效。
  1. // 不推荐的选择
  2. const pattern = /(a|b|c)/;
  3. // 推荐的字符类
  4. const pattern = /[abc]/;
复制代码

捕获组会消耗额外的内存和处理时间。如果不需要引用匹配的组,使用非捕获组(?:...)。
  1. // 不推荐的捕获组
  2. const pattern = /(\d{4})-(\d{2})-(\d{2})/;
  3. // 推荐的非捕获组(如果不需要引用)
  4. const pattern = /(?:\d{4})-(?:\d{2})-(?:\d{2})/;
复制代码

如果可能,使用锚点(如^和$)来限制匹配范围,这样可以减少不必要的匹配尝试。
  1. // 不推荐的无锚点匹配
  2. const pattern = /error/;
  3. // 推荐的有锚点匹配(如果知道错误在行首)
  4. const pattern = /^error/;
复制代码

如果同一个正则表达式会被多次使用,预编译它可以提高性能。
  1. // 不推荐的每次创建新正则表达式
  2. function validateEmail(email) {
  3.     return /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email);
  4. }
  5. // 推荐的预编译正则表达式
  6. const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
  7. function validateEmail(email) {
  8.     return emailRegex.test(email);
  9. }
复制代码

6.2 DOM操作性能优化

DOM操作是前端开发中的常见性能瓶颈。以下是一些优化DOM操作性能的最佳实践:

DOM访问是昂贵的操作,应该尽量减少。缓存DOM查询结果,避免重复查询。
  1. // 不推荐的重复DOM查询
  2. function updateItems() {
  3.     const items = document.querySelectorAll('.item');
  4.     items.forEach(item => {
  5.         item.style.color = 'red';
  6.     });
  7.    
  8.     // 其他操作...
  9.    
  10.     // 再次查询相同的元素
  11.     const items2 = document.querySelectorAll('.item');
  12.     items2.forEach(item => {
  13.         item.style.backgroundColor = 'yellow';
  14.     });
  15. }
  16. // 推荐的缓存DOM查询结果
  17. function updateItems() {
  18.     const items = document.querySelectorAll('.item');
  19.    
  20.     items.forEach(item => {
  21.         item.style.color = 'red';
  22.     });
  23.    
  24.     // 其他操作...
  25.    
  26.     // 使用缓存的元素
  27.     items.forEach(item => {
  28.         item.style.backgroundColor = 'yellow';
  29.     });
  30. }
复制代码

当需要添加多个DOM元素时,使用文档片段(DocumentFragment)可以减少重排和重绘。
  1. // 不推荐的直接添加多个元素
  2. function addItems(items) {
  3.     const container = document.getElementById('container');
  4.     items.forEach(item => {
  5.         const div = document.createElement('div');
  6.         div.textContent = item;
  7.         container.appendChild(div);
  8.     });
  9. }
  10. // 推荐的使用文档片段
  11. function addItems(items) {
  12.     const container = document.getElementById('container');
  13.     const fragment = document.createDocumentFragment();
  14.    
  15.     items.forEach(item => {
  16.         const div = document.createElement('div');
  17.         div.textContent = item;
  18.         fragment.appendChild(div);
  19.     });
  20.    
  21.     container.appendChild(fragment);
  22. }
复制代码

避免频繁修改单个元素的样式,而是通过修改类名来批量更新样式。
  1. // 不推荐的逐个修改样式
  2. function highlightItems() {
  3.     const items = document.querySelectorAll('.item');
  4.     items.forEach(item => {
  5.         item.style.color = 'red';
  6.         item.style.backgroundColor = 'yellow';
  7.         item.style.fontWeight = 'bold';
  8.     });
  9. }
  10. // 推荐的通过类名批量更新样式
  11. function highlightItems() {
  12.     const items = document.querySelectorAll('.item');
  13.     items.forEach(item => {
  14.         item.classList.add('highlight');
  15.     });
  16. }
  17. // CSS中定义.highlight类
  18. // .highlight {
  19. //     color: red;
  20. //     background-color: yellow;
  21. //     font-weight: bold;
  22. // }
复制代码

当需要为多个元素添加相同的事件处理程序时,使用事件委托可以减少内存使用和提高性能。
  1. // 不推荐的为每个元素添加事件监听器
  2. function setupItemHandlers() {
  3.     const items = document.querySelectorAll('.item');
  4.     items.forEach(item => {
  5.         item.addEventListener('click', function() {
  6.             console.log('Item clicked:', this.textContent);
  7.         });
  8.     });
  9. }
  10. // 推荐的事件委托
  11. function setupItemHandlers() {
  12.     const container = document.getElementById('container');
  13.     container.addEventListener('click', function(event) {
  14.         if (event.target.classList.contains('item')) {
  15.             console.log('Item clicked:', event.target.textContent);
  16.         }
  17.     });
  18. }
复制代码

避免在JavaScript中读取布局信息后立即修改布局,这会导致强制同步布局,影响性能。
  1. // 不推荐的强制同步布局
  2. function updateElement() {
  3.     const element = document.getElementById('myElement');
  4.     // 读取布局信息
  5.     const width = element.offsetWidth;
  6.     // 立即修改布局
  7.     element.style.height = width * 2 + 'px';
  8. }
  9. // 推荐的分离读写操作
  10. function updateElement() {
  11.     const element = document.getElementById('myElement');
  12.     // 先读取所有布局信息
  13.     const width = element.offsetWidth;
  14.     const height = element.offsetHeight;
  15.    
  16.     // 然后进行所有布局修改
  17.     element.style.height = width * 2 + 'px';
  18.     element.style.width = height * 2 + 'px';
  19. }
复制代码

6.3 代码组织和可维护性

良好的代码组织和可维护性是长期项目成功的关键。以下是一些最佳实践:

将代码组织成模块,每个模块负责特定的功能。
  1. // regexUtils.js - 正则表达式工具模块
  2. export const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
  3. export const phoneRegex = /^1[3-9]\d{9}$/;
  4. export function validateEmail(email) {
  5.     return emailRegex.test(email);
  6. }
  7. export function validatePhone(phone) {
  8.     return phoneRegex.test(phone);
  9. }
  10. // domUtils.js - DOM操作工具模块
  11. export function createElement(tag, attributes, content) {
  12.     const element = document.createElement(tag);
  13.    
  14.     if (attributes) {
  15.         Object.keys(attributes).forEach(key => {
  16.             element.setAttribute(key, attributes[key]);
  17.         });
  18.     }
  19.    
  20.     if (content) {
  21.         element.textContent = content;
  22.     }
  23.    
  24.     return element;
  25. }
  26. export function addClass(element, className) {
  27.     element.classList.add(className);
  28. }
  29. // main.js - 主模块
  30. import { validateEmail, validatePhone } from './regexUtils.js';
  31. import { createElement, addClass } from './domUtils.js';
  32. function processForm(formData) {
  33.     if (!validateEmail(formData.email)) {
  34.         showError('邮箱格式不正确');
  35.         return false;
  36.     }
  37.    
  38.     if (!validatePhone(formData.phone)) {
  39.         showError('手机号格式不正确');
  40.         return false;
  41.     }
  42.    
  43.     // 处理表单数据...
  44.     return true;
  45. }
复制代码

使用适当的设计模式可以提高代码的可维护性和可扩展性。
  1. // 策略模式 - 用于不同的验证策略
  2. class Validator {
  3.     constructor(strategy) {
  4.         this.strategy = strategy;
  5.     }
  6.    
  7.     validate(value) {
  8.         return this.strategy.validate(value);
  9.     }
  10. }
  11. class EmailValidator {
  12.     validate(email) {
  13.         return /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email);
  14.     }
  15. }
  16. class PhoneValidator {
  17.     validate(phone) {
  18.         return /^1[3-9]\d{9}$/.test(phone);
  19.     }
  20. }
  21. // 使用策略模式
  22. const emailValidator = new Validator(new EmailValidator());
  23. const phoneValidator = new Validator(new PhoneValidator());
  24. console.log(emailValidator.validate('test@example.com')); // true
  25. console.log(phoneValidator.validate('13800138000')); // true
复制代码

编写可测试的代码可以提高代码质量和可维护性。
  1. // 可测试的验证函数
  2. function validateInput(input, pattern) {
  3.     if (!input || !pattern) {
  4.         return { isValid: false, error: '输入和模式不能为空' };
  5.     }
  6.    
  7.     try {
  8.         const regex = new RegExp(pattern);
  9.         const isValid = regex.test(input);
  10.         return { isValid, error: isValid ? '' : '输入格式不正确' };
  11.     } catch (error) {
  12.         return { isValid: false, error: '正则表达式错误: ' + error.message };
  13.     }
  14. }
  15. // 测试用例
  16. function testValidateInput() {
  17.     // 测试邮箱验证
  18.     const emailResult = validateInput('test@example.com', '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$');
  19.     console.assert(emailResult.isValid === true, '邮箱验证测试失败');
  20.    
  21.     // 测试无效邮箱
  22.     const invalidEmailResult = validateInput('invalid-email', '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$');
  23.     console.assert(invalidEmailResult.isValid === false, '无效邮箱验证测试失败');
  24.    
  25.     // 测试空输入
  26.     const emptyResult = validateInput('', '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$');
  27.     console.assert(emptyResult.isValid === false, '空输入验证测试失败');
  28.    
  29.     console.log('所有测试通过');
  30. }
  31. testValidateInput();
复制代码

良好的注释和文档可以提高代码的可读性和可维护性。
  1. /**
  2. * 验证邮箱地址格式
  3. * @param {string} email - 要验证的邮箱地址
  4. * @returns {boolean} - 如果邮箱格式正确返回true,否则返回false
  5. *
  6. * @example
  7. * // 返回 true
  8. * validateEmail('test@example.com');
  9. *
  10. * @example
  11. * // 返回 false
  12. * validateEmail('invalid-email');
  13. */
  14. function validateEmail(email) {
  15.     if (!email || typeof email !== 'string') {
  16.         return false;
  17.     }
  18.    
  19.     // 邮箱正则表达式,支持大多数常见邮箱格式
  20.     const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
  21.     return emailRegex.test(email);
  22. }
复制代码

7. 结论

正则表达式和JavaScript DOM操作是前端开发中的两项核心技术,它们结合使用可以创建高效、动态且用户友好的网页。通过本文的学习,我们了解了:

1. 正则表达式的基础知识和常用模式,以及如何在JavaScript中使用它们进行文本匹配和处理。
2. JavaScript DOM操作的基本方法,包括选择、修改、创建和删除DOM元素,以及事件处理。
3. 如何结合正则表达式和DOM操作实现表单验证、动态搜索和过滤、文本处理和格式化、动态样式应用等功能。
4. 通过实战案例,我们看到了这些技术在实际应用中的强大功能。
5. 性能优化和最佳实践,帮助我们编写更高效、更可维护的代码。

掌握这些技能将大大提升你的前端开发能力,使你能够创建更加动态、交互性更强的网页应用。继续实践和探索,你会发现正则表达式和DOM操作的更多可能性,为你的项目带来更大的价值。

7.1 进一步学习的资源

如果你想进一步深入学习正则表达式和JavaScript DOM操作,以下资源可能会有所帮助:

1. MDN Web文档:正则表达式文档对象模型 (DOM)
2. 正则表达式
3. 文档对象模型 (DOM)
4. 书籍:《JavaScript高级程序设计》(第4版)- Nicholas C. Zakas《JavaScript权威指南》(第7版)- David Flanagan《正则表达式必知必会》- Ben Forta
5. 《JavaScript高级程序设计》(第4版)- Nicholas C. Zakas
6. 《JavaScript权威指南》(第7版)- David Flanagan
7. 《正则表达式必知必会》- Ben Forta
8. 在线工具:RegExr- 正则表达式学习和测试工具Regex101- 正则表达式测试和调试工具JSFiddle- 在线JavaScript代码编辑和测试
9. RegExr- 正则表达式学习和测试工具
10. Regex101- 正则表达式测试和调试工具
11. JSFiddle- 在线JavaScript代码编辑和测试
12. 课程:Coursera上的”JavaScript, jQuery, and JSON”课程Udemy上的”JavaScript: Understanding the Weird Parts”课程Frontend Masters上的”JavaScript: The Hard Parts”课程
13. Coursera上的”JavaScript, jQuery, and JSON”课程
14. Udemy上的”JavaScript: Understanding the Weird Parts”课程
15. Frontend Masters上的”JavaScript: The Hard Parts”课程

MDN Web文档:

• 正则表达式
• 文档对象模型 (DOM)

书籍:

• 《JavaScript高级程序设计》(第4版)- Nicholas C. Zakas
• 《JavaScript权威指南》(第7版)- David Flanagan
• 《正则表达式必知必会》- Ben Forta

在线工具:

• RegExr- 正则表达式学习和测试工具
• Regex101- 正则表达式测试和调试工具
• JSFiddle- 在线JavaScript代码编辑和测试

课程:

• Coursera上的”JavaScript, jQuery, and JSON”课程
• Udemy上的”JavaScript: Understanding the Weird Parts”课程
• Frontend Masters上的”JavaScript: The Hard Parts”课程

通过不断学习和实践,你将能够更加熟练地运用正则表达式和DOM操作,创建出更加出色的前端应用。
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则