最近在开发一个需要处理用户输入的项目时我发现很多开发者对点击输入文本这个看似简单的功能存在不少误解。很多人以为这只是一个基础的HTML表单功能但实际上现代Web开发中的文本输入已经演变成一个涉及用户体验、性能优化和安全防护的复杂技术领域。特别是在移动端开发中传统的文本输入方式面临着诸多挑战虚拟键盘的弹出会遮挡页面内容、不同设备的输入法兼容性问题、长文本输入时的性能瓶颈等。这些问题如果不妥善解决会直接影响用户的使用体验和转化率。本文将深入探讨现代Web开发中文本输入的最佳实践从基础的事件处理到高级的优化技巧帮助开发者构建更流畅、更安全的输入体验。无论你是前端新手还是资深开发者都能从中获得实用的技术方案。1. 文本输入的真实痛点与解决方案在实际项目中文本输入功能远不止一个input标签那么简单。最常见的痛点包括虚拟键盘的布局问题在移动端不同类型的输入应该触发不同的虚拟键盘布局。比如输入电话号码时应该显示数字键盘输入邮箱时应该显示带符号的键盘。!-- 正确的输入类型设置 -- input typetel placeholder请输入电话号码 input typeemail placeholder请输入邮箱地址 input typeurl placeholder请输入网址输入性能优化当处理大量文本输入时如富文本编辑器频繁的DOM操作会导致页面卡顿。我们需要使用防抖debounce和节流throttle技术来优化性能。// 防抖函数实现 function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later () { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout setTimeout(later, wait); }; } // 在输入框中使用 const searchInput document.getElementById(search); searchInput.addEventListener(input, debounce(function(e) { // 处理输入逻辑 console.log(用户输入:, e.target.value); }, 300));跨浏览器兼容性不同浏览器对输入事件的处理存在差异特别是在IME输入法输入时的表现各不相同。2. 现代输入事件处理机制理解输入事件的处理机制是优化文本输入的基础。现代浏览器提供了多种输入相关的事件2.1 关键事件的区别与使用场景事件类型触发时机适用场景input值发生变化时立即触发实时搜索、输入验证change失去焦点且值变化时触发表单提交前的最终验证keydown按键按下时触发快捷键、特殊键处理keyup按键释放时触发组合键检测compositionstartIME输入开始时中文输入法处理compositionendIME输入结束时中文输入法处理// 完整的输入事件处理示例 class TextInputHandler { constructor(inputElement) { this.input inputElement; this.isComposing false; // IME输入状态标志 this.setupEventListeners(); } setupEventListeners() { // IME输入相关事件 this.input.addEventListener(compositionstart, () { this.isComposing true; }); this.input.addEventListener(compositionend, (e) { this.isComposing false; this.handleInput(e); // 输入法输入完成后再处理 }); // 普通输入事件 this.input.addEventListener(input, (e) { if (!this.isComposing) { this.handleInput(e); } }); // 键盘事件 this.input.addEventListener(keydown, (e) { this.handleKeyDown(e); }); } handleInput(e) { console.log(最终输入值:, e.target.value); // 这里可以添加输入验证、实时搜索等逻辑 } handleKeyDown(e) { // 处理特殊按键 if (e.key Enter !e.shiftKey) { e.preventDefault(); this.submitForm(); } } submitForm() { // 表单提交逻辑 console.log(提交表单:, this.input.value); } }2.2 输入法(IME)处理的特殊性对于中文、日文等需要输入法的语言直接监听input事件会导致中间状态被误处理。正确的做法是结合compositionstart和compositionend事件// 专门处理IME输入的工具函数 function createIMEAwareInputHandler(callback) { let isComposing false; return function(e) { if (e.type compositionstart) { isComposing true; return; } if (e.type compositionend) { isComposing false; // 在compositionend后手动触发一次处理 callback(e); return; } // 如果是input事件且不在IME输入过程中 if (e.type input !isComposing) { callback(e); } }; } // 使用示例 const inputHandler createIMEAwareInputHandler((e) { console.log(安全处理输入:, e.target.value); }); const inputElement document.getElementById(text-input); inputElement.addEventListener(input, inputHandler); inputElement.addEventListener(compositionstart, inputHandler); inputElement.addEventListener(compositionend, inputHandler);3. 移动端输入优化策略移动端输入面临着独特的挑战需要针对性的优化方案3.1 虚拟键盘管理// 检测虚拟键盘状态的工具类 class VirtualKeyboardManager { constructor() { this.keyboardHeight 0; this.isKeyboardVisible false; this.init(); } init() { // 通过窗口大小变化检测键盘状态 let originalHeight window.innerHeight; window.addEventListener(resize, () { const currentHeight window.innerHeight; const heightDifference originalHeight - currentHeight; if (heightDifference 100) { // 键盘弹出 this.isKeyboardVisible true; this.keyboardHeight heightDifference; this.onKeyboardShow(heightDifference); } else { // 键盘收起 this.isKeyboardVisible false; this.onKeyboardHide(); } originalHeight currentHeight; }); } onKeyboardShow(height) { // 调整布局避免内容被键盘遮挡 const activeElement document.activeElement; if (activeElement (activeElement.tagName INPUT || activeElement.tagName TEXTAREA)) { this.scrollToElement(activeElement, height); } } onKeyboardHide() { // 恢复布局 window.scrollTo(0, 0); } scrollToElement(element, keyboardHeight) { const elementRect element.getBoundingClientRect(); const absoluteElementTop elementRect.top window.pageYOffset; const middle absoluteElementTop - (window.innerHeight - keyboardHeight) / 2; window.scrollTo(0, middle); } } // 使用示例 const keyboardManager new VirtualKeyboardManager();3.2 输入类型优化!-- 针对移动端优化的输入表单 -- form classmobile-optimized-form div classinput-group label forusername用户名/label input typetext idusername autocompleteusername enterkeyhintnext /div div classinput-group label foremail邮箱/label input typeemail idemail autocompleteemail enterkeyhintnext /div div classinput-group label forphone电话/label input typetel idphone autocompletetel enterkeyhintdone /div /form style .mobile-optimized-form { max-width: 100%; padding: 20px; } .input-group { margin-bottom: 15px; } .input-group label { display: block; margin-bottom: 5px; font-weight: bold; } .input-group input { width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 8px; font-size: 16px; /* 防止iOS缩放 */ box-sizing: border-box; } /* 针对不同输入类型的样式优化 */ input[typetel] { letter-spacing: 2px; } input[typeemail] { text-transform: lowercase; } /style4. 高级输入功能实现4.1 富文本输入处理// 简单的富文本编辑器实现 class RichTextEditor { constructor(containerId) { this.container document.getElementById(containerId); this.setupEditor(); } setupEditor() { // 创建编辑区域 this.editor document.createElement(div); this.editor.contentEditable true; this.editor.className rich-text-editor; // 添加工具栏 this.toolbar this.createToolbar(); this.container.appendChild(this.toolbar); this.container.appendChild(this.editor); this.setupEventListeners(); } createToolbar() { const toolbar document.createElement(div); toolbar.className editor-toolbar; const buttons [ { command: bold, text: B, title: 加粗 }, { command: italic, text: I, title: 斜体 }, { command: insertUnorderedList, text: •, title: 无序列表 } ]; buttons.forEach(btn { const button document.createElement(button); button.innerHTML btn.text; button.title btn.title; button.addEventListener(click, () { document.execCommand(btn.command, false, null); this.editor.focus(); }); toolbar.appendChild(button); }); return toolbar; } setupEventListeners() { // 输入事件处理 this.editor.addEventListener(input, this.debounce(() { this.onContentChange(); }, 500)); // 粘贴事件处理 this.editor.addEventListener(paste, (e) { e.preventDefault(); const text e.clipboardData.getData(text/plain); document.execCommand(insertText, false, text); }); } onContentChange() { // 内容变化处理逻辑 console.log(编辑器内容:, this.editor.innerHTML); } debounce(func, wait) { let timeout; return function executedFunction(...args) { const later () { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout setTimeout(later, wait); }; } getContent() { return this.editor.innerHTML; } setContent(html) { this.editor.innerHTML html; } } // 使用示例 const editor new RichTextEditor(editor-container);4.2 实时搜索与自动完成// 智能搜索输入组件 class SmartSearchInput { constructor(inputId, resultsContainerId) { this.input document.getElementById(inputId); this.resultsContainer document.getElementById(resultsContainerId); this.setupSearch(); } setupSearch() { // 输入事件处理 this.input.addEventListener(input, this.debounce(async (e) { const query e.target.value.trim(); if (query.length 2) { this.hideResults(); return; } const results await this.search(query); this.displayResults(results); }, 300)); // 键盘导航 this.input.addEventListener(keydown, (e) { this.handleKeyboardNavigation(e); }); } async search(query) { try { // 模拟API调用 const response await fetch(/api/search?q${encodeURIComponent(query)}); return await response.json(); } catch (error) { console.error(搜索失败:, error); return []; } } displayResults(results) { this.resultsContainer.innerHTML ; if (results.length 0) { this.resultsContainer.innerHTML div classno-results未找到相关结果/div; this.showResults(); return; } results.forEach((result, index) { const item document.createElement(div); item.className result-item; item.textContent result.title; item.dataset.index index; item.addEventListener(click, () { this.selectResult(result); }); this.resultsContainer.appendChild(item); }); this.showResults(); } selectResult(result) { this.input.value result.title; this.hideResults(); // 处理选择结果 this.onResultSelect(result); } onResultSelect(result) { console.log(选中结果:, result); } handleKeyboardNavigation(e) { const items this.resultsContainer.querySelectorAll(.result-item); if (items.length 0) return; let currentIndex -1; // 查找当前选中项 items.forEach((item, index) { if (item.classList.contains(selected)) { currentIndex index; } }); if (e.key ArrowDown) { e.preventDefault(); currentIndex (currentIndex 1) % items.length; } else if (e.key ArrowUp) { e.preventDefault(); currentIndex currentIndex 0 ? currentIndex - 1 : items.length - 1; } else if (e.key Enter currentIndex ! -1) { e.preventDefault(); items[currentIndex].click(); return; } // 更新选中状态 items.forEach(item item.classList.remove(selected)); if (currentIndex ! -1) { items[currentIndex].classList.add(selected); } } showResults() { this.resultsContainer.style.display block; } hideResults() { this.resultsContainer.style.display none; } debounce(func, wait) { let timeout; return function executedFunction(...args) { const later () { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout setTimeout(later, wait); }; } }5. 性能优化与内存管理5.1 大数据量输入处理// 虚拟滚动输入列表 class VirtualScrollInput { constructor(containerId, itemCount, itemHeight) { this.container document.getElementById(containerId); this.itemCount itemCount; this.itemHeight itemHeight; this.visibleItemCount Math.ceil(this.container.clientHeight / itemHeight); this.scrollTop 0; this.setupVirtualScroll(); } setupVirtualScroll() { // 设置容器高度 this.container.style.height ${this.itemCount * this.itemHeight}px; this.container.style.overflow auto; this.container.style.position relative; // 创建可视区域 this.viewport document.createElement(div); this.viewport.style.position absolute; this.viewport.style.top 0; this.viewport.style.left 0; this.viewport.style.width 100%; this.container.appendChild(this.viewport); // 滚动事件监听 this.container.addEventListener(scroll, () { this.handleScroll(); }); this.renderItems(); } handleScroll() { this.scrollTop this.container.scrollTop; this.renderItems(); } renderItems() { const startIndex Math.floor(this.scrollTop / this.itemHeight); const endIndex Math.min(startIndex this.visibleItemCount 5, this.itemCount); // 更新可视区域位置 this.viewport.style.top ${startIndex * this.itemHeight}px; this.viewport.style.height ${(endIndex - startIndex) * this.itemHeight}px; // 清空当前显示的项目 this.viewport.innerHTML ; // 渲染可视项目 for (let i startIndex; i endIndex; i) { const item this.createItem(i); this.viewport.appendChild(item); } } createItem(index) { const item document.createElement(div); item.style.height ${this.itemHeight}px; item.style.lineHeight ${this.itemHeight}px; item.style.borderBottom 1px solid #eee; item.textContent 项目 ${index 1}; return item; } }5.2 输入记忆与恢复// 输入状态管理类 class InputStateManager { constructor() { this.states new Map(); this.setupAutoSave(); } // 保存输入状态 saveState(inputId, value) { const state { value: value, timestamp: Date.now(), cursorPosition: this.getCursorPosition(inputId) }; this.states.set(inputId, state); localStorage.setItem(input_state_${inputId}, JSON.stringify(state)); } // 恢复输入状态 restoreState(inputId) { const saved localStorage.getItem(input_state_${inputId}); if (saved) { const state JSON.parse(saved); const input document.getElementById(inputId); if (input) { input.value state.value; this.setCursorPosition(input, state.cursorPosition); return true; } } return false; } // 获取光标位置 getCursorPosition(inputId) { const input document.getElementById(inputId); return input ? input.selectionStart : 0; } // 设置光标位置 setCursorPosition(input, position) { if (input position ! undefined) { input.focus(); input.setSelectionRange(position, position); } } // 设置自动保存 setupAutoSave() { // 监听页面卸载事件 window.addEventListener(beforeunload, () { this.saveAllStates(); }); // 监听visibilitychange事件标签页切换 document.addEventListener(visibilitychange, () { if (document.hidden) { this.saveAllStates(); } }); } // 保存所有输入状态 saveAllStates() { document.querySelectorAll(input, textarea).forEach(input { if (input.id) { this.saveState(input.id, input.value); } }); } // 清除过期的状态超过24小时 cleanupExpiredStates() { const now Date.now(); const twentyFourHours 24 * 60 * 60 * 1000; for (let [inputId, state] of this.states) { if (now - state.timestamp twentyFourHours) { this.states.delete(inputId); localStorage.removeItem(input_state_${inputId}); } } } } // 使用示例 const stateManager new InputStateManager(); // 页面加载时恢复状态 document.addEventListener(DOMContentLoaded, () { stateManager.restoreState(username); stateManager.restoreState(content); });6. 安全防护与输入验证6.1 XSS防护与输入过滤// 安全的输入验证工具类 class InputSecurity { // HTML标签过滤 static sanitizeHTML(input) { const temp document.createElement(div); temp.textContent input; return temp.innerHTML; } // 防SQL注入过滤 static sanitizeSQL(input) { return input.replace(/[\\;]/g, ); } // 邮箱格式验证 static validateEmail(email) { const emailRegex /^[^\s][^\s]\.[^\s]$/; return emailRegex.test(email); } // 手机号格式验证 static validatePhone(phone) { const phoneRegex /^1[3-9]\d{9}$/; return phoneRegex.test(phone); } // 密码强度验证 static validatePassword(password) { const requirements { minLength: password.length 8, hasUpperCase: /[A-Z]/.test(password), hasLowerCase: /[a-z]/.test(password), hasNumbers: /\d/.test(password), hasSpecialChar: /[!#$%^*(),.?:{}|]/.test(password) }; return { isValid: Object.values(requirements).every(Boolean), requirements: requirements }; } } // 使用示例 const userInput scriptalert(xss)/scriptHello; const safeInput InputSecurity.sanitizeHTML(userInput); console.log(safeInput); // 输出: lt;scriptgt;alert(xss)lt;/scriptgt;Hello // 实时输入验证 function setupRealTimeValidation() { const emailInput document.getElementById(email); const passwordInput document.getElementById(password); emailInput.addEventListener(blur, () { if (!InputSecurity.validateEmail(emailInput.value)) { this.showError(emailInput, 请输入有效的邮箱地址); } }); passwordInput.addEventListener(input, () { const result InputSecurity.validatePassword(passwordInput.value); this.updatePasswordStrength(result); }); }6.2 敏感词过滤// 敏感词过滤系统 class SensitiveWordFilter { constructor() { this.keywords new Set(); this.loadKeywords(); } async loadKeywords() { try { const response await fetch(/api/sensitive-words); const words await response.json(); words.forEach(word this.keywords.add(word.toLowerCase())); } catch (error) { console.warn(无法加载敏感词库使用默认词库); this.loadDefaultKeywords(); } } loadDefaultKeywords() { const defaultWords [敏感词1, 敏感词2, 敏感词3]; defaultWords.forEach(word this.keywords.add(word.toLowerCase())); } // 检查文本是否包含敏感词 containsSensitiveWords(text) { const lowerText text.toLowerCase(); for (let keyword of this.keywords) { if (lowerText.includes(keyword)) { return true; } } return false; } // 替换敏感词 filterText(text, replacement ***) { let filteredText text; this.keywords.forEach(keyword { const regex new RegExp(keyword, gi); filteredText filteredText.replace(regex, replacement); }); return filteredText; } // 实时过滤输入 setupRealTimeFilter(inputElement) { inputElement.addEventListener(input, (e) { const originalValue e.target.value; const filteredValue this.filterText(originalValue); if (originalValue ! filteredValue) { const cursorPosition e.target.selectionStart; e.target.value filteredValue; e.target.setSelectionRange(cursorPosition, cursorPosition); this.showWarning(检测到敏感词已自动过滤); } }); } showWarning(message) { // 显示警告信息 const warning document.createElement(div); warning.className sensitive-warning; warning.textContent message; warning.style.cssText position: fixed; top: 20px; right: 20px; background: #ffeb3b; padding: 10px; border-radius: 4px; z-index: 1000; ; document.body.appendChild(warning); setTimeout(() warning.remove(), 3000); } }7. 无障碍访问支持7.1 屏幕阅读器兼容性!-- 支持无障碍访问的输入组件 -- div classaccessible-input-group label foraccessible-input idinput-label 请输入您的姓名 span classrequired aria-hiddentrue*/span span classsr-only必填字段/span /label input typetext idaccessible-input aria-labelledbyinput-label aria-requiredtrue aria-describedbyinput-hint placeholder例如张三 div idinput-hint classhint-text aria-livepolite 请输入真实姓名长度在2-10个字符之间 /div /div style .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; } .accessible-input-group { margin-bottom: 20px; } .hint-text { font-size: 0.9em; color: #666; margin-top: 5px; } .required { color: #e74c3c; } input:focus { outline: 2px solid #007bff; outline-offset: 2px; } /style7.2 键盘导航支持// 增强键盘导航功能 class KeyboardNavigation { constructor() { this.focusableElements []; this.currentIndex -1; this.init(); } init() { // 获取所有可聚焦元素 this.focusableElements Array.from(document.querySelectorAll( a, button, input, textarea, select, [tabindex]:not([tabindex-1]) )).filter(el !el.disabled el.offsetParent ! null); // 添加键盘事件监听 document.addEventListener(keydown, (e) this.handleKeyDown(e)); // 添加焦点样式 this.setupFocusStyles(); } handleKeyDown(e) { if (e.key Tab) { e.preventDefault(); if (e.shiftKey) { this.previous(); } else { this.next(); } } } next() { this.currentIndex (this.currentIndex 1) % this.focusableElements.length; this.focusCurrent(); } previous() { this.currentIndex this.currentIndex 0 ? this.currentIndex - 1 : this.focusableElements.length - 1; this.focusCurrent(); } focusCurrent() { this.focusableElements[this.currentIndex].focus(); } setupFocusStyles() { const style document.createElement(style); style.textContent .keyboard-focus { outline: 2px solid #007bff !important; outline-offset: 2px !important; } ; document.head.appendChild(style); // 添加焦点样式 this.focusableElements.forEach(el { el.addEventListener(focus, () { el.classList.add(keyboard-focus); }); el.addEventListener(blur, () { el.classList.remove(keyboard-focus); }); }); } }8. 测试与调试技巧8.1 输入测试工具// 输入测试模拟工具 class InputTestingUtils { // 模拟用户输入 static simulateInput(element, text, delay 100) { return new Promise((resolve) { let currentIndex 0; function typeNextCharacter() { if (currentIndex text.length) { const char text[currentIndex]; element.value char; // 触发input事件 const event new Event(input, { bubbles: true, cancelable: true }); element.dispatchEvent(event); currentIndex; setTimeout(typeNextCharacter, delay); } else { resolve(); } } element.focus(); typeNextCharacter(); }); } // 模拟键盘事件 static simulateKeyEvent(element, key, options {}) { const event new KeyboardEvent(keydown, { key: key, code: options.code || Key${key.toUpperCase()}, keyCode: options.keyCode, which: options.keyCode, bubbles: true, cancelable: true, shiftKey: options.shiftKey || false, ctrlKey: options.ctrlKey || false, altKey: options.altKey || false, metaKey: options.metaKey || false }); element.dispatchEvent(event); } // 生成测试数据 static generateTestData(type, count 10) { const generators { email: () test${Math.random().toString(36).substr(2, 8)}example.com, phone: () 1${Math.floor(3000000000 Math.random() * 1000000000)}, name: () { const names [张三, 李四, 王五, 赵六, 钱七]; return names[Math.floor(Math.random() * names.length)]; }, text: () { const texts [这是一段测试文本, Hello World, 测试数据生成]; return texts[Math.floor(Math.random() * texts.length)]; } }; const results []; for (let i 0; i count; i) { results.push(generators[type]()); } return results; } } // 使用示例 async function runInputTests() { const input document.getElementById(test-input); // 测试正常输入 await InputTestingUtils.simulateInput(input, Hello World); // 测试特殊按键 InputTestingUtils.simulateKeyEvent(input, Enter); // 测试中文输入 await InputTestingUtils.simulateInput(input, 中文测试); }8.2 性能监控// 输入性能监控 class InputPerformanceMonitor { constructor() { this.metrics { inputDelay: [], processingTime: [], memoryUsage: [] }; this.startMonitoring(); } startMonitoring() { // 监听输入延迟 this.monitorInputDelay(); // 监听处理时间 this.monitorProcessingTime(); // 监控内存使用 this.monitorMemoryUsage(); } monitorInputDelay() { let lastInputTime 0; document.addEventListener(input, (e) { const now performance.now(); if (lastInputTime 0) { const delay now - lastInputTime; this.metrics.inputDelay.push(delay); if (delay 100) { // 超过100ms的延迟需要关注 console.warn(输入延迟过高:, delay, ms); } } lastInputTime now; }); } monitorProcessingTime() { const originalAddEventListener EventTarget.prototype.addEventListener; EventTarget.prototype.addEventListener function(type, listener, options) { if (type input) { const wrappedListener function(...args) { const startTime performance.now(); listener.apply(this, args); const endTime performance.now(); const processingTime endTime - startTime; this.metrics.processingTime.push(processingTime); if (processingTime 50) { // 处理时间超过50ms需要优化 console.warn(输入处理时间过长:, processingTime, ms); } }; return originalAddEventListener.call(this, type, wrappedListener, options); } return originalAddEventListener.call(this, type, listener, options); }; } monitorMemoryUsage() { if (performance.memory) { setInterval(() { const memory performance.memory; this.metrics.memoryUsage.push({ used: memory.usedJSHeapSize, total: memory.totalJSHeapSize, limit: memory.jsHeapSizeLimit }); // 内存使用超过80%需要警告 if (memory.usedJSHeapSize / memory.totalJSHeapSize 0.8) { console.warn(内存使用率过高当前使用率:, ((memory.usedJSHeapSize / memory.totalJSHeapSize) * 100).toFixed(2) %); } }, 5000); } } getReport() { return { averageInputDelay: this.calculateAverage(this.metrics.inputDelay), averageProcessingTime: this.calculateAverage(this.metrics.processingTime), maxMemoryUsage: Math.max(...this.metrics.memoryUsage.map(m m.used)), totalInputEvents: this.metrics.inputDelay.length }; } calculateAverage(values) { if (values.length 0) return 0; return values.reduce((sum, val) sum val, 0) / values.length; } }9. 实际项目集成示例9.1 完整的注册表单实现!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title用户注册/title style .registration-form { max-width: 400px; margin: 0 auto; padding: 20px; } .form-group { margin-bottom: 20px; } label { display: block; margin-bottom: 5px; font-weight: bold; } input { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; box-sizing: border-box; } .error { color: #e74c3c; font-size: 0.9em; margin-top: 5px; } .success { color: #27ae60; } button { width: 100%; padding: 12px; background: #007bff; color: white; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; } button:disabled { background: #ccc; cursor: not-allowed; } .password-strength { height: 4px; background: #eee; margin-top: 5px; border-radius: 2px; overflow: hidden; } .strength-weak { background: #e74c3c; width: 33%; } .strength-medium { background: #f39c12; width: 66%; } .strength-strong { background: #27ae60; width: 100%; } /style /head body form classregistration-form idregistrationForm div classform-group label forusername用户名/label