添加带onkeypress事件的div:动态宽度Input框复用异常问题
Hey Marcus, let's figure out why your dynamically appended input fields are breaking that sweet auto-width functionality you built. I’ve run into this exact issue before, so let’s break it down and fix it step by step.
The Root Cause
When you use append() to add elements with inline onkeypress events, two common issues usually crop up:
- Scope conflicts with inline events: If your width-adjustment function isn’t in the global scope (or gets overwritten somehow), the dynamically added inputs won’t be able to call it.
- Global variable pollution: If your width calculation uses shared global variables (like a single temporary span to measure text width), multiple inputs will overwrite each other’s values, causing wonky width behavior.
Fix 1: Ditch Inline Events for Event Delegation (Recommended)
Event delegation is the cleanest way to handle dynamic elements—it binds a single listener to a parent container, so any new inputs added later will still trigger the function automatically.
Here’s how to refactor your code:
<!-- Parent container for all inputs --> <div id="input-group"> <!-- Your initial working input --> <input type="text" class="auto-width-input"> </div> <button onclick="addNewInput()">Add Input</button>
// Bind the listener to the parent container document.getElementById('input-group').addEventListener('keypress', function(e) { // Only run the logic if the pressed element is one of our inputs if (e.target.classList.contains('auto-width-input')) { adjustInputWidth(e.target, e); } }); // Function to add new inputs dynamically function addNewInput() { const newInput = document.createElement('input'); newInput.type = 'text'; newInput.classList.add('auto-width-input'); document.getElementById('input-group').appendChild(newInput); } // Adjust width logic—isolated per input function adjustInputWidth(input, event) { // Create a temporary span to measure text width (no globals here!) const tempSpan = document.createElement('span'); // Copy the input's font/padding styles to get accurate measurements tempSpan.style.font = getComputedStyle(input).font; tempSpan.style.padding = getComputedStyle(input).padding; tempSpan.style.visibility = 'hidden'; tempSpan.style.position = 'absolute'; // Include the upcoming character to make width adjustments feel instant const upcomingChar = String.fromCharCode(event.keyCode); tempSpan.textContent = input.value + upcomingChar; document.body.appendChild(tempSpan); input.style.width = tempSpan.offsetWidth + 'px'; document.body.removeChild(tempSpan); }
Fix 2: Fix Inline Events (If You Want to Keep Them)
If you prefer sticking with inline onkeypress, make sure:
- Your
adjustWidthfunction is in the global scope (so dynamically added inputs can access it). - You avoid shared global variables by tying temporary elements to individual inputs.
Example adjusted width function:
// Global function accessible to all inputs function adjustWidth(input) { // Use the input's dataset to store its own temp span (no cross-input interference) let tempSpan = input.dataset.tempSpanId ? document.getElementById(input.dataset.tempSpanId) : null; if (!tempSpan) { tempSpan = document.createElement('span'); tempSpan.id = `temp-span-${Date.now()}`; input.dataset.tempSpanId = tempSpan.id; // Match input styles for accuracy tempSpan.style.font = getComputedStyle(input).font; tempSpan.style.padding = getComputedStyle(input).padding; tempSpan.style.visibility = 'hidden'; tempSpan.style.position = 'absolute'; document.body.appendChild(tempSpan); } // Add the upcoming character to the measurement const upcomingChar = event ? String.fromCharCode(event.keyCode) : ''; tempSpan.textContent = input.value + upcomingChar; input.style.width = tempSpan.offsetWidth + 'px'; }
Quick Check: Avoid Duplicate IDs!
If your appended code uses a fixed ID (like <input id="my-input">), you’ll end up with multiple elements sharing the same ID in the DOM. This breaks any selector logic that relies on IDs—switch to using classes instead for dynamic elements.
内容的提问来源于stack exchange,提问作者Marcus

