Vue实现todo清单,登录注册功能,待办事项

一、作品介绍

1、作品用到的技术栈

  1. 开发工具 : Vscode
  2. 语言:Vue2、html、css、js

2、作品实现功能

  1. 注册登录页面
  2. 对待办事项的增删改操作
  3. 显示当前时间和倒计时等功能
  4. 本地存储功能

二、作品展示

1. 用户注册和登录功能

  1. 用户注册请添加图片描述

    1. 用户登录请添加图片描述

2. 用户可实现功能

  1. 增加、删除、修改待办事项在这里插入图片描述在这里插入图片描述

  2. 查看倒计时效果在这里插入图片描述

三、作品代码

  1. 项目基本结构[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jpVnLi5P-1666620582866)(image-20221024220333060.png)]

  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>
    
  3. 登录代码

    <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>
    
  4. 倒计时代码

    <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>
    
    
  5. 待办清单代码

    1. 头部

      <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>
      
    2. 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>
      
    3. 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>
      
    4. 脚部

      <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>
      
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值