如何在HTML/CSS/JS实现的虚拟键盘中切换符号与字母布局
实现虚拟键盘的符号布局切换功能
Hey there! Let's fix up your virtual keyboard to switch between letter and symbol layouts exactly how you want. Here's a step-by-step solution with modified code and clear explanations:
Modified JavaScript Code
const Keyboard = { elements: { main: null, keysContainer: null, keys: [] }, eventHandlers: { oninput: null, onclose: null }, properties: { value: "", capsLock: false, currentLayout: "letters" // 新增:跟踪当前布局,默认字母模式 }, init() { // Create main elements this.elements.main = document.createElement("div"); this.elements.keysContainer = document.createElement("div"); // Setup main elements this.elements.main.classList.add("keyboard", "keyboard--hidden"); this.elements.keysContainer.classList.add("keyboard__keys"); // 初始化时生成字母布局按键 this.elements.keysContainer.appendChild(this._createKeys()); this.elements.keys = this.elements.keysContainer.querySelectorAll(".keyboard__key"); // Add to DOM this.elements.main.appendChild(this.elements.keysContainer); document.body.appendChild(this.elements.main); // Automatically use keyboard for elements with .use-keyboard-input document.querySelectorAll(".use-keyboard-input").forEach(element => { element.addEventListener("focus", () => { this.open(element.value, currentValue => { element.value = currentValue; }); }); }); }, _createKeys() { const fragment = document.createDocumentFragment(); // 定义字母和符号两套布局 const layouts = { letters: [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "backspace", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "caps", "a", "s", "d", "f", "g", "h", "j", "k", "l", "enter", "toggle", // 替换done为布局切换键 "z", "x", "c", "v", "b", "n", "m", ",", ".", "?", "space" ], symbols: [ "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "backspace", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "caps", "a", "s", "d", "f", "g", "h", "j", "k", "l", "enter", "toggle", // 替换done为布局切换键 "z", "x", "c", "v", "b", "n", "m", ",", ".", "?", "space" ] }; // 根据当前布局获取对应键数组 const keyLayout = layouts[this.properties.currentLayout]; // Creates HTML for an icon const createIconHTML = (icon_name) => { return `<i class="material-icons">${icon_name}</i>`; }; keyLayout.forEach(key => { const keyElement = document.createElement("button"); const insertLineBreak = ["backspace", "p", "enter", "?"].indexOf(key) !== -1; // Add attributes/classes keyElement.setAttribute("type", "button"); keyElement.classList.add("keyboard__key"); switch (key) { case "backspace": keyElement.classList.add("keyboard__key--wide"); keyElement.innerHTML = createIconHTML("backspace"); keyElement.addEventListener("click", () => { this.properties.value = this.properties.value.substring(0, this.properties.value.length - 1); this._triggerEvent("oninput"); }); break; case "caps": keyElement.classList.add("keyboard__key--wide", "keyboard__key--activatable"); keyElement.innerHTML = createIconHTML("keyboard_capslock"); keyElement.addEventListener("click", () => { this._toggleCapsLock(); keyElement.classList.toggle("keyboard__key--active", this.properties.capsLock); }); break; case "enter": keyElement.classList.add("keyboard__key--wide"); keyElement.innerHTML = createIconHTML("keyboard_return"); keyElement.addEventListener("click", () => { this.properties.value += "\n"; this._triggerEvent("oninput"); }); break; case "space": keyElement.classList.add("keyboard__key--extra-wide"); keyElement.innerHTML = createIconHTML("space_bar"); keyElement.addEventListener("click", () => { this.properties.value += " "; this._triggerEvent("oninput"); }); break; case "toggle": // 布局切换键逻辑 keyElement.classList.add("keyboard__key--wide", "keyboard__key--dark"); // 根据当前布局显示对应图标:字母模式显示符号图标,符号模式显示键盘图标 const toggleIcon = this.properties.currentLayout === "letters" ? "symbols" : "keyboard"; keyElement.innerHTML = createIconHTML(toggleIcon); keyElement.addEventListener("click", () => { this._toggleLayout(); // 调用布局切换方法 }); break; default: keyElement.textContent = key.toLowerCase(); keyElement.addEventListener("click", () => { this.properties.value += this.properties.capsLock ? key.toUpperCase() : key.toLowerCase(); this._triggerEvent("oninput"); // 如果当前是符号布局,点击符号后自动切回字母布局 if (this.properties.currentLayout === "symbols") { this._toggleLayout(); } }); break; } fragment.appendChild(keyElement); if (insertLineBreak) { fragment.appendChild(document.createElement("br")); } }); return fragment; }, _toggleLayout() { // 切换布局类型 this.properties.currentLayout = this.properties.currentLayout === "letters" ? "symbols" : "letters"; // 清空当前按键容器,重新生成对应布局的按键 this.elements.keysContainer.innerHTML = ""; this.elements.keysContainer.appendChild(this._createKeys()); this.elements.keys = this.elements.keysContainer.querySelectorAll(".keyboard__key"); // 保持大写锁定状态(如果之前开启) if (this.properties.capsLock) { this._toggleCapsLock(); this._toggleCapsLock(); } }, _triggerEvent(handlerName) { if (typeof this.eventHandlers[handlerName] == "function") { this.eventHandlers[handlerName](this.properties.value); } }, _toggleCapsLock() { this.properties.capsLock = !this.properties.capsLock; for (const key of this.elements.keys) { if (key.childElementCount === 0) { key.textContent = this.properties.capsLock ? key.textContent.toUpperCase() : key.textContent.toLowerCase(); } } }, open(initialValue, oninput, onclose) { this.properties.value = initialValue || ""; this.eventHandlers.oninput = oninput; this.eventHandlers.onclose = onclose; this.elements.main.classList.remove("keyboard--hidden"); }, close() { this.properties.value = ""; this.eventHandlers.oninput = null; // 修复原代码未定义变量的bug this.eventHandlers.onclose = null; this.elements.main.classList.add("keyboard--hidden"); } }; window.addEventListener("DOMContentLoaded", function() { Keyboard.init(); });
Key Changes Explained
- Layout Tracking: Added a
currentLayoutproperty to keep track of whether we're in letter or symbol mode. - Dual Layout Definitions: Created a
layoutsobject to store both key sets, making it easy to switch between them. - Toggle Key Replacement: Replaced the "done" key with a layout toggle button that shows context-aware icons (switches between "symbols" and "keyboard" icons).
- Auto-switch Back: When a symbol key is pressed, the keyboard automatically switches back to the letter layout after inserting the symbol.
- Layout Refresh: The
_toggleLayoutmethod clears existing keys, regenerates the new layout, and preserves caps lock state if it was active. - Bug Fix: Corrected the
closemethod to properly reset event handlers.
Your CSS and HTML code don't need any adjustments—just swap in this modified JavaScript, and your keyboard will work exactly as you requested!
内容的提问来源于stack exchange,提问作者johnrambot




