【IMWeb训练营作业】todo list 便签

用vue完成一个便签的小程序
基本样式如下:
这里写图片描述

1.添加任务

 -  v-model
 -  v-for
 -  v-on:click.enter
 -  v-show
 -  methods

这里写图片描述
输入框代码,v-model记录输入信息,同时将值赋值到todo里,当回车时,用到v-on:click.enter事件.enter事件修饰符,触发addTodo方法,此方法记录在methods对象里,这时通过addTodo方法将记录的todo值传到列表里,在经过v-for渲染,ok完成

<input 
    type="text"
    v-model="todo"
    v-on:keyup.enter="addTodo"
    placeholder="提示:回车会添加任务" 
>

v-forvm实例中list对象数组渲染到列表里

<li v-for="(item,index) in list">
    <div class="view">
        <span class="icon-check"><label><input type="checkbox"></label></span>
        <span class="text">{{item.title}}</span>
        <span class="f-fr close"></span>
    </div>
    <input 
     type="text" 
     class="edit" 
    />
</li>

js里

var vm = new Vue({
    el:".m-body",
    data:{
        list:[],
        todo:"",//要添加任务
        total:"0"//共有任务数
    },
    methods:{
        addTodo(){
            var obj = {
                title :this.todo
            }
            this.list.push(obj);
            this.todo="";//输入完,清空
            this.total=list.length;
        }
    }
})

注意一些小细节,当输入完,input要清空内容,这是让todo=""
当有任务出现时,
这里写图片描述
这个要去掉,用到了v-show:""其值真假可控制元素是否出现

<span class="msg" v-show="!list.length">未添加任务</span>

2.完成任务,加删除符号,双击编辑
在checkbox上v-model="item.isChecked"用isChecked值记录控制有没有选中,在li通过v-bind:class{completed:item.isChecked}来控制样式改变
这里写图片描述

<li 
    v-for="(item,index) in list" 
    :class={completed:item.isChecked}"
>
    <div class="view">
        <span class="icon-check">
            <label 
                :class="{checked:item.isChecked}"
            >
                <input 
                    type="checkbox" 
                    v-model="item.isChecked"
                >
            </label>
        </span>
        <span class="text">{{item.title}}</span>
        <span class="f-fr close" v-on:click="deleteTodo(index)"></span>
    </div>
    <input //编辑框
     type="text" 
     class="edit" 
    />
</li>

在view元素上,添加双击事件@dblclick="edtorTodo(item)换出编辑框

<input 
 type="text" 
 class="edit"
 v-model="item.title"
 v-focus="edtorTodos===item"
 @blur="edtorTodoed(item)"
 @keyup.13="edtorTodoed(item)"
 @keyup.esc="cancelTodo(item)"
/>

v-focus自定义指令,当edtorTodos===item当前编辑时自动获得焦点,添加失去焦点事件,回车事件.创建一个方法cancelTodo(item)当编辑中按esc键自动返回原来值

    directives:{
        'focus':{
            update(el,binding){ //钩子函数update绑定元素更新时调用
                if(binding.value){//binding.value是指令的绑定值
                    el.focus()
                }
            }
        }
    }
    methods:{
        addTodo(){ //添加任务
            this.list.push({
                title :this.todo,
                isChecked:false
            });
            this.todo="";//输入完,清空
            console.log(this.list[0].title)
            this.total=this.list.length;
        },
        deleteTodo(index){ //删除任务
            this.list.splice(index,1);
            this.total=this.list.length;
        },
        edtorTodo(todo){ //编辑任务
            this.beforeTitle=todo.title;
            this.edtorTodos=todo;
        },
        edtorTodoed(todo){//编辑完成
            this.edtorTodos = "";
        },
        cancelTodo(todo){//当按esc时返回原先编辑数据
            todo.title = this.beforeTitle;
            this.edtorTodos = "";
            this.beforeTitle="";
        }
    }

3.过滤任务
通过hash来过滤,添加visibility记录当前hash

function watchHashChange(){
    var hash = window.location.hash.slice(1);
    vm.visibility = hash;
}
window.addEventListener("hashchange", watchHashChange)

vm实例上增加计算,过滤filteredList,将viewlist替换

    computed:{
        filteredList:function(){
            var filter = {
                all:function(list){
                    return list;
                },
                unfinished:function(list){
                    return list.filter(function(item){
                        return !item.isChecked;
                    })
                },
                finished:function(list){
                    return list.filter(function(item){
                        return item.isChecked;
                    })
                }
            }
            return filter[this.visibility]?filter[this.visibility](list):list
        }
    },

4.本地储存localStorage

//本地存取localStorage中数据
var store = {
    save(key,value){
        localStorage.setItem(key,JSON.stringify(value));
    },
    fetch(key){
        return JSON.parse(localStorage.getItem(key))||[]
    }
}

在vm实例中添加watch用来监控list,当list中值发生变化时,触发对应函数,即改变本地存储

    watch:{ //深度监控
        list:{
            handler:function(){
                store.save("miaov-class",this.list)
            },
            deep:true
        }
    }

最后定义var list = store.fetch('miaov-class');当刷新时就能从本地实时拿值了.

最后附上完整代码
HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="./css.css">
    <script src="./vue/vue.js"></script>
</head>
<body>
    <!-- 标题 -->
    <div class="m-nav">
        <div class="g-main">
            <h2>任务计划列表</h2>
        </div>
    </div>
    <div class="m-body">
        <div class="g-main">
            <!-- 添加任务区 -->
            <div class="u-add">
                <h3>添加任务:</h3>
                <input 
                    type="text"
                    v-model="todo"
                    v-on:keyup.enter="addTodo"
                    placeholder="提示:回车会添加任务" 
                >
                <!-- 按钮区 -->
                <div class="message">
                    <span class="msg f-fl">共有{{noCheckedList}}个任务</span>
                    <a class="btn" href="#all">所有任务</a>
                    <a class="btn" href="#finished">已完成任务</a>
                    <a class="btn" href="#unfinished">未成任务</a>
                </div>
            </div>
            <!-- 任务列表 -->
            <div class="u-list">
                <h3>任务列表:</h3>
                <span class="msg" v-show="!list.length">未添加任务</span>
                <ul>
                    <li v-for="(item,index) in filteredList" :class="{completed:item.isChecked,editing:edtorTodos===item}"><!-- 在li上统一管理class -->
                        <div class="view" @dblclick="edtorTodo(item)">
                            <span class="icon-check"><label :class="{checked:item.isChecked}"><input type="checkbox" v-model="item.isChecked"></label></span>
                            <span class="text">{{item.title}}</span>
                            <span class="f-fr close" v-on:click="deleteTodo(index)"></span>
                        </div>
                        <input 
                         type="text" 
                         class="edit"
                         v-model="item.title"
                         v-focus="edtorTodos===item"
                         @blur="edtorTodoed(item)"
                         @keyup.13="edtorTodoed(item)"
                         @keyup.esc="cancelTodo(item)"
                        />
                    </li>
                </ul>
            </div>
        </div>
    </div>
    <script src="./app1.js"></script>
</body>
</html>

JS

//本地存取localStorage中数据
var store = {
    save(key,value){
        localStorage.setItem(key,JSON.stringify(value));
    },
    fetch(key){
        return JSON.parse(localStorage.getItem(key))||[]
    }
}

var list = store.fetch('miaov-class');

var vm = new Vue({
    el:".m-body",
    data:{
        list:list,
        todo:"",//要添加任务
        edtorTodos:"",//记录正在编辑数据
        beforeTitle:"",//编辑前数据
        visibility:"all"//通过属性值变化对数据筛选
    },
    methods:{
        addTodo(){ //添加任务
            this.list.push({
                title :this.todo,
                isChecked:false
            });
            this.todo="";//输入完,清空
            console.log(this.list[0].title)
            this.total=this.list.length;
        },
        deleteTodo(index){ //删除任务
            this.list.splice(index,1);
            this.total=this.list.length;
        },
        edtorTodo(todo){ //编辑任务
            this.beforeTitle=todo.title;
            this.edtorTodos=todo;
        },
        edtorTodoed(todo){//编辑完成
            this.edtorTodos = "";
        },
        cancelTodo(todo){//当按esc时返回原先编辑数据
            todo.title = this.beforeTitle;
            this.edtorTodos = "";
            this.beforeTitle="";
        }
    },
    directives:{
        'focus':{
            update(el,binding){ //钩子函数update绑定元素更新时调用
                if(binding.value){//binding.value是指令的绑定值
                    el.focus()
                }
            }
        }
    },
    computed:{
        noCheckedList:function(){
            return list.filter(function(item){
                return !item.isChecked
            }).length
        },
        filteredList:function(){
            var filter = {
                all:function(list){
                    return list;
                },
                unfinished:function(list){
                    return list.filter(function(item){
                        return !item.isChecked;
                    })
                },
                finished:function(list){
                    return list.filter(function(item){
                        return item.isChecked;
                    })
                }
            }
            return filter[this.visibility]?filter[this.visibility](list):list
        }
    },
    watch:{
        list:{
            handler:function(){
                store.save("miaov-class",this.list)
            },
            deep:true
        }
    }
})

function watchHashChange(){
    var hash = window.location.hash.slice(1);
    vm.visibility = hash;
}
window.addEventListener("hashchange", watchHashChange)

css

html,body,h2,h3,ul{margin: 0;border: 0;padding: 0;}
        h2,h3{line-height: 2em}
        li{list-style: none;font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;}
        a{text-decoration: none;color: #666;}
        .f-fl{float:left;}
        .f-fr{float: right;}
        .g-main{
            width: 500px;
            margin: 0 auto;
        }
        body{
            background-color: #efe;
        }
        .m-nav{
            background-color: #E8583C;
            color: #fff;
        }
        .u-add input{
            width: 100%;
            margin-bottom: 10px;
        }
        .u-add .message{
            text-align: right;
            margin: 0 10px;
            font:14px '微软雅黑';
            color: #666;
        }
        .u-add .message .btn{
            display: inline-block;
            border: 1px solid #efe; 
            padding: 0 10px;
        }
        .u-add .message .btn:hover{
            border-color: #999;
            background-color: #fff;
            cursor: pointer;
        }
        .u-add .message .msg{
            color: red;
        }

        .u-list .completed{
            text-decoration: line-through;
            color:#aaa;
        }
        .u-list .msg{
            font :14px '微软雅黑';
            color: #666;
            margin-left: 10px;      
        }
        .u-list li{
            background-color: #fff;
            margin-bottom: 1px;
            padding: 10px 0;
            position: relative;
        }
        .u-list li .edit{
            display: none;
        }
        .u-list li.editing .edit{
            display: block;
            padding: 0;
            width: 100%;
            height: 100%;
            box-sizing: border-box;
        }
        .u-list li.editing .view{
            display: none;
        }
        .u-list .icon-check{
            position: relative;
            display: inline-block;
            height: 20px;
            width: 20px;
            margin-left: 10px;
        }
        .u-list .icon-check input{
            height: 20px;
            width: 20px;
            visibility: hidden;
            margin: 0;
            padding:0;
        }
        .u-list .icon-check label{
            position: absolute;
            top:4px;
            display: inline-block;
            height: 18px;
            width: 18px;
            border: 1px solid #666;
            border-radius: 50% 50%;

        }
        .u-list .icon-check label.checked{
            background:url(./icon.png) 2px 2px/90% 90%;
        }
        .u-list li:hover{
            background-color: #efe;
        }
        .u-list li:hover .close{
            display: block;
        }
        .u-list .close{
            display: none;
            position: absolute;
            width: 19px;
            height: 19px;
            top: 12px;
            right: 10px;
            color: #cc9a9a;
        }
        .u-list .close:after{
            content: "X"
        }
        .u-list .close:hover{
            cursor: pointer;
        }
在Node.js中,你可以使用内置的crypto模块来实现HMAC-SHA256算法。下面是一个示例代码: ```javascript const crypto = require('crypto'); const secret = 'Secret_Key'; const message = 'timestampGET/users/self/verify'; const hmac = crypto.createHmac('sha256', secret); hmac.update(message); const sign = hmac.digest('base64'); console.log(sign); ``` 在这个示例中,我们首先引入了crypto模块。然后,我们定义了密钥(secret)和要加密的消息(message)。接下来,我们使用createHmac方法创建了一个HMAC对象,并指定了算法为SHA256,并传入密钥。然后,我们使用update方法将消息传入HMAC对象进行更新。最后,我们使用digest方法以base64编码格式输出加密后的签名。 请注意,这个示例中的密钥和消息只是示意用法,你需要根据实际情况替换为你自己的密钥和消息。 #### 引用[.reference_title] - *1* [Typescript/Nodejs 使用HmacSHA256 & Base64对接口调用签名](https://blog.csdn.net/HumorChen99/article/details/117548951)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] - *2* [Hmac SHA256 加密在原生 Java 及 Node.js 的实现](https://blog.csdn.net/frgod/article/details/122025192)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] - *3* [腾讯IMWeb团队是如何使用 NodeJS 实现 JWT 原理](https://blog.csdn.net/lunahaijiao/article/details/109881868)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值