• DOM实战-js todo


    1.需求:

    实现一个如下页面:

    • 最上面是输入框,后面是add按钮,输入文本点击add按钮,在下面就会出现一行,下面出现的每行最前面是两个按钮,然后后面是todo(要做的事)
    • 第一个按钮是完成按钮,第二个按钮是删除按钮,点击完成按钮后这一行虽然不会消失,但是这一行会有一条横线在上面表示完成,点击删除按钮后这一行的数据就会消失不见
    • 第三个按钮是修改,点击修改即可修改todo中的内容,修改完成后回车或按界面其他地方即可保存
    • 两个按钮后面的第一个是todo,第二个是发布时间

    2.实现代码:

    HTML:

     1 <!-- author: wyb -->
     2 <!DOCTYPE html>
     3 <html lang="en">
     4 <head>
     5     <meta charset="UTF-8">
     6     <title>js todo</title>
     7     <style>
     8         *{
     9             margin: 0;
    10             padding: 0;
    11         }
    12         .container{
    13              60%;
    14             margin: 0 auto;
    15         }
    16         .button{
    17             margin-right: 5px;
    18         }
    19         .complete{
    20             color: red;
    21             text-decoration: line-through;
    22         }
    23         .pub-time{
    24             margin-left: 15px;
    25         }
    26     </style>
    27 </head>
    28 <body>
    29 
    30 <div class="container">
    31     <!-- todo输入框 -->
    32     <div class="todo-form">
    33         <input type="text" id="input">
    34         <button id="button-add">add</button>
    35     </div>
    36     <!-- todo列表 -->
    37     <div id="todo-list">
    38         <!-- 示例todo -->
    39         <div class="todo-cell">
    40         </div>
    41     </div>
    42 </div>
    43 
    44 <script src="todo.js"></script>
    45 </body>
    46 </html>

    JavaScript:

      1 // 封装输出
      2 var log = function() {
      3     console.log.apply(console, arguments)
      4 };
      5 
      6 // 字符串处理:
      7 var todoTemplate = function (todo) {
      8     // 下面是JavaScript中的字符串替换:
      9     var t = `<div class="todo-cell"><button class="button-complete button">完成</button><button class="button-delete button">删除</button><button class="button-update button">编辑</button><span contenteditable='false' class="todo-label">${todo.task}</span><span class="pub-time">发布时间: ${todo.time}</span>`;
     10     return t;
     11 };
     12 
     13 // 插入新元素
     14 var insertTodo = function (todo) {
     15     // 获得todo-cell的HTML字符串:
     16     var todoItem = todoTemplate(todo);
     17 
     18     var todoList = document.querySelector("#todo-list");
     19     todoList.insertAdjacentHTML('beforeend', todoItem);
     20 };
     21 
     22 // 开关一个元素的某个class
     23 var toggleClass = function(element, className) {
     24     if (element.classList.contains(className)) {
     25         element.classList.remove(className)
     26     } else {
     27         element.classList.add(className)
     28     }
     29 };
     30 
     31 // 得到当前时间
     32 var currentTime = function () {
     33     var d = new Date();
     34     var year = d.getFullYear();
     35     var month = d.getMonth() + 1;
     36     var day = d.getDate();
     37     var hour = d.getHours();
     38     var minute = d.getMinutes();
     39     var second = d.getSeconds();
     40     // 时间格式处理
     41     if(minute <= 9){
     42         minute = "0" +minute
     43     }
     44     if(second <= 9){
     45         second = "0" +second
     46     }
     47 
     48     var timeString = `${year}/${month}/${day} ${hour}:${minute}:${second}`;
     49     log("now time is: ", timeString);
     50     return timeString
     51 };
     52 
     53 // 返回自己在父元素中的下标
     54 var indexOfElement = function(element) {
     55     var parent = element.parentElement;
     56     for (var i = 0; i < parent.children.length; i++) {
     57         var e = parent.children[i];
     58         if (e === element) {
     59             return i
     60         }
     61     }
     62 };
     63 
     64 // 保存 todoList
     65 var saveTodos = function() {
     66     var s = JSON.stringify(todoArray);
     67     localStorage.todoArray = s;
     68 };
     69 
     70 var loadTodos = function() {
     71     var s = localStorage.todoArray;
     72     return JSON.parse(s);
     73 };
     74 
     75 
     76 // 事件处理相关:
     77 // 响应事件函数:
     78 var bindEventAdd = function () {
     79     var buttonAdd = document.getElementById("button-add");
     80     buttonAdd.addEventListener('click', function () {
     81         log("button-add click");
     82 
     83         // 获得todo的值:
     84         var task = document.getElementById("input").value;
     85         // log(task);
     86         // 获得todo对象
     87         var todo = {
     88             'task': task,
     89             'time': currentTime(),
     90         };
     91         // 将数据存入数组中
     92         todoArray = loadTodos();
     93         todoArray.push(todo);
     94         saveTodos();
     95 
     96         // 插入todo-list:
     97         insertTodo(todo)
     98     });
     99 };
    100 
    101 var bindEventEnter = function(){
    102     var todoList = document.querySelector("#todo-list");
    103     todoList.addEventListener('keydown', function (event) {
    104         log('todo keydown: ', event, event.target);
    105         var target = event.target;
    106         if(event.key === 'Enter') {
    107             log('按了回车');
    108             // 失去焦点
    109             target.blur();
    110             // 阻止默认行为的发生, 也就是不插入回车
    111             event.preventDefault();
    112             // 更新todo
    113             var index = indexOfElement(target.parentElement);
    114             log('update index: ',  index);
    115             // 把元素在 todoList 中更新
    116             todoArray = loadTodos();
    117             todoArray[index-1].task = target.innerText;
    118             saveTodos();
    119         }
    120     });
    121 };
    122 
    123 var bindEventButton = function () {
    124     // bindEventButton -> 复制todo所在div中的3个按钮的响应
    125     var todoList = document.querySelector("#todo-list");
    126     todoList.addEventListener('click', function (event) {
    127         log('click: ', event, event.target);
    128         // 获得点击对象和其父元素(todo的div)
    129         var target = event.target;
    130         var todoDiv = target.parentElement;
    131 
    132         // complete和delete和update的具体操作:
    133         if(target.classList.contains('button-complete')) {
    134             // 给 todo的div 开关一个状态 class
    135             toggleClass(todoDiv, 'complete')
    136         } else if (target.classList.contains('button-delete')) {
    137             log('delete');
    138             var index = indexOfElement(todoDiv) - 1;
    139             log(index);
    140             // 删除父节点
    141             todoDiv.remove();
    142             // 把元素从 todoArray 删除:
    143             // delete todoArray[index] -> 不是完全删除,删除的数据变成了undefined依然留着数组中
    144             todoArray = loadTodos();
    145             log("delete: ", todoArray[index]);
    146             todoArray.splice(index, 1);
    147             log(todoArray);
    148             saveTodos();
    149         }
    150         else if (target.classList.contains('button-update')) {
    151             log('update');
    152             var cell = target.parentElement;
    153             var span = cell.children[3];
    154             log("span is: ", span);
    155             span.setAttribute("contenteditable", true);
    156             // span.contentEditable = true  // 同理
    157             span.focus();
    158         }
    159     });
    160 };
    161 
    162 var bindEventBlur = function() {
    163     var todoList = document.querySelector('#todo-list');
    164     todoList.addEventListener('blur', function(event){
    165         log('todo blur: ', event, event.target);
    166         var target = event.target;
    167         if (target.classList.contains('todo-label')) {
    168             log('update and save');
    169             // 让 span 不可编辑
    170             target.setAttribute('contenteditable', 'false');
    171             // 更新todo
    172             var index = indexOfElement(target.parentElement);
    173             log('update index: ',  index);
    174             // 把元素在 todoList 中更新
    175             todoArray = loadTodos();
    176             todoArray[index-1].task = target.innerText;
    177             saveTodos()
    178         }
    179     }, true)
    180 };
    181 
    182 
    183 // 绑定事件:
    184 var bindEvents = function () {
    185     // 添加todo
    186     bindEventAdd();
    187     // 文本框输入todo 按回车保存
    188     bindEventEnter();
    189     // 完成按钮和删除按钮和编辑按钮
    190     bindEventButton();
    191     // 文本框失去焦点后保存todo
    192     bindEventBlur()
    193 };
    194 
    195 
    196 // 初始化todo:
    197 var initTodos = function () {
    198     var todoArray = loadTodos();
    199     for (var i = 0; i < todoArray.length; i++) {
    200         var todo = todoArray[i];
    201         insertTodo(todo);
    202     }
    203 };
    204 
    205 // 存储数据
    206 var todoArray = [];
    207 // 程序主入口
    208 var __main = function (){
    209     // 绑定事件:
    210     bindEvents();
    211 
    212     // 程序加载后, 加载 todoArray 并且添加到页面中
    213     initTodos();
    214 
    215 };
    216 
    217 __main();
    218 
    219 
    220 
    221 // 一些说明:
    222 // 事件委托相关概念
    223 // ===
    224 //
    225 // 问题在于, todo都是运行的时候才添加的元素
    226 // 对于这样的元素, 我们没办法实现绑定事件
    227 // 我们可以把 click 事件绑定在事先存在的父元素上
    228 // 通过父元素响应click事件 调用相应的事件响应函数
    229 // 而事件响应函数会被传入一个参数, 就是事件本身
    230 // 然后在运行的时候通过 event.target 属性(发起事件的元素,例如某个按钮)
    231 // 来检查被点击的对象是否是需要的对象, 这个概念就是事件委托
    232 
    233 // 与存储相关的问题:
    234 // ===
    235 // localStorage 可以用来存储字符串数据, 在浏览器关闭后依然存在
    236 // 存储方法如下:
    237 // localStorage.name = 'wyb';
    238 // 关闭浏览器, 注释上一句代码
    239 // 再次用同一个浏览器打开该项目, 仍然能获取到这个值
    240 // log('关闭浏览器后: ', localStorage.name);
    241 // localStorage删除数据:
    242 // localStorage.removeItem("name");
    243 // 注意:
    244 // 利用 localStorage 就可以 存储todo
    245 // 但是 todo存在于array中
    246 // 而 localStorage 只能存储 string 数据
    247 // 所以没办法直接存储todo数据
    248 //
    249 // 可行的办法如下:
    250 // 存储的时候把 array 转换为字符串   读取的时候把字符串转成 array
    251 // 这个过程通常被称之为 序列化 和 反序列化
    252 // 在 js 中, 序列化使用 JSON 格式
    253 //
    254 // var s = JSON.stringify([1, 2, 3, 4]);
    255 // log('序列化后的字符串', typeof s, s);
    256 // var a = JSON.parse(s);
    257 // log('反序列化后的数组', typeof a, a);
    258 // 输出结果:
    259 // 序列化后的字符串 string [1,2,3,4]
    260 // 反序列化后的数组 object Array(4)
    261 //
    262 // 使用 JSON 序列化后, 就可以把 todo存入浏览器的 localStorage 了
    263 //
    264 // 与时间相关的问题: JavaScript中的时间对象 -> Date对象
    265 // ===
    266 // 常用用法如下:
    267 /*
    268 var d = new Date()
    269 d.getFullYear()
    270 年份, 2016
    271 d.getMonth()
    272 月份, 0-11
    273 d.getDate()
    274 日期, 1-31
    275 d.getHours()
    276 小时, 0-23
    277 d.getMinutes()
    278 分钟, 0-59
    279 d.getSeconds()
    280 秒数, 0-59
    281 d.getMilliseconds()
    282 毫秒, 0-999
    283 d.getDay()
    284 星期几, 0-6
    285 */

    3.实现效果:

    (1)最开始界面

     

    (2)输入信息点击add

    (3)点击完成

    (4)点击删除

     

    (5)点击编辑 

    修改完成后回车后或点击其他页面即可

    (6)刷新或关闭网页再次打开依然是之前保存的todo

  • 相关阅读:
    三、k8s 核心功能
    【RobotFramework】显式等待、隐式等待、强制等待
    如何快速发现缺陷
    冒烟测试知多少
    【Robot Framework】发送GET与POST请求
    Fastdfs.jar手动安装到本地仓库配置
    Lua架构
    SPU与SKU
    docker环境删除与安装配置
    idea-maven导入出现omitted for duplicate且下标标红
  • 原文地址:https://www.cnblogs.com/wyb666/p/9365371.html
Copyright © 2020-2023  润新知