jQuary实现最简单的待办事项列表(移动和PC端均可使用)

jQuary实现最简单的待办事项列表(移动和PC端均可使用)


前言:ToDoList是一款无需注册即可使用,数据存储在用户浏览器的H5本地数据库里,是最简单、最安全的代办事项列表应用!

PC端效果:

在这里插入图片描述

1、实现流程

  • 导入移动端所需要的CSS初始化样式
  • 导入flexible.js适配文件、jQuery.js插件
  • 布局方式:采用 flexible.js + rem 适配布局
  • 书写html结构
  • 书写css样式,并设置jQuery需要的属性
  • 书写jQuery代码实现具体功能,主要创建对象并实例化调用

2、实现思路

  • 文档注册键盘事件,当按下的是Enter键就创建li节点添加到正在进行ol中
  • 给正在进行中的li节点中的复选框添加点击事件,点击后克隆节点添加到已经完成中,然后删除正进行中的节点
  • 给已经完成中的li节点中的复选框添加点击事件,点击后克隆节点添加到正在进行中,然后删除已经完成中的节点
  • 给文档中所有li的右边的删除按钮a添加点击事件,点击后判断是哪一个元素,然后删除对应的li
  • 给文档中最底下的clear,即a标签添加点击事件,点击后删除文档中的所有li
  • 在文档创建的时候将其写入本地数据路,并添加对应的唯一标记,来后期识别
  • 当点击复选框后根据唯一标记判断是哪一个li,并将其checked属性值更改为truefalse来辨别是已经完成的还是正在进行中的
  • 当点击li中右边的删除按钮后,将其本地中的数据拿出来转换为json对象删除对应的数据,然后再转换为字符串将本地中的数据替换
  • 当点击清除按钮后,将其本地中的数据拿出来转换为json对象,然后清空所有数据,再将其空数组转换为字符串替换本地数据。
  • 在文档加载的时候将其本地加载进来进行转换,根据标记创建对应的节点,找到对应的css样式即可

3、所遇Bug

  1. 无法动态获取创建的节点

    **解决:**使用jQuery中的on方法注册事件,并且使用事件委托动态获取创建的元素。

  2. 获取到对应的节点无法解决事件委托和冒泡

    **解决:**根据对应的元素自己所拥有的唯一属性来辨别是否是该元素

  3. 无法将数据存入本地

    **解决:**如果本地数据为空,则使用数组套json对象的方式创建数组json对象,并将json数组对象转换为json字符串存入本地;否则只将该次的json对象追加到本地的数组中

  4. 更改本地数据后找不到对应的元素

    **解决:**节点创建时都给一个唯一的ID标记,并将该ID标记存入本地,每次触发的事件的时候根据该ID值判断是否是该元素的父亲,并进行操作

  5. 加载本地数据不知道如何归类

    **解决:**根据每次更改的checked属性来辨别是未完成的还是已经完成的,并调用创建元素节点的函数,通过判断将其添加到对应的地方

4、源码奉上

  1. index.html(结构)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0,
    maximum-scale=1.0,minimum-scale=1.0" ">
    <title>ToDoList</title>
    <!-- 导入jQuery插件 -->
    <script src="./jQuery/jquery-3.5.1.min.js "></script>
    <!-- 导入flexible插件 -->
    <script src="./js/index.js "></script>
    <!-- 移动端布局样式初始化的插件 -->
    <link rel="stylesheet " href="./css/normalize.css ">
    <link rel="stylesheet " href="css/style.css ">
    <script src="./js/main.js "></script>
    <script src="./js/cleateE.js "></script>
    <script src="./js/data.js "></script>
</head>

<body>
    <!-- 页头开始了 -->
    <header>
        <form action=" ">
            <label for="title ">ToDoList</label>
            <input type="text " id="title " class="title " placeholder="添加ToDo " required>
        </form>
    </header>
    <!-- 页头结束了 -->
    <section>
        <h2 class="one ">
            正在进行
            <span>0</span>
        </h2>
        <ol></ol>
        <h2 class="two ">
            已经完成
            <span>0</span>
        </h2>
        <ul></ul>
    </section>
    <!-- 页脚开始了 -->
    <footer>
            Copyright © 2014 todolist.cn 
            <a href="javascript:; ">clear</a>
    </footer>
</body>

</html>
  1. normalize.css(移动端初始化样式插件)

  2. index.js(移动端适配插件)

  3. jquery-3.5.1.min.js(jQuery插件)

  4. style.scc(元素样式文件)

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}


/* 当设备宽度大于750px时 */

@media screen and (min-width:750px) {
    /* html采用75px的字体大小 */
    html {
        font-size: 75px !important;
    }
}

body {
    background: #CDCDCD;
}

header {
    height: .666667rem;
    background: rgba(47, 47, 47, 0.98);
}

header form {
    width: 10rem;
    margin: 0 auto;
    display: flex;
    align-items: center;
}

header label {
    flex: 1;
    width: 1.333333rem;
    height: .666667rem;
    line-height: .666667rem;
    color: #ffffff;
    font-size: .32rem;
    cursor: pointer;
}

header input {
    flex: 1;
    width: 4.826667rem;
    height: .346667rem;
    padding-left: .2rem;
    border: none;
    border-radius: .066667rem;
    box-shadow: 0 1px rgba(255, 255, 255, 0.24), 0 1px 6px rgba(0, 0, 0, 0.45) inset;
    font-size: .16rem;
    margin-right: 10px;
    /* 点击表单后,表单边框消失 */
    outline: none;
}

section,
footer {
    min-width: 320px;
    max-width: 750px;
    width: 10rem;
    margin: 0 auto;
    font-family: Arial, Helvetica;
    background: #CDCDCD;
}

section h2 {
    height: .413333rem;
    margin: .266667rem 0;
    font-size: .333333rem;
}

section span {
    float: right;
    width: .266667rem;
    height: .266667rem;
    line-height: .266667rem;
    text-align: center;
    border-radius: 50%;
    background: #E6E6FA;
    font-size: .186667rem;
    color: #666666;
    margin-right: .133333rem;
}

ul,
ol {
    list-style: none;
}

footer {
    color: #666666;
    font-size: .186667rem;
    text-align: center;
}

footer a {
    text-decoration: none;
    color: #999999;
}

.li {
    height: .426667rem;
    background: #ffffff;
    margin-bottom: .133333rem;
    border-radius: .04rem;
    border-left: .066667rem solid #629A9C;
    box-shadow: 0 .013333rem .026667rem rgba(0, 0, 0, 0.07);
    /* 弹性布局 */
    display: flex;
    /* 侧轴居中 */
    align-items: center;
    /* 两边贴边,再平分剩余空间 */
    justify-content: space-around;
    /* 相对定位 */
    position: relative;
    cursor: pointer;
}

.li input {
    position: absolute;
    width: .293333rem;
    height: .293333rem;
    left: .2rem;
}

.li p {
    display: inline-block;
    width: 85%;
    height: 100%;
    line-height: .426667rem;
    font-size: .186667rem;
}

.li a {
    position: absolute;
    width: .346667rem;
    height: .32rem;
    line-height: .14rem;
    text-align: center;
    right: .106667rem;
    border-radius: 50%;
    border: .08rem double #ffffff;
    background: #cccccc;
    color: #ffffff;
}

.finish {
    opacity: 0.5;
    border-left: .066667rem solid #999999;
}
  1. main.js(js主入口文件)
$(function() {
    // 实例化数据对象
    var data = new Data();
    // 实例化创建元素的对象
    var create = new cleateE();
    // 将数据加载进来
    data.load();
    //存储输入的文本值
    this.text = null;
    // 索引
    this.num = 0;
    // 给文档绑定键盘事件
    $(document).keydown(function(event) {
        if (event.which == 13 && $(".title").val() != "") {
            // 获取输入的值
            this.text = $(".title").val();
            // 将文本框清空
            $(".title").val("");
            // 调用创建li节点的函数,并将索引作为参数传递
            var n = create.creatE("ol", this.text, this.num);
            // 索引递增
            this.num++;
            // 调用写入本地的函数,并将li的索引作为参数传递
            data.storage(n, this.text);
        }
    })

    // 将ol和ul中的a委托给文档对象的点击事件去执行
    $(document).on("click", $("ol li a,ul li a"), function(event) {
        // 如果点击的这个元素有href属性
        if ($(event.target).prop("href") != undefined) {
            // 获取该元素父亲的tag属性
            var index = $(event.target).parent("li").attr("tag");
            // 删除该节点的父亲
            $(event.target).parent("li").remove();
            // 调用删除本地对应数据的函数,并将触发该事件的元素对象的父亲作为参数传递
            data.removeD(index);
        }
    })

    // 【已完成】:使用事件委托,将li中的input委托给ul去执行
    $("ol").on("click", $("input"), function(event) {
        // 如果所点的这个元素有checked属性,并且为true
        if ($(event.target).prop("checked") != undefined && $(event.target).prop("checked")) {
            // 标记
            var a = 1;
            // 调用修改数据的函数,并将事件对象作为参数传递
            data.amendV($(event.target).parent("li"), a);
            // 则克隆这个元素的父亲li,并添加到ul中
            $("ul").append($(event.target).parent("li").clone().addClass("finish"));
            // 删除ol中的li节点
            $(event.target).parent(".li").remove();

        }
    })

    // 【未完成】:使用事件委托,将li中的input委托给ul去执行
    $("ul").on("click", $("input"), function(event) {
        // 如果所点的这个元素有checked属性,并且为false
        if ($(event.target).prop("checked") != undefined && !$(event.target).prop("checked")) {
            // 标记
            var a = 0;
            data.amendV($(event.target).parent("li"), a);
            // 则克隆这个元素的父亲li,并添加到ol中
            $("ol").append($(event.target).parent("li").clone().removeClass("finish"));
            // 删除ul中的li节点
            $(event.target).parent(".li").remove();
        }
    })

    // 页脚的a添加点击事件
    $("footer a").on("click", function() {
        // 删除ul和ol中所有的li
        $("ol li,ul li").remove();
        data.clear();
    })

    // 计时器实时更新li的个数
    setInterval(() => {
        // 并将其文本添加到各自的span中
        $(".one span").text($("ol li").length);
        $(".two span").text($("ul li").length);
    }, 1);
});
  1. cleateE.js(创建节点文件)
function cleateE() {
    // 创建li节点
    this.creatE = function(isol, value, num) {
        // 创建li标签,并指定类名,并设置自定义属性
        var li = $("<li></li>").addClass("li").attr("tag", num);
        // 创建input标签,并添加到li标签中
        li.append($("<input type='checkbox'>"));
        // 创建a标签,并设置文本值,添加到li中
        li.append($("<a></a>").text("-"));
        // 如果为ol,则添加到ol中
        if (isol == "ol") {
            // 创建p标签,并设置文本值,添加到li中
            li.append($("<p></p>").text(value));
            // 将li添加到ol中
            $("ol").append(li);
        } else {
            // 否则就是添加到ul中
            // 创建p标签,并设置文本值,添加到li中
            li.append($("<p></p>").text(value));
            // 否则将li添加到ul中
            $("ul").append(li);
        }
        // 返回创建的这个li的索引
        return num;
    }
}
  1. data.js(存入本地文件)
function Data() {
    // 写入本地数据
    this.storage = function(n, text) {
        // 如果获取本地的数据不为空
        if (window.localStorage.getItem("todo") != null) {
            // 则获取本地数据,将其转换为json对象数组
            var obj = JSON.parse(window.localStorage.getItem("todo"));
            // 创建一个json对象,将其添加到另一个json对象数组中
            obj.push({ "title": text, "done": false, "tag": n });
            // 再将json对象数组转换为字符串写入到本地
            window.localStorage.setItem("todo", JSON.stringify(obj))
        } else {
            //创建jeson对象,并装入数组
            var data = [{ "title": text, "done": false, "tag": n }];
            //将jeson对象转换为字符串写入本地
            window.localStorage.setItem("todo", JSON.stringify(data))
        }
    }

    // 修改本地数据
    this.amendV = function(target, isFinish) {
        // 则获取本地数据,将其转换为json对象数组
        var obj = JSON.parse(window.localStorage.getItem("todo"));
        // 如果是完成
        if (isFinish) {
            // 遍历json的数组,拿到每个json对象
            for (var i = 0; i < obj.length; i++) {
                // 如果点击的这个元素的tag属性 == 存储的json对象的tag,那么它们就是一个
                if (target.attr("tag") == obj[i]["tag"]) {
                    // 更改存储的done属性,说明复选框被选中
                    obj[i]["done"] = true;
                }
            }
        } else {
            // 遍历json的数组,拿到每个json对象
            for (var i = 0; i < obj.length; i++) {
                // 如果点击的这个元素的tag属性 == 存储的json对象的tag,那么它们就是一个
                if (target.attr("tag") == obj[i]["tag"]) {
                    // 更改存储的done属性,说明复选框被选中
                    obj[i]["done"] = false;

                }
            }
        }
        // 再将json对象数组转换为字符串写入到本地
        window.localStorage.setItem("todo", JSON.stringify(obj))
    }

    // 删除本地数据
    this.removeD = function(index) {
        // 获取本地数据,将其转换为json对象数组
        var obj = JSON.parse(window.localStorage.getItem("todo"));
        // 遍历json数组对象
        for (var i = 0; i < obj.length; i++) {
            if (index == obj[i]["tag"]) {
                // 那么就根据数组中的索引删除该元素
                var value = obj.splice(i, 1);
            }
        }
        // 再将json对象数组转换为字符串写入到本地
        window.localStorage.setItem("todo", JSON.stringify(obj))
    }

    // 清空本地数据
    this.clear = function() {
        // 获取本地数据,将其转换为json对象数组
        var obj = JSON.parse(window.localStorage.getItem("todo"));
        // 遍历数组
        for (var i = 0; i < obj.length; i++) {
            obj.splice(i, 1)
            i--;
        }
        // 再将json对象数组转换为字符串写入到本地
        window.localStorage.setItem("todo", JSON.stringify(obj))
    }

    // 加载本地数据
    this.load = function() {
        // 实例化创建元素的对象
        var create = new cleateE();
        // 则获取本地数据,将其转换为json对象数组
        var obj = JSON.parse(window.localStorage.getItem("todo"));
        // 如果获取到
        if (obj != null) {
            // 就遍历对象
            for (var i = 0; i < obj.length; i++) {
                // 拿到文本值
                var value = obj[i]["title"];
                // 获取标记
                var tag = obj[i]["tag"];
                // 如果状态时true,则是已经完成的
                if (obj[i]["done"]) {
                    // 那么就将它添加到ul中
                    create.creatE("ul", value, tag);
                    // 并设置复选框的样式
                    $("li input").addClass("finish").prop("checked", true);
                } else {
                    // 否则就添加到ol中
                    create.creatE("ol", value, tag);
                }
            }
        }
    }
}

移动端效果:

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
以下是使用jQuery实现待办事项的示例代码: ```html <!DOCTYPE html> <html> <head> <title>jQuery Todo List</title> <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script> <style> .completed { text-decoration: line-through; } </style> </head> <body> <h1>Todo List</h1> <input type="text" id="todoInput" placeholder="Add a new task"> <ul id="todoList"> <!-- Existing tasks will be added dynamically here --> </ul> <script> // Load saved data on page load $(document).ready(function() { load(); }); // Add new task when Enter key is pressed $("#todoInput").on("keydown", function(event) { if (event.keyCode === 13) { var task = $(this).val(); addTask(task); $(this).val(""); } }); // Add new task to the list function addTask(task) { var listItem = $("<li>").text(task); var checkbox = $("<input>").attr("type", "checkbox"); checkbox.on("click", function() { $(this).parent().toggleClass("completed"); saveData(); }); listItem.prepend(checkbox); $("#todoList").append(listItem); saveData(); } // Save data to local storage function saveData() { var tasks = []; $("#todoList li").each(function() { var task = { text: $(this).text(), completed: $(this).hasClass("completed") }; tasks.push(task); }); localStorage.setItem("todoData", JSON.stringify(tasks)); } // Load data from local storage function load() { var data = localStorage.getItem("todoData"); if (data) { var tasks = JSON.parse(data); for (var i = 0; i < tasks.length; i++) { var listItem = $("<li>").text(tasks[i].text); if (tasks[i].completed) { listItem.addClass("completed"); listItem.prepend($("<input>").attr("type", "checkbox").prop("checked", true)); } else { listItem.prepend($("<input>").attr("type", "checkbox")); } $("#todoList").append(listItem); } } } </script> </body> </html> ``` 这个示例代码实现了一个简单待办事项列表。用户可以在输入框中输入新的任务,并按Enter键添加到列表中。每个任务都有一个复选框,用户可以勾选完成任务。已完成的任务会有删除线样式。所有的任务数据都会保存在浏览器的本地存储中,以便在页面重新加载时恢复数据。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

御弟謌謌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值