todo_list开发笔记

todo_list开发笔记

Preface

​ 在大学的最后的一个寒假(考上研另说)里重新复习一下前端三件套做的练手Demo,在大致过了一遍《Javascript高级程序设计第三版》之后总感觉和之前读的时候感觉差不多,寒假这次不记得是第几次看了,断断续续没看完的状态。寒假这次重新学的高程三大概过了一下日常开发所要使用的东西,对于闭包、作用域链之类的还没看打算开学再搞。在这次的高程三学习中对于DOM的理解简直是全新体验,以前一直是把DOM看成是getElementById之类的操作,没有理解到DOM的核心思想是将HTML结点看做对象调用方法,将结点当做对象来使用(这点我直接震惊我对DOM的是什么勾八理解)。

​ 这次做的todoList Demo完全使用HTML、CSS、Javascript原生DOM完成。虽然是个简单的东西,但是在做的时候也遇到了很多逻辑上的东西以及一些技术问题。大致来说完成了一个小目标吧。话不多说上才艺

Github项目地址https://github.com/JYThomas/toDoList_Demo

一、Demo预览

image-20220209160316852

image-20220209160457005

二、遇到的技术问题及解决方法

这里将从HTML、CSS、Javascript三方面遇到的问题分类讲起

(一)、HTML

这方面遇到的问题比较少,基本上就是页面结构。要注意的是外部文件的引入

1.引入外部CSS文件

1
2
3
4
5
6
7
<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>Morant's toDolist</title>
<link rel="stylesheet" href="./toDo.css">
</head>

2.引入外部JS文件:这里需要特别注意遇到一个问题就是外部JS文件引入的位置应该是位于body标签内部,所有的页面元素后面。刚刚开始放的位置是head标签里面,但是后面在调用JS文件的时候发现函数老是报错,原因文件从上到下编译,JS文件放在head里面的时候 涉及了DOM操作 ,但是这个时候body里面的页面元素还没有渲染完成,所以获取到的变量时undefined,放在body标签内部,所有的页面元素后面就解决了这个问题。

1
2
3
4
5
6
7
<body onload="load()">
..........

<!-- 页面渲染完DOM结点再编译js文件 -->
<script src="./index_toDo.js"></script>

</body>

(二)、CSS

  1. 使用div的时候为其添加 heightwidth 属性才看得到盒子。盒子元素背景是background-color,color的话是div里面的文字元素的颜色。

  2. 类 和 id 的css分别是 ‘.’ 和 ‘#’

    1
    2
    3
    4
    5
    6
    7
    8
    9
    .mainContent {
    width: 700px;
    height: auto;
    margin: 0 auto;
    padding-top: 10px ;
    padding-bottom: 10px ;
    border-radius: 20px;
    background-color: aquamarine;
    }
    1
    2
    3
    4
    5
    6
    7
    #addTodoArea{
    width: 600px;
    height: 200px;
    margin: 0 auto;
    border-radius: 20px;
    background-color: #FFCC99;
    }
  3. 设置某个元素下元素A的样式

    1
    2
    3
    4
    5
    6
    li下className为delBtn的元素
    li .delBtn{
    float: right;
    border-radius: 3px;
    background-color: #FFB6C1;
    }
  1. 文字居中、垂直居中、浮动

    1
    2
    3
    4
    5
    6
    7
    #Heading{
    width: 200px;
    height: 80px;
    margin: 5px auto;
    text-align: center; //文字居中
    line-height: 80px; //垂直居中与height等值
    }
  1. 随页面调整大小

    1
    2
    3
    4
    .mainContent {
    width: 700px;
    height: auto; //高度自动调整
    }
  2. margin 与 padding

    margin是指从自身边框到另一个容器边框之间的距离,就是容器外距离。(外边距)

    padding是指自身边框到自身内部另一个容器边框之间的距离,就是容器内距离。(内边距)

    调整div里面的其他元素位置用padding,调整div外部盒子与盒子位置关系用margin

(三)、Javascript

  1. 全局变量:直接在文档外部定义变量

    1
    2
    3
    4
    5
    6
    var toDoArr = new Array(); //创建全局动态数组
    var btn = document.getElementById("add");
    var tbx = document.getElementById("input");
    var toDo_Ol = document.querySelectorAll("ol")[0]; //获取代办列表
    var finished_Ol = document.querySelectorAll("ol")[1]; //获取已完成列表
    var cleanBtn = document.getElementById("cleanBtn");
  2. ES6局部变量声明:let

    1
    2
    3
    4
    btn.onclick = function(){
    let tbxVal = tbx.value;
    ....
    }
  3. 返回字符串某个字符前的字符串

    1
    2
    3
    4
    5
    // 过滤li的文字,过滤返回特定字符'<'前的文字
    function filter(str){
    let res = str.split('<')[0];
    return res;
    }
  4. DOM动态结点生成appendChild 及 删除removeChild

    思想是将小的结点挂载到大的结点上 大结点.appendChild(小结点);大结点.removeChild(小结点);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // 创建列表结点
    function createDataLi(_textVal){
    let node = document.createElement("li"); //创建li结点
    let finishedBtn = document.createElement("button");
    let deleteBtn = document.createElement("button");

    let textNode_toDo = document.createTextNode(_textVal); //创建text结点
    let textNode_finished = document.createTextNode("finished");
    let textNode_del = document.createTextNode("delete");

    // 添加结点
    finishedBtn.appendChild(textNode_finished);
    deleteBtn.appendChild(textNode_del);

    // 设置样式
    finishedBtn.className = "finishedBtn";
    deleteBtn.className = "delBtn";

    // 添加结点到li
    node.appendChild(textNode_toDo);
    node.appendChild(deleteBtn);
    node.appendChild(finishedBtn);

    // 添加结点到ol
    toDo_Ol.appendChild(node);
    }
  1. localStorage的使用(增、查)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //数据存入localStorage
    function setData(_toDoArr){
    /*
    只添加一组key-value实现localStorage数据存储覆盖问题
    而不是使用多组key-value
    */
    localStorage.setItem("todo",JSON.stringify(_toDoArr));
    }

    //获取localStorage字符串数据并返回
    function getData(){
    return localStorage.getItem("todo");
    }

    ​ localStorage的key与value不是每个一个数据都用一个键值对,而是只用一个键值对,在代码里面使用JSON.stringify()将对象转为字符串、JSON.parse()将字符串转为对象然后操作对象,避免操作字符串。

三、逻辑问题

  1. 数据存储:使用localStorage实现本地存储,页面关闭上次使用仍然存在。将数据获取到之后存放到localStorage存储,然后再从localStorage中获取数据渲染。以localStorage为中介,任何数据存储以及显示都要以localStorage中的数据为准。

  2. 添加待办:先将待办事项获取到然后存放到localStorage,之后删除页面上的DOM结点,再从localStorage中获取数据,生成结点渲染到页面上,解决li结点重复显示的问题

  3. 持续数据:当每次关闭或者操作页面的时候都要先从localStorage中获取数据存放到全局变量对象数组中,防止页面刷新或者关闭之后localStorage中的数据被重置

  4. 结点渲染函数load:在页面每次生成的时候执行load函数加载节点、渲染数据

  5. 函数封装的思想 :最大的体会就是每个函数做好自己的事,代码之间的逻辑通过函数的封装提高了程序的可读性,避免在程序流中出现过多高耦合的代码。

  6. 数据存储:使用localStorage一对键值对,存储的时候存储的是字符串,在操作数据的时候将字符串转换为对象数组对数据进行访问。

  7. 使用事件委托处理列表点击事件减少DOM操作稍微提高程序性能。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!