• todo demo


    Todo

    功能实现

    https://rencoo.github.io/appDemo/todo/index.html

    ---1.添加事项

    ---2.置顶事项

    ---3.删除事项

    ---4.用时排序

    ---5.删除所有

      1class Todo{
    2    constructor(id) {
    3        this.container = document.getElementById(id);
    4        this.todoContainer = this.container.querySelector('.todo-container');    
    5        this.delContainer = this.container.querySelector('.delete-container');     
    6
    7        this.todoList = [];                                            // 用于存放todo
    8        this.todoDelList = [];                                         // 用于存放删除的todo
    9
    10        let container = this.container,
    11            addBtn = container.querySelector('.addBtn'),                       
    12            input = container.querySelector('.todo-ctrl input'),   
    13            delBtn = container.querySelector('.delBtn'),                      
    14            sortBtn = container.querySelector('.sortBtn');                     
    15
    16        /* 待办板块 */
    17        // 点击按钮添加
    18        addBtn.addEventListener('click', () => this.createTodo());
    19        // 回车添加
    20        input.addEventListener('keydown', evt => {
    21            if(evt.key == 'Enter') {
    22                this.createTodo();
    23            }
    24        })  
    25        // 点击todo文本,编辑todo  
    26        let todoContainer = this.todoContainer;
    27        todoContainer.addEventListener('click', evt => {
    28            let target = evt.target;
    29            if(target.classList.contains('todo-task')) {
    30                target.setAttribute('contenteditable''true');
    31            }
    32            target.focus(); // 点击后使文本框立即获得焦点
    33        })
    34        // 回车按钮完成编辑,并失焦
    35        todoContainer.addEventListener('keydown', evt => {
    36            let target = evt.target;
    37            if(evt.key == 'Enter') {
    38                if(target.classList.contains('todo-task')) {
    39                    let todoCell = target.parentNode,
    40                        idx = this.indexOfElement(todoCell),
    41                        task = target.value,               // 获取task
    42                        todo = this.todoList[idx];   
    43                    todo.task = task;                      // 修改todo
    44                    this.saveTodos()                       // 保存
    45                    target.blur();                         // 失焦
    46                    evt.preventDefault();                  // 阻止回车默认换行行为
    47                }
    48            }
    49        })
    50        // 点击时间进行置顶
    51        todoContainer.addEventListener('click', evt => {
    52            let target = evt.target;
    53            let todoList = this.todoList;
    54            if(target.classList.contains('todo-time')) {
    55                let todoCell = target.parentNode,
    56                    idx = this.indexOfElement(todoCell),
    57                    todo = todoList[idx];
    58                todoList.splice(idx, 1);                  // 在待办数组中删除todo
    59                todoList.unshift(todo);                   // 在待办数组中置顶todo
    60                this.saveTodos();                         // 保存
    61                todoCell.remove();                        // 在待办页面删除todoCell
    62                todoContainer.prepend(todoCell)           // 在删除页面置顶todoCell
    63            }
    64        })
    65        // 点击复选框移除事件(事件委托)
    66        todoContainer.addEventListener('click', evt => {
    67            let target = evt.target;
    68            if(target.classList.contains('todo-input')) { // 判断目标元素;jQuery 可以直接指定响应事件的元素
    69                let todoCell = target.parentNode,
    70                    idx = this.indexOfElement(todoCell),  // 获取todo的idx
    71                    todo = this.todoList[idx];            // 获取todo数据
    72                this.todoList.splice(idx, 1)              // 从待办数组中删除todo
    73                this.saveTodos();                         // 保存
    74                todoCell.remove();                        // 在待办中移除todoCell
    75
    76                let time = this.getInterval(todo);        // 获取删除和创建的时间差
    77                todo.time = time;                         
    78                this.todoDelList.push(todo);              // 往删除数组中添加todo
    79                this.saveTodos();                         // 保存
    80                this.insertTodo(delContainer, todo);      // 在删除中显示todoCell
    81            }
    82        })
    83
    84        /* 删除板块 */
    85        // 点击复选框移除单条(删除板块)
    86        let delContainer = this.delContainer;
    87        delContainer.addEventListener('click', evt => {
    88            let target = evt.target;
    89            if(target.classList.contains('todo-input')) {
    90                let todoCell = target.parentNode,
    91                    idx = this.indexOfElement(todoCell);
    92                this.todoDelList.splice(idx, 1);
    93                this.saveTodos();
    94                todoCell.remove();
    95            }
    96        })
    97        // 清空删除板块
    98        delBtn.addEventListener('click', evt => {
    99            var r = confirm("确定要删除所有吗");
    100            if (r==true) {
    101                this.todoDelList.length = 0               // 清空todoDelList
    102                delContainer.innerHTML = '';              // 删除板块清空todoCell
    103                this.saveTodos();                         // 保存
    104            }
    105            else{
    106              return;
    107            }
    108        })
    109        // 事项用时排序
    110        sortBtn.addEventListener('click', evt => {
    111            let todoDelList = this.todoDelList;
    112            todoDelList.sort(desc);                       // 对数组进行排序
    113            this.saveTodos();                             // 保存
    114            delContainer.innerHTML = '';
    115            let len = todoDelList.length;
    116            for(let i = 0; i < len; i++) {
    117                let todo = todoDelList[i];
    118                this.insertTodo(delContainer, todo);
    119            }
    120        })
    121        // sort rule,完成事项用时的排序规则
    122        let  desc = function(a, b) { 
    123            let m = this.time_to_minute(a.time), 
    124                n = this.time_to_minute(b.time);
    125            return m > n ? -1 : 1;
    126        }.bind(this);
    127
    128        // 初始化,载入数据和渲染页面
    129        this.initTodos();
    130    }
    131    // 创建todo
    132    createTodo() {
    133        let task = this.getInputValue();              // 获取文本框中的值
    134        if(!task) {                                   // 文本框是否为空
    135            alert("请输入!");                  
    136            return;
    137        }
    138        let currentTime = this.getCurrentTime();      // 获取当前时间
    139        let todo = {                                  // 创建todo对象
    140            'task': task,
    141            'time': currentTime
    142        }
    143        this.todoList.push(todo);                     // 待办数组添加todo
    144        this.saveTodos();                             // 保存数据
    145        this.insertTodo(this.todoContainer, todo);    // 在页面上添加todoCell
    146        let input = this.container.querySelector('.todo-ctrl input');
    147        input.value = '';                              
    148    }
    149    // 获取输入框的值
    150    getInputValue() {
    151        let input = this.container.querySelector('.todo-ctrl input'), 
    152            value = input.value;
    153        return value;
    154    }
    155    // 插入todo; 
    156    insertTodo(box, todo) {                           // 参数:容器;todo;
    157        let t = this.templateTodo(todo);
    158        box.insertAdjacentHTML('beforeEnd', t);
    159    }
    160    // 模板todo
    161    templateTodo(todo) {
    162        let t = `
    163        <div class="todo-cell">
    164            <input class="todo-inputtype="checkbox"/>
    165            <span class="todo-taskcontenteditable ="false">${todo.task}</span>
    166            <span class="todo-time">${todo.time}>>Top</span>
    167        </div>
    168        `
    169        return t;
    170    }
    171    // 获取当前时间
    172    getCurrentTime() {
    173        var d= new Date(),
    174            addZero = this.addZero,
    175            month = addZero(d.getMonth() + 1),
    176            date = addZero(d.getDate()),        // 几号;区别于getDay星期几
    177            hour = addZero(d.getHours()),
    178            minute = addZero(d.getMinutes());
    179        var t = `${month}/${date} ${hour}:${minute}`;
    180        return t;
    181    }
    182    addZero(t) {
    183        t = t < 10 ? '0' + t : t; 
    184        return t;
    185    }
    186    // 获取元素的序号   
    187    indexOfElement(el) {
    188        let parent = el.parentElement,
    189            len = parent.children.length;
    190        for (let i = 0; i < len; i++) {
    191            let e = parent.children[i];
    192            if (e === el) {
    193                return i;
    194            }
    195        }
    196    }
    197    // todo的时长
    198    getInterval(todo) {                                                                  // 时间差是分钟级别的
    199        let createdTime = todo.time,                                                     // 创建时刻
    200            delTime = this.getCurrentTime(),                                             // 删除时刻
    201            interval = this.time_to_minute(delTime) - this.time_to_minute(createdTime),  // 时间差
    202            time = this.minute_to_time(interval);                                        // 将分钟转化为标准格式
    203        return time;
    204    }
    205    // 时间积累量(相对于月初)
    206    time_to_minute(time) {
    207        let t = time.split('/'),  // '08', '17 16:34'
    208            s= t[1].split(' '),   // '17', '16:34'
    209            d = s[1].split(':'),  // '16', '34'
    210            // month = t[0],      // 默认事件都在同一个月内发生
    211            date = s[0],
    212            hour = d[0],
    213            minute = d[1],
    214            m = Number(date * 1440) + Number(hour * 60) + Number(minute);
    215        return m;
    216    }
    217    // 积累量转化为时间
    218    minute_to_time(m) {
    219        let addZero = this.addZero;
    220        let date = addZero(Math.floor(m / 1440)),
    221            hour = addZero(Math.floor(m / 60) % 24),
    222            minute = addZero(m % 60),
    223            time =  `00/${date} ${hour}:${minute}`;
    224        return time;
    225    }
    226    // localStorage 网页存储数据
    227    saveTodos() {
    228        let m = JSON.stringify(this.todoList),
    229            n = JSON.stringify(this.todoDelList);
    230        localStorage.todoList = m;
    231        localStorage.todoDelList = n;
    232    }
    233    // 载入数据
    234    loadTodos() { 
    235        let m = localStorage.todoList,
    236            n = localStorage.todoDelList,
    237            obj ={
    238                todoList: JSON.parse(m),
    239                todoDelList: JSON.parse(n)
    240            };
    241        return obj;
    242    }
    243    // 初始化todo
    244    initTodos() {
    245        let obj = this.loadTodos();
    246        this.todoList = obj.todoList;
    247        let len = this.todoList.length;
    248        for (let i = 0; i < len; i++) {
    249            let todo = this.todoList[i];
    250            this.insertTodo(this.todoContainer, todo);
    251        }
    252
    253        this.todoDelList = obj.todoDelList;
    254        let length = this.todoDelList.length;
    255        for(let j = 0; j < length; j++) {
    256            let todoDel = this.todoDelList[j];
    257            this.insertTodo(this.delContainer, todoDel);     
    258        }
    259    } 
    260}
    261
    262// 实例化对象
    263const todo = new Todo('todoDemo');

    200多行的小demo收获

    由于demo存在两个类似的板块,因此很多方法都需要抽象出来,使得两者都能使用;

    由于有了数据存储这个操作,因此每次进行删除、插入、置顶、排序等操作时,就先必须把数据库中(数组)的数据信息更新并保存(类似于告诉后端你更新了什么数据),再在页面上显示相关改动(相当于展示在用户面前的前端重新局部渲染)

    利用localStorage存储数据(localStorage中只能存储字符串,所以我们要借助于JSON.stringify()和JSON.parse();)

    处理数据:利用对象保存解析localStorage的多条数据信息,而不能使用数组;然后要使用数据的时候,再读取对象的属性(这里是todoList与todoDelList);

    对处理数据有了初步认知,处理好数据是编程中十分重要的内容,利用合理的数据结构存储数据,能方便数据的管理与使用

    localStorage存储数据不安全,每条数据的key-value都被清晰的记录在浏览器的面板上;

    根据数组中元素的特性,可以自定义排序规则,再根据规则利用sort对数组进行排序;

    完成事项用时(ex 00/00 01:08)的排序,可以分别对每个位置进行比较,一旦出现大小结果就直接返回,这样排序开销会比较低;排序规则如下

     1// ex
    2// 先将标准时间的各项数据提取出保存在对象中(处理数据)
    3var times = [
    4    {
    5        date17,
    6        h: 18,
    7        m: 04
    8    },
    9    {
    10        date18,
    11        h: 18,
    12        m: 04
    13    },
    14    {
    15        date19,
    16        h: 18,
    17        m: 04
    18    },
    19    {
    20        date19,
    21        h: 20,
    22        m: 04
    23    },
    24]
    25// 制定比较规则
    26var desc = function(a, b) {
    27    if (a.date !== b.date) {
    28        return a.date > b.date ? -1 : 1;
    29    } else {
    30        if (a.h !== b.h) {
    31            return a.h > b.h ? -1 : 1;
    32        } else {
    33            if (a.m !== b.m) {
    34                return a.m > b.m ? -1 : 1;
    35            }
    36        }
    37    }
    38}
    39// 对时间数组中的对象进行排序
    40times.sort(desc)
    41
    42// 结果如下,符合预期
    43[{ date19, h: 20, m: 4 },{ date19, h: 18, m: 4 },{ date18, h: 18, m: 4 },{ date17, h: 18, m: 4 }]​​
  • 相关阅读:
    JavaWeb
    List的三种遍历(转)
    Java中父类和子类集合互相转换(转)
    Day4
    Ubuntu20.04配置 ES7.17.0集群
    K8S中部署apisix(非ingress)
    使用 Flutter&&Hive&&Bloc 写一个待办小demo
    SQL多行数据分组后合并某个字段
    sql group 拼接字段
    Socket
  • 原文地址:https://www.cnblogs.com/rencoo/p/9496713.html
Copyright © 2020-2023  润新知