You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

JS重复代码重构为函数求助,联系人管理功能代码优化

优化通讯录编辑/删除功能的DRY原则实践

首先,咱们先梳理下你代码里的核心问题:

  • 重复的循环逻辑(多次遍历contactsBook查找联系人、多次遍历UL子节点找LI)违反了DRY(Don't Repeat Yourself)原则,不仅冗余还容易出错
  • 直接用childNodes会包含空白文本节点,需要额外判断tagName,增加了不必要的复杂度
  • 封装函数时崩溃大概率是因为变量作用域(比如var导致的变量泄漏)或者DOM操作的错误(比如原代码里items.insertBefore(input, ulChild.childNodes);的节点引用错误)

下面是一步步的优化方案:

1. 封装通用工具函数

先把重复用到的逻辑抽成独立函数,复用性更强:

查找联系人

用数组的find方法替代手动for循环,更简洁直观:

// 根据firstName查找通讯录中的联系人
function getContactByFirstName(firstName) {
  return contactsBook.find(contact => contact.firstName === firstName);
}

获取联系人列表项

querySelectorAll直接获取UL下的所有LI元素,不用手动遍历子节点:

// 获取指定UL下的所有联系人信息LI项
function getContactListItems(ulElement) {
  return ulElement.querySelectorAll('li');
}

2. 拆分独立的按钮处理函数

把Edit、Save、Delete的逻辑拆成单独的函数,职责单一,可读性拉满:

处理编辑操作

function handleEditContact(ul, button) {
  const contact = getContactByFirstName(ul.dataset.person);
  if (!contact) return;

  const listItems = getContactListItems(ul);
  listItems.forEach(item => {
    // 创建输入框并填充当前文本
    const input = document.createElement('input');
    input.type = 'text';
    input.value = item.textContent;
    // 替换LI内容为输入框
    item.textContent = '';
    item.appendChild(input);
  });
  // 切换按钮文本为Save
  button.textContent = 'Save';
}

处理保存操作

function handleSaveContact(ul, button) {
  const contact = getContactByFirstName(ul.dataset.person);
  if (!contact) return;

  const listItems = getContactListItems(ul);
  // 假设你的LI顺序对应firstName, lastName, phone等字段,可根据实际调整
  contact.firstName = listItems[0].querySelector('input').value;
  contact.lastName = listItems[1].querySelector('input').value;
  contact.phone = listItems[2].querySelector('input').value;
  
  // 更新LI显示为新的文本
  listItems.forEach((item, index) => {
    const fieldValue = Object.values(contact)[index];
    item.textContent = fieldValue;
  });
  // 切换按钮文本为Edit
  button.textContent = 'Edit';
  
  // 更新localStorage
  localStorage.setItem('addbook', JSON.stringify(contactsBook));
}

处理删除操作

function handleDeleteContact(ul) {
  const contact = getContactByFirstName(ul.dataset.person);
  if (!contact) return;

  // 从DOM中移除联系人UL
  ul.remove();
  // 从通讯录数组中移除对应项
  const contactIndex = contactsBook.indexOf(contact);
  contactsBook.splice(contactIndex, 1);
  // 更新localStorage
  localStorage.setItem('addbook', JSON.stringify(contactsBook));
}

3. 重构点击事件监听

现在主点击事件就变得非常简洁,只负责分发操作:

// Click event for Edit and Delete buttons.
contacts.addEventListener("click", (e) => {
  if (e.target.tagName !== "BUTTON") return;
  
  const button = e.target;
  const ul = button.parentNode;

  switch(button.textContent) {
    case "Edit":
      handleEditContact(ul, button);
      break;
    case "Save":
      handleSaveContact(ul, button);
      break;
    case "Delete":
      handleDeleteContact(ul);
      break;
  }
});

关键优化点说明

  • 消除重复逻辑:所有遍历查找的逻辑都被抽成工具函数,避免了多次写相同的for循环和if判断
  • 简化DOM操作:用querySelectorAll替代childNodes,自动过滤非LI节点,减少冗余判断
  • 职责单一:每个按钮操作都有独立函数,代码逻辑清晰,后期维护或修改某功能时不用动其他部分
  • 修复潜在错误:原代码中items.insertBefore(input, ulChild.childNodes);的节点引用错误被修正为直接将输入框追加到LI中,避免DOM操作报错

内容的提问来源于stack exchange,提问作者Darsh2987

火山引擎 最新活动