
在web开发中,我们经常需要实现列表项的编辑功能,即点击“编辑”按钮后,将对应行的数据填充到表单输入框中,以便用户修改。一个常见的误区是在事件监听器中获取输入框的当前值,并将这些值作为参数传递给处理函数。例如:
// 假设 expName, expDate, expAmount, expType 都是DOM输入元素
expBtn.addEventListener("click", () => {
const expN = expName.value; // 获取的是值
const expD = expDate.value;
const expA = expAmount.value;
const expT = expType.value;
// ... 创建表格行并添加数据 ...
const editBtn = document.getElementsByClassName("edit-btn");
editFun(editBtn, expN, expD, expA, expT); // 将值传递给函数
});
function editFun(editBtn, expN, expD, expA, expT) {
Array.from(editBtn).forEach((e) => {
e.addEventListener("click", (e) => {
const siblings = e.currentTarget.parentElement.childNodes;
// 尝试修改参数,但实际上是修改了函数内部的局部变量
expT = siblings[1].innerText;
expN = siblings[2].innerText;
expD = siblings[3].innerText;
expA = siblings[4].innerText;
// 此时,原始的输入框元素并未被修改
});
});
}上述代码的问题在于,当我们将expN, expD, expA, expT这些变量(它们存储的是输入框的当前value字符串)传递给editFun时,JavaScript采用的是“按值传递”机制。这意味着在editFun内部,expN等参数成为了新的局部变量,它们只是原始字符串值的一个副本。因此,在editFun中对这些局部变量进行重新赋值(expT = siblings[1].innerText;)并不会影响到函数外部的原始DOM输入框元素的value属性。要修改输入框的内容,我们需要直接操作其DOM元素的引用。
正确的做法是,当需要修改DOM元素的属性(如输入框的value)时,我们应该将DOM元素的引用(而不是它的值)传递给函数。这样,在函数内部就可以通过这个引用来访问并修改元素的属性。
首先,在expBtn的点击事件监听器中,我们不再获取输入框的value,而是直接将输入框的DOM元素引用传递给editFun。
// 获取DOM元素引用
const expAmount = document.getElementById("exp-amount");
const expName = document.getElementById("exp-name");
const expDate = document.getElementById("exp-date");
const expBtn = document.getElementById("exp-btn");
const expType = document.getElementById("exp-type");
const table = document.getElementById("table");
const tableChild = document.getElementById("table").childNodes; // 注意:此行可能需要优化以获取实际的行数
expBtn.addEventListener("click", () => {
// 直接传递DOM元素的引用
const expN_ref = expName;
const expD_ref = expDate;
const expA_ref = expAmount;
const expT_ref = expType;
// 在创建表格行时,仍使用元素的当前值
if (expT_ref.value === "choose-type") {
alert("Please choose the expense type !");
return;
}
const tr = document.createElement("tr");
// ... (创建表格行和td元素,这里使用 .value 填充td) ...
const td2Text = document.createTextNode(expT_ref.value); // 使用 .value
// ...
const td3Text = document.createTextNode(expN_ref.value); // 使用 .value
// ...
const td4Text = document.createTextNode(expD_ref.value); // 使用 .value
// ...
const td5Text = document.createTextNode(expA_ref.value + " Rs"); // 使用 .value
// ...
table.appendChild(tr);
const editBtn = document.getElementsByClassName("edit-btn");
// 将DOM元素引用传递给editFun
editFun(editBtn, expN_ref, expD_ref, expA_ref, expT_ref);
const delBtn = document.getElementsByClassName("del-btn");
btnFun(delBtn);
});接下来,在editFun内部,我们可以直接通过接收到的DOM元素引用来设置其value属性。
立即学习“Java免费学习笔记(深入)”;
// Function for Delete Button (保持不变)
function btnFun(delBtn) {
Array.from(delBtn).forEach((e) => {
e.addEventListener("click", (e) => {
const a = e.currentTarget;
a.parentElement.remove();
});
});
}
// Function for Edit Button - 接收DOM元素引用作为参数
function editFun(editBtnCollection, expN_input, expD_input, expA_input, expT_select) {
Array.from(editBtnCollection).forEach((e) => {
e.addEventListener("click", (e) => {
const siblings = e.currentTarget.parentElement.childNodes;
// 通过DOM元素引用设置其value属性
expT_select.value = siblings[1].innerText;
expN_input.value = siblings[2].innerText;
expD_input.value = siblings[3].innerText;
// 注意:金额数据可能包含单位,需要进行处理
expA_input.value = siblings[4].innerText.replace(" Rs", "");
console.log(`编辑表单已更新:金额为 ${expA_input.value}`);
});
});
}以下是整合了上述修改后的完整JavaScript代码:
// 获取所有必要的DOM元素引用
const expAmount = document.getElementById("exp-amount");
const expName = document.getElementById("exp-name");
const expDate = document.getElementById("exp-date");
const expBtn = document.getElementById("exp-btn");
const expType = document.getElementById("exp-type");
const table = document.getElementById("table");
// 注意:tableChild 获取的是所有子节点,包括文本节点。
// 如果需要获取实际的行数,可能需要更精确的选择器,例如 table.querySelectorAll('tbody > tr').length
const tableChild = document.getElementById("table").childNodes;
// 添加费用按钮的事件监听器
expBtn.addEventListener("click", () => {
// 直接传递DOM元素的引用,而不是它们的值
const expN_ref = expName;
const expD_ref = expDate;
const expA_ref = expAmount;
const expT_ref = expType;
// 验证费用类型是否已选择
if (expT_ref.value === "choose-type") {
alert("请选择费用类型!");
return;
}
// 创建新的表格行
const tr = document.createElement("tr");
// 1. 序号
const td1 = document.createElement("td");
// 这里 tableChild.length - 1 作为序号可能不准确,取决于表格结构
td1.appendChild(document.createTextNode(table.children.length)); // 更准确的序号
tr.appendChild(td1);
// 2. 费用类型
const td2 = document.createElement("td");
td2.appendChild(document.createTextNode(expT_ref.value)); // 使用引用获取当前值
td2.classList.add("expT-data");
tr.appendChild(td2);
// 3. 费用名称
const td3 = document.createElement("td");
td3.appendChild(document.createTextNode(expN_ref.value)); // 使用引用获取当前值
td3.classList.add("expN-data");
tr.appendChild(td3);
// 4. 费用日期
const td4 = document.createElement("td");
td4.appendChild(document.createTextNode(expD_ref.value)); // 使用引用获取当前值
td4.classList.add("expD-data");
tr.appendChild(td4);
// 5. 费用金额
const td5 = document.createElement("td");
td5.appendChild(document.createTextNode(expA_ref.value + " Rs")); // 使用引用获取当前值
td5.classList.add("expA-data");
tr.appendChild(td5);
// 6. 删除按钮
const td6 = document.createElement("td");
td6.appendChild(document.createTextNode("删除"));
td6.classList.add("del-btn");
tr.appendChild(td6);
// 7. 编辑按钮
const td7 = document.createElement("td");
td7.appendChild(document.createTextNode("编辑"));
td7.classList.add("edit-btn");
tr.appendChild(td7);
// 将新行添加到表格中
table.appendChild(tr);
// 获取所有编辑按钮并绑定事件,传递DOM元素引用
const editButtons = document.getElementsByClassName("edit-btn");
editFun(editButtons, expN_ref, expD_ref, expA_ref, expT_ref);
// 获取所有删除按钮并绑定事件
const delButtons = document.getElementsByClassName("del-btn");
btnFun(delButtons);
// 清空表单(可选)
expName.value = '';
expDate.value = '';
expAmount.value = '';
expType.value = 'choose-type';
});
// 删除按钮的功能函数
function btnFun(delBtnCollection) {
// 遍历所有删除按钮,为每个按钮添加点击事件
Array.from(delBtnCollection).forEach((button) => {
button.addEventListener("click", (event) => {
// 移除按钮所在的表格行
event.currentTarget.parentElement.remove();
});
});
}
// 编辑按钮的功能函数
function editFun(editBtnCollection, expN_input, expD_input, expA_input, expT_select) {
// 遍历所有编辑按钮,为每个按钮添加点击事件
Array.from(editBtnCollection).forEach((button) => {
button.addEventListener("click", (event) => {
// 获取当前点击按钮的父元素(tr)的所有子节点(td)
const siblings = event.currentTarget.parentElement.childNodes;
// 将表格行中的数据填充到对应的表单输入框中
// 注意:这里使用传入的DOM元素引用,并修改其value属性
expT_select.value = siblings[1].innerText;
expN_input.value = siblings[2].innerText;
expD_input.value = siblings[3].innerText;
// 金额需要去除单位“ Rs”
expA_input.value = siblings[4].innerText.replace(" Rs", "");
console.log(`表单已更新为:类型-${expT_select.value}, 名称-${expN_input.value}, 日期-${expD_input.value}, 金额-${expA_input.value}`);
});
});
}// 示例:使用事件委托处理删除和编辑按钮
table.addEventListener('click', (event) => {
if (event.target.classList.contains('del-btn')) {
event.target.parentElement.remove();
} else if (event.target.classList.contains('edit-btn')) {
const siblings = event.target.parentElement.childNodes;
// 假设表单元素在全局作用域可访问或通过其他方式获取
expType.value = siblings[1].innerText;
expName.value = siblings[2].innerText;
expDate.value = siblings[3].innerText;
expAmount.value = siblings[4].innerText.replace(" Rs", "");
}
});
// 此时,expBtn.addEventListener 中的 editFun 和 btnFun 调用可以移除通过理解JavaScript的参数传递机制并正确地操作DOM元素引用,我们可以有效地实现动态修改表单内容的功能,为用户提供流畅的交互体验。
以上就是JavaScript中动态修改表单元素值的正确姿势:避免局部变量陷阱的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号