一、作品介绍
1、作品用到的技术栈
- 开发工具 : Vscode
- 语言:Vue2、html、css、js
2、作品实现功能
- 注册登录页面
- 对待办事项的增删改操作
- 显示当前时间和倒计时等功能
- 本地存储功能
二、作品展示
1. 用户注册和登录功能
-
用户注册
- 用户登录
- 用户登录
2. 用户可实现功能
-
增加、删除、修改待办事项
-
查看倒计时效果
三、作品代码
-
项目基本结构
-
注册代码
<template> <div class="form-div"> <div class="reg-content"> <h1>欢迎注册</h1> <span>已有帐号?</span> <a class="toLogin" @click="toLogin">登 录</a> <br /> </div> <table> <tr> <td class="inputs"> <el-input name="username" type="text" id="username" placeholder="账号" v-model="username" /> <br /> </td> </tr> <tr> <td class="inputs"> <el-input show-password name="password" type="password" id="password" placeholder="密码" v-model="password" /> <br /> </td> </tr> </table> <div class="buttons"> <input value="注 册" type="submit" id="reg_btn" @click="register" /> </div> </div> </template> <script> export default { name: "Register", data() { return { users: JSON.parse(localStorage.getItem("users")) || [], username: "", password: "", }; }, methods: { toLogin() { this.$router.push("login"); }, register() { if (this.username.trim() == "" || this.password.trim() == "") { return alert("请输入完整"); } let users = localStorage.users; if (users) { users = JSON.parse(users); } else { users = []; } for (let i = 0; i < this.users.length; i++) { if (this.users[i].username==this.username) { alert("该账号已存在,请更换!") this.username='' this.password='' return } } users.push({ username: this.username, password: this.password, }); localStorage.users = JSON.stringify(users); alert("恭喜您 注册成功"); setTimeout(() => { this.$router.push("login"); }, 500); }, }, }; </script>
-
登录代码
<template> <div class="form-div"> <div class="reg-content"> <h1>用户登录</h1> </div> <table> <tr> <td class="inputs"> <el-input name="username" type="text" id="username" placeholder="账号" v-model="username" /> <br /> </td> </tr> <tr> <td class="inputs"> <el-input name="password" type="password" id="password" placeholder="密码" v-model="password" show-password /> <br /> </td> </tr> </table> <div class="buttons"> <input value="登 录" type="submit" id="reg_btn" @click="login" /> <input value="注 册" type="submit" id="reg_btn" @click="toRegister" /> </div> </div> </template> <script> export default { name: "Register", data() { return { users: JSON.parse(localStorage.getItem("users")) || [], username: "", password: "", }; }, methods: { toRegister() { this.$router.push("register"); }, login() { let a=false for (let i = 0; i < this.users.length; i++) { if ( this.users[i].username == this.username && this.users[i].password == this.password ) { a=true break }else{ a=false } } if(a){ this.$router.push({ name:"todo", query:{ username:this.username } }); }else{ alert('账号或密码输入错误'); this.password='' } }, }, }; </script>
-
倒计时代码
<template> <div class="todo-container"> <div class="time"> <p>现在是:{{ year }}年{{ month }}月{{ date }}日{{ hour }}</p> <p>今天剩余 {{ shi }}时 {{ fen }}分 {{ miao }}秒</p> <p>距离今年结束还有 {{ day }}天 {{ shi }}时 {{ fen }}分 {{ miao }}秒</p> <p>这个月已经过去{{ date - 1 }}天</p> <p>今天是:{{ week }}</p> </div> <div class="back"> <button class="btn btn-edit" @click="back">返回</button> </div> </div> </template> <script> export default { name: "CountDown", data() { return { year: "", month: "", date: "", hour: "", day: "", shi: "", fen: "", miao: "", week: "", dingshi:null }; }, methods: { // 返回主页面 back() { this.$router.back(); }, Day() { let t = new Date(); this.year = t.getFullYear(); this.month = t.getMonth() + 1; this.date = t.getDate(); this.week = t.getDay(); let weekday = new Array(7); weekday = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]; this.week = weekday[this.week]; }, timer() { let t = new Date(); this.hour = t.toLocaleTimeString(); console.log(t); }, countDown() { let today = new Date(); let endDay = new Date("2023/1/1 0:0:0"); let between = endDay - today; between = parseInt(between / 1000); this.day = parseInt(parseInt(parseInt(between / 60) / 60) / 24); this.shi = parseInt(parseInt(parseInt(between / 60) / 60) % 24); this.fen = parseInt(parseInt(between / 60) % 60); this.miao = parseInt(between % 60) + 1; }, dingshi1() { this.dingshi = setInterval(() => { this.timer(); this.countDown(); }, 500); }, clear() { clearInterval(this.dingshi); }, }, mounted() { this.Day(); this.dingshi1(); }, beforeDestroy(){ this.clear(); }, }; </script>
-
待办清单代码
-
头部
<template> <div class="todo-header"> <input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="add" /> </div> </template> <script> import { nanoid } from "nanoid"; export default { name: "MyHeader", data() { return { title: "", }; }, methods: { add() { if (this.title.trim() == "") { alert("待办事项不能为空,请输入你的待办事项!"); this.title='' } else { //包装为todo对象 const todoObj = { id: nanoid(), title: this.title, done: false, isEdit:false }; this.$emit('addTodo', todoObj); //清空输入框中的值 this.title = ""; } }, }, }; </script>
-
list
<template> <ul class="todo-main"> <MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" /> </ul> </template> <script> import MyItem from "./MyItem.vue"; export default { name: "MyList", components: { MyItem, }, props:['todos'] }; </script>
-
item
<template> <transition name="todo" appear> <li> <label> <input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)" /> <!-- 如下代码也能实现功能,但是不太推荐,因为有点违反原则,因为修改了props --> <!-- <input type="checkbox" v-model="todo.done"/> --> <span id="title" v-show="!todo.isEdit" :class="todo.done? 'line-through' :''" >{{ todo.title }}</span> <input id="tiTle" v-show="todo.isEdit" type="text" :value="todo.title" @blur="handleBlur(todo, $event)" ref="inputTitle" /> </label> <button class="btn btn-danger" @click="handleDelete(todo.id)"> <i class="el-icon-delete"></i> </button> <button class="btn btn-edit" @click="handleEdit(todo)" v-show="!todo.isEdit&&!todo.done" > <i class="el-icon-edit"></i> </button> </li> </transition> </template> <script> export default { name: "MyItem", //声明接收todo对象 props: ["todo"], methods: { //勾选或取消勾选 handleCheck(id) { // this.checkTodo(id) this.$bus.$emit("checkTodo", id); }, //删除 handleDelete(id) { if (confirm("您确定要删除该项待办吗?")) { // this.deleteTodo(id) this.$bus.$emit("deleteTodo", id); } }, //编辑 handleEdit(todo) { // this.$set(todo,'isEdit',true) todo.isEdit = true; //由于Vue先解析代码还没有将输入框渲染上页面,如果不设置延迟将会找不到该输入框,从而没有focus效果 // setTimeout(()=>{ // this.$refs.inputTitle.focus() // },100) this.$nextTick(function () { this.$refs.inputTitle.focus(); }); }, //失去焦点修改todo handleBlur(todo, e) { todo.isEdit = false; if (!e.target.value.trim()) { return alert("输入不能为空!"); } this.$bus.$emit("updateTodo", todo.id, e.target.value); }, }, }; </script>
-
脚部
<template> <div class="todo-footer" v-show="total"> <label> <!-- <input type="checkbox" :checked="isAll" @change="checkAll"/> --> <input type="checkbox" v-model="isAll" /> </label> <span> <span>已完成{{ doneTotal }}</span> / 全部{{ total }} </span> <button class="btn btn-danger" @click="clearAll">清除已完成任务</button> </div> </template> <script> export default { name: "MyFooter", props: ["todos", "checkAllTodo", "clearAllTodo"], computed: { total() { return this.todos.length; }, doneTotal() { let i = 0; this.todos.forEach((todo) => { if (todo.done) { i++; } }); return i; }, isAll: { get() { return this.doneTotal == this.total && this.total > 0; }, set(value) { this.checkAllTodo(value); }, }, }, methods: { clearAll() { if (confirm("您确定要删除所有的已完成待办吗?")) { this.clearAllTodo(); } }, }, }; </script>
-