本案例未使用任何框架,均使用 js 原生以及 DOM 操作实现,代码完整,复制即用。


目录

一、案例效果

二、涉及要点

1. 事件监听

2. DOM 节点操作

(1)常用节点获取方法

(2)常用节点信息获取方法

(3)常用节点属性获取方式

(4)DOM 修改

(5)DOM 添加

(6)DOM 删除

3. DOM 控制 CSS 样式

(1)通过 style 属性控制样式

(2)通过classList控制样式:

三、完整代码+详细注释


一、案例效果

        如下图,备忘录可添加新事件,对事件进行编辑,删除已有事件,对完成的事件进行标注。

二、涉及要点

1. 事件监听

        事件源要与事件绑定后,才能触发对应事件,事件绑定有三种方式:行内事件属性赋值、事件属性赋值、事件监听。

        本案例使用了事件监听的方式进行事件绑定,与其他两种方式的区别在于事件属性多次赋值则只会执行最后一次事件处理程序;而事件监听可以添加多个监听器,执行多个事件处理程序。

事件监听格式为:

addEventListener(type, listener, useCapture)

//type: 事件类型
//listener: 监听器(处理程序)
//useCapture: 默认为false,设置为true时,不会因冒泡触发监听器

//eg:
const btn = document.querySelector('button');
btn.addEventListener('click', function() {
  alert('事件监听')
})

2. DOM 节点操作

(1)常用节点获取方法

名称描述
getElementById()获取带有指定id的节点
getElementsByTagName()获取带有指定标签名的节点集合
querySelector()获取指定选择器或选择器组匹配的第一个节点
querySelectorAll()获取指定选择器或选择器组匹配的所有节点集合

(2)常用节点信息获取方法

名称描述
innerHTML返回元素内包含的所有HTML内容(文本和标签),类型为字符串
parentNode返回指定节点的父节点
children返回指定元素的子元素节点集合
firstElementChild返回指定元素的第一个子元素节点
lastElementChild返回指定元素的最后一个子元素节点

(3)常用节点属性获取方式

名称描述
getAttribute()返回元素一个指定的属性值
直接使用属性名称获取适用于部分属性(如:titlevaluehref

(4)DOM 修改

名称描述
innerHTMLinnerHTML除了获取元素内容,也可通过赋值用于修改元素中内容。如果修改内容中包含html字符串会被解析成html元素
setAttribute(name,value)设置指定元素上的某个属性值。如果属性已经存在,则更新该值;否则,使用指定的名称和值添加一个新的属性
通过属性名更改属性对元素属性重新赋值可更改对应属性值

(5)DOM 添加

名称描述
createElement(tagName)创建一个由标签名称tagName指定的HTML元素
appendChild(node)将一个节点插入到指定父节点的子节点列表的末尾处
insertAdjacentHTML(position, text)

将指定文本解析为HTML字符串,插入到指定位置(IE不友好)

position(内容相对当前元素位置):

  • 'beforebegin':元素自身的前面

  • 'afterbegin':插入元素内部的第一个子节点之前

  • 'beforeend':插入元素内部的最后一个子节点之后

  • 'afterend':元素自身的后面

(6)DOM 删除

名称描述
removeChild(child)删除选定的子节点,需要指定其父元素
remove()删除选定节点(IE不友好)

3. DOM 控制 CSS 样式

(1)通过 style 属性控制样式

box.style.color = "#fff"; //将元素中文字设置为白色 
box.style.marginLeft = "100px"; //将元素左外边距设置为100px 

(2)通过classList控制样式:

名称描述
add(class1, class2, …)添加一个或多个类名
remove(class1, class2, …)移除一个或多个类名
replace(oldClass, newClass)替换类名
contains(class)判定类名是否存在,返回布尔值

toggle(class, true|false)

如果类名存在,则移除它,否则添加它,第二个参数代表无论类名是否存在,强制添加(true)或删除(false

三、完整代码+详细注释

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>我的备忘录</title>
  <style>
    button {
      cursor: pointer;
    }

    input {
      outline: none;
      background-color: antiquewhite;
      border: none;
      border-radius: 3px;
      width: 250px;
      height: 30px;
      margin: 15px;
    }

    input::-webkit-input-placeholder {
      color: #999;
    }

    /* 解决li前面的点删除后还占空间的问题 */
    ul {
      padding: 0;
      margin: 0;
    }

    ul>li {
      list-style: none;
    }

    .border {
      width: 500px;
      background-color: #999;
      border-radius: 20px;
      margin: auto;
      padding-bottom: 20px;
    }

    .border .title {
      font-size: 24px;
      color: aliceblue;
      line-height: 50px;
      text-align: center;
    }

    .form {
      width: 80%;
      margin: 15px auto;
    }

    .form #add {
      width: 100px;
      height: 30px;
      border-radius: 5px;
      border: 0;
      font-weight: 600;
      font-size: 16px;
      color: #999;
      letter-spacing: 6px;
    }

    /* 每一条li,代表每一条事件 */
    .item {
      display: flex;
      justify-content: space-between;
      line-height: 30px;
      font-size: 14px;
      color: rgb(75, 73, 73);
      padding: 5px 0;
      border-bottom: 1px solid white;
    }

    .item .info {
      margin-left: 10px;
    }

    .list .item .edit,
    .fin,
    .del {
      width: 50px;
      height: 30px;
      border: 0;
      border-radius: 5px;
      color: white;
    }

    .edit {
      background-color: #337ab7;
    }

    .fin {
      background-color: #20c248;
    }

    .del {
      background-color: #d9534f;
    }

    .btn {
      display: inline-block;
      width: 180px;
      margin-right: 0;
    }

    /* 点击完成按钮后所添加的新类名finished */
    .finished {
      color: rgb(112, 110, 110);
      background-color: rgb(197, 190, 190);
      border-radius: 3px
    }

    .finished>.info {
      /* 为文字添加删除线 */
      text-decoration: line-through;
    }
  </style>
</head>

<body>
  <!-- 备忘录外层边框 -->
  <div class="border">
    <!-- 标题 -->
    <div class="title">我的备忘录</div>
    <hr>
    <!-- 输入框和按钮 -->
    <div class="form">
      <input type="text" name="text" placeholder="请填写您的事件">
      <button id="add">添加</button>
    </div>

    <!-- 备忘录事件列表 -->
    <div
      style="width: 94%;margin: auto;border-radius: 3px;box-shadow: 2px 2px rgb(119, 115, 115);background-color: rgb(214, 219, 219);">
      <ul class="list">
        <li class="item">
          <!-- 事件区域 -->
          <span class="info">事件1</span>
          <!-- 按钮区域 -->
          <div class="btn">
            <button class="edit">编辑</button>
            <button class="fin">完成</button>
            <button class="del">删除</button>
          </div>
        </li>
        <li class="item">
          <!-- 事件区域 -->
          <span class="info">事件2</span>
          <!-- 按钮区域 -->
          <div class="btn">
            <button class="edit">编辑</button>
            <button class="fin">完成</button>
            <button class="del">删除</button>
          </div>
        </li>
      </ul>
    </div>
  </div>
</body>

<script>
  var input = document.querySelector('.form input'); //获取事件输入框
  var addBtn = document.querySelector('#add'); //获取添加按钮
  var list = document.querySelector('.list'); //获取事件列表ul

  //点击添加按钮
  addBtn.addEventListener('click', function () { //使用监听器addEventListener
    //使用DOM添加insertAdjacentHTML,第一个参数:添加的位置;第二个参数:添加的内容
    //每次添加的li均添加到ul内的第一个li之前(afterbegin)
    list.insertAdjacentHTML('afterbegin', `
    <li class="item">
          <!-- 事件区域 -->
          <span class="info">${input.value}</span>
          <!-- 按钮区域 -->
          <div class="btn">
            <button class="edit">编辑</button>
            <button class="fin">完成</button>
            <button class="del">删除</button>
          </div>
        </li>
    `);

    //由于之前设置点击添加按钮后新元素item会被添加到插入元素内部的第一个子节点之前
    //所以我们应该对list的第一个子元素节点进行操作,否则新增事件无法被删除、修改和完成
    //删除
    list.firstElementChild.querySelector('.del').addEventListener('click', function () {
      var item = this.parentNode.parentNode
      item.remove()
    })
    //完成
    list.firstElementChild.querySelector('.fin').addEventListener('click', function () {
      var item = this.parentNode.parentNode
      item.classList.add('finished')
    })
    //修改
    list.firstElementChild.querySelector('.edit').addEventListener('click', function () {
      var item = this.parentNode.parentNode
      item.querySelector('.info').innerText = prompt('请修改你的事件:')
    })
  })

  var delBtns = document.querySelectorAll('.del'); //获取删除按钮
  var finBtns = document.querySelectorAll('.fin'); //获取完成按钮
  var editBtns = document.querySelectorAll('.edit'); //获取编辑按钮

  //遍历,有几个删除按钮则相当于有几个事件(li)
  for (var idx = 0; idx < delBtns.length; idx++) {
    //点击删除按钮
    delBtns[idx].addEventListener('click', function () {
      var item = this.parentNode.parentNode //删除按钮父级的父级,即类名为item的li(该按钮所在的行),一个li即一个事件行
      item.remove(); //点击删除按钮后删除该条li
    })

    //点击完成按钮
    finBtns[idx].addEventListener('click', function () {
      var item = this.parentNode.parentNode; //获取该条事件行
      //classList属性可以返回一个元素类属性集合
      item.classList.add('finished'); //点击完成按钮后为该行添加新类名finished,以实现新样式
    })

    //点击编辑按钮
    editBtns[idx].addEventListener('click', function () {
      var item = this.parentNode.parentNode; //获取该条事件行
      item.querySelector('.info').innerText = prompt('请修改你的事件:'); //点击编辑后将内容插入类名为info的span并弹出系统提示框
    })
  }
</script>

</html>

更多推荐

前端案例:我的备忘录(支持事件的增加、删除和修改,代码完整)