组件化的可编辑数据表格

你还不会写可编辑表格的代码吗?一篇学会如何实现可编辑表格。

要求:

1.可以对页面中数据进行修改、保存、删除;

2.输入数据不符合要求时要有提示,并强制改正后方可确认输入;

3.可以增加新的数据行;

4.注意页面样式。

一、设计思路

1、HTML设计思路

1、表格被定义为一个table元素,包含两个部分:thead、tbody。thead包含表头行(编号、姓名、邮箱、电话号码、操作),tbody包含表格数据行,用于显示已存在数据。

2、使用form元素实现手动输入数据添加。点击添加后新增的数据会添加到table表格最后。

实现效果如下: 

2、CSS设计思路

CSS样式定义表格的样式,包括边框、单元格内边距、文本对齐等。 还需定义可操作和不可操作按钮的颜色设定。

3、JavaScript设计思路

1、点击操作项中保存、修改、删除按钮事件触发的函数实现;

2、保存、修改、删除函数的具体实现;

3、手动添加新的数据行的函数实现;

4、判断输入是否合法;

5、绑定键盘事件监听(enter和esc的监听);

6、绑定按钮事件(包括保存、修改、删除、新增按钮)。

二、实现方法

1、使用正则表达式来判断输入是否合法

//邮箱和电话号码匹配验证
      //邮箱正则表达式:\S+匹配一个或多个非空格字符 xxx@xx.xxx
      const emailRegex = /^\S+@\S+\.\S+$/;
      //电话号码正则表达式:1开头 [3-9]之间任意数字 \d匹配一个数字0-9 {9}匹配\d表达式9次
      const phoneRegex = /^1[3-9]\d{9}$/;

 2、保存函数操作

// 定义函数,点击保存,编辑状态下的保存操作
    function saveRow(row) {
      const tds = row.querySelectorAll('td');
      //textContent属性属性返回指定节点的文本内容
      const num = tds[0].textContent;
      const name = tds[1].textContent;
      const email = tds[2].textContent;
      const phone = tds[3].textContent;

      //邮箱和电话号码匹配验证
      //邮箱正则表达式:\S+匹配一个或多个非空格字符 xxx@xx.xxx
      const emailRegex = /^\S+@\S+\.\S+$/;
      //电话号码正则表达式:1开头 [3-9]之间任意数字 \d匹配一个数字0-9 {9}匹配\d表达式9次
      const phoneRegex = /^1[3-9]\d{9}$/;
      //验证
      if (!emailRegex.test(email) || !phoneRegex.test(phone)) {
        alert('邮箱或电话号码不合法');
        return;
      }

      //移除html表格单元格的可编辑属性的方法(将可编辑状态设置为不可编辑)
      //该方法可以在不重新加载页面的情况下实时更新表格单元格的编辑属性,点击保存后不可在直接编辑
      tds[0].removeAttribute('contenteditable');
      tds[1].removeAttribute('contenteditable');
      tds[2].removeAttribute('contenteditable');
      tds[3].removeAttribute('contenteditable');

      //默认编辑按钮可用,保存按钮不可用
      row.querySelector('.edit').disabled = false;
      row.querySelector('.save').disabled = true;
    }

3、删除函数操作

 // 定义函数,编辑状态下点击删除执行删除操作
    function deleteRow(row) {
      if (confirm('确认要删除该行吗?')) {
        row.remove();
      }
    }

4、修改函数操作

function editRow(row) {
      const tds = row.querySelectorAll('td');//获取到当前行
      //设置属性为可编辑状态
      tds[0].setAttribute('contenteditable', true);
      tds[1].setAttribute('contenteditable', true);
      tds[2].setAttribute('contenteditable', true);
      tds[3].setAttribute('contenteditable', true);

      //设置修改按钮不可用,保存按钮可用
      row.querySelector('.edit').disabled = true;
      row.querySelector('.save').disabled = false;
    }

5、点击保存、删除、修改按钮触发的操作

点击这几个按钮就会触发对应的操作,找到该行再调用对应的函数操作。

//定义函数,点击保存,触发保存操作
    function handleSaveClick(event) {
      //event.target表示被点击的元素 closest()接收一个css选择器做参数
      const row = event.target.closest('tr');//找到离当前元素最近的tr元素
      saveRow(row);  //保存该行信息,调用第一个函数(保存函数)
    }

    //定义函数,点击删除,触发删除操作
    function handleDeleteClick(event) {
      const row = event.target.closest('tr');
      deleteRow(row);  //删除该行,调用第二个函数(删除函数)
    }

    //定义函数,点击修改,触发修改操作
    function handleEditClick(event) {
      const row = event.target.closest('tr');
      editRow(row);  //编辑该行,调用第三个函数(修改函数)
    }

6、手动添加的行的操作

事件触发后将输入的内容添加到列表中。

 //定义函数,用于处理添加表单提交事件的函数,向表格中添加新的一行数据
    function handleAddFormSubmit(event) {
      event.preventDefault();//用于阻止默认的表单提交行为,避免页面刷新重新加载
      //使用了document.getElementById()方法获取四个输入框的值
      const num = document.getElementById('add-编号').value;
      const name = document.getElementById('add-姓名').value;
      const email = document.getElementById('add-邮箱').value;
      const phone = document.getElementById('add-电话号码').value;

      // 邮箱和电话号码匹配验证,同上述保存函数
      const emailRegex = /^\S+@\S+\.\S+$/;
      const phoneRegex = /^1[3-9]\d{9}$/;
      if (!emailRegex.test(email) || !phoneRegex.test(phone)) {
        alert('邮箱或电话号码不合法');
        return;
      }

      //使用了document.createElement()方法,创建一个新的表格行元素tr
      const newRow = document.createElement('tr');
      //innerHTML属性来设置这一行的HTML内容(四个单元格内容,三个按钮)
      newRow.innerHTML = `
        <td contenteditable="true">${num}</td>
        <td contenteditable="true">${name}</td>
        <td contenteditable="true">${email}</td>
        <td contenteditable="true">${phone}</td>
        <td>
          <button class="edit button">修改</button>
          <button class="save button" disabled>保存</button>
          <button class="delete button">删除</button>
        </td>
      `;

      //为三个按钮分别添加监听事件,事件分别由上述定义的handleEditClick()、handleSaveClick()和handleDeleteClick()来处理
      newRow.querySelector('.edit').addEventListener('click', handleEditClick);
      newRow.querySelector('.save').addEventListener('click', handleSaveClick);
      newRow.querySelector('.delete').addEventListener('click', handleDeleteClick);
      
      //使用了appendChild()方法添加新行
      table.querySelector('tbody').appendChild(newRow);

      addForm.reset();  // 重置添加栏(表单)
    }

三、代码展示

<html>
<head>
  <title>Editable Table</title>
  <style>
    table {
      border-collapse: collapse;
      width: 100%;
      text-align: center;
    }

    th, td {
      border: 1px solid #ddd;
      padding: 8px;
    }

    th {
      background-color: #f2f2f2;
    }

    form {
      display: flex;
      justify-content: center;
      margin-bottom: 20px;
    }

    form input {
      margin-right: 10px;
    }

    .button {
      background-color: #4CAF50;
      color: white;
      border: none;
      cursor: pointer;
      padding: 10px 16px;
      margin-right: 5px;
    }

    .button:hover {
      opacity: 0.8;
    }

    .button:disabled {
      opacity: 0.5;
      cursor: not-allowed;
    }
  </style>
</head>
<body>
  <!-- 写出表格基本结构 -->
  <table id="table">
    <thead>
      <tr>
        <th>编号</th>
        <th>姓名</th>
        <th>邮箱</th>
        <th>电话号码</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <!--contenteditable=true表示内容可编辑,以下为原始数据-->
        <td contenteditable="true">001</td>
        <td contenteditable="true">张三</td>
        <td contenteditable="true">zhangsan@example.com</td>
        <td contenteditable="true">13811112222</td>
        <td>
          <button class="edit button">修改</button>
          <!-- 未修改时默认保存不可用 -->
          <button class="save button" disabled>保存</button>
          <button class="delete button">删除</button>
        </td>
      </tr>
      <tr>
        <td contenteditable="true">002</td>
        <td contenteditable="true">李四</td>
        <td contenteditable="true">lisi@example.com</td>
        <td contenteditable="true">13911113333</td>
        <td>
          <button class="edit button">修改</button>
          <button class="save button" disabled>保存</button>
          <button class="delete button">删除</button>
        </td>
      </tr>
    </tbody>
  </table>
<!--初始状态下,添加数据的一栏-->
  <form id="add-form">
    <!-- placehol占位符,在输入框中默认显示 -->
    <input type="text" id="add-编号" placeholder="编号" required>
    <input type="text" id="add-姓名" placeholder="姓名" required>
    <input type="email" id="add-邮箱" placeholder="邮箱" required>
    <input type="tel" id="add-电话号码" placeholder="电话号码" required>
    <button type="submit" class="button">新增</button>
  </form>

  <script>
    //获取table
    const table = document.getElementById('table');
    //获取添加栏
    const addForm = document.getElementById('add-form');

    // 定义函数,点击保存,编辑状态下的保存操作
    function saveRow(row) {
      const tds = row.querySelectorAll('td');
      //textContent属性属性返回指定节点的文本内容
      const num = tds[0].textContent;
      const name = tds[1].textContent;
      const email = tds[2].textContent;
      const phone = tds[3].textContent;

      //邮箱和电话号码匹配验证
      //邮箱正则表达式:\S+匹配一个或多个非空格字符 xxx@xx.xxx
      const emailRegex = /^\S+@\S+\.\S+$/;
      //电话号码正则表达式:1开头 [3-9]之间任意数字 \d匹配一个数字0-9 {9}匹配\d表达式9次
      const phoneRegex = /^1[3-9]\d{9}$/;
      //验证
      if (!emailRegex.test(email) || !phoneRegex.test(phone)) {
        alert('邮箱或电话号码不合法');
        return;
      }

      //移除html表格单元格的可编辑属性的方法(将可编辑状态设置为不可编辑)
      //该方法可以在不重新加载页面的情况下实时更新表格单元格的编辑属性,点击保存后不可在直接编辑
      tds[0].removeAttribute('contenteditable');
      tds[1].removeAttribute('contenteditable');
      tds[2].removeAttribute('contenteditable');
      tds[3].removeAttribute('contenteditable');

      //默认编辑按钮可用,保存按钮不可用
      row.querySelector('.edit').disabled = false;
      row.querySelector('.save').disabled = true;
    }


    // 定义函数,编辑状态下点击删除执行删除操作
    function deleteRow(row) {
      if (confirm('确认要删除该行吗?')) {
        row.remove();
      }
    }

    // 定义函数,编辑状态下点击修改,变成可编辑的表单
    function editRow(row) {
      const tds = row.querySelectorAll('td');//获取到当前行
      //设置属性为可编辑状态
      tds[0].setAttribute('contenteditable', true);
      tds[1].setAttribute('contenteditable', true);
      tds[2].setAttribute('contenteditable', true);
      tds[3].setAttribute('contenteditable', true);

      //设置修改按钮不可用,保存按钮可用
      row.querySelector('.edit').disabled = true;
      row.querySelector('.save').disabled = false;
    }

    //定义函数,点击保存,触发保存操作
    function handleSaveClick(event) {
      //event.target表示被点击的元素 closest()接收一个css选择器做参数
      const row = event.target.closest('tr');//找到离当前元素最近的tr元素
      saveRow(row);  //保存该行信息,调用第一个函数(保存函数)
    }

    //定义函数,点击删除,触发删除操作
    function handleDeleteClick(event) {
      const row = event.target.closest('tr');
      deleteRow(row);  //删除该行,调用第二个函数(删除函数)
    }

    //定义函数,点击修改,触发修改操作
    function handleEditClick(event) {
      const row = event.target.closest('tr');
      editRow(row);  //编辑该行,调用第三个函数(修改函数)
    }

    //定义函数,用于处理添加表单提交事件的函数,向表格中添加新的一行数据
    function handleAddFormSubmit(event) {
      event.preventDefault();//用于阻止默认的表单提交行为,避免页面刷新重新加载
      //使用了document.getElementById()方法获取四个输入框的值
      const num = document.getElementById('add-编号').value;
      const name = document.getElementById('add-姓名').value;
      const email = document.getElementById('add-邮箱').value;
      const phone = document.getElementById('add-电话号码').value;

      // 邮箱和电话号码匹配验证,同上述保存函数
      const emailRegex = /^\S+@\S+\.\S+$/;
      const phoneRegex = /^1[3-9]\d{9}$/;
      if (!emailRegex.test(email) || !phoneRegex.test(phone)) {
        alert('邮箱或电话号码不合法');
        return;
      }

      //使用了document.createElement()方法,创建一个新的表格行元素tr
      const newRow = document.createElement('tr');
      //innerHTML属性来设置这一行的HTML内容(四个单元格内容,三个按钮)
      newRow.innerHTML = `
        <td contenteditable="true">${num}</td>
        <td contenteditable="true">${name}</td>
        <td contenteditable="true">${email}</td>
        <td contenteditable="true">${phone}</td>
        <td>
          <button class="edit button">修改</button>
          <button class="save button" disabled>保存</button>
          <button class="delete button">删除</button>
        </td>
      `;

      //为三个按钮分别添加监听事件,事件分别由上述定义的handleEditClick()、handleSaveClick()和handleDeleteClick()来处理
      newRow.querySelector('.edit').addEventListener('click', handleEditClick);
      newRow.querySelector('.save').addEventListener('click', handleSaveClick);
      newRow.querySelector('.delete').addEventListener('click', handleDeleteClick);
      
      //使用了appendChild()方法添加新行
      table.querySelector('tbody').appendChild(newRow);

      addForm.reset();  // 重置添加栏(表单)
    }

    //绑定键盘事件监听,enter与esc
    document.addEventListener('keydown', function (event) {
      if (event.keyCode==13) {
        //获取当前正在编辑的元素
        const e1 = document.activeElement; 
        saveRow(row);
        e1.blur();  // 令当前编辑元素失焦,从而保存编辑状态
      }
      if (event.keyCode==27) {
        //获取当前正在编辑的元素
        const e2 = document.activeElement;
        //令当前编辑元素失焦,实现了让当前元素退出编辑状态
        e2.blur(); 
      }
    });

    // 绑定事件
    //用document.querySelectorAll()方法查询了表格中所有需要添加事件监听的修改按钮
    const editBtns = document.querySelectorAll('.edit');
    //使用for循环为每个修改按钮添加监听
    for (const btn of editBtns) {
      btn.addEventListener('click', handleEditClick);
    }

    const saveBtns = document.querySelectorAll('.save');
    for (const btn of saveBtns) {
      btn.addEventListener('click', handleSaveClick);
    }

    const deleteBtns = document.querySelectorAll('.delete');
    for (const btn of deleteBtns) {
      btn.addEventListener('click', handleDeleteClick);
    }

    //为添加栏设置监听
    addForm.addEventListener('submit', handleAddFormSubmit);
  </script>
</body>
</html>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值