纯前端Vue实现Todo_list备忘录及导航案例

Vue实现Todo_list备忘录及导航

1、前言

去年在学习Vue的时候做了一个todoList案例,这里我简单的对其进行了一些改造,并加了些导航,如果做得更完善一些的话可以做成个人浏览器主页。

image-20220630181453016

2、主要用到的技术及依赖

  • Vue
  • core-js
  • nanoid

3、关于项目

https://github.com/GitHub-Ninghai/Todo_list_vue

🌟引入:npm init

🚀运行: npm run serve

daka1文件夹为打包后的文件夹

4、代码实现

首先将页面拆分为五个小组件,为了方便理解我绘制了一份容器图。

image-20220630213322514

由于主要以Vue为主,下面的示例就不写style标签了,详情请看github仓库。

1、HelloWorld组件

先说一下最简单的HelloWord组件,是的连Vue初始化的名字都没有改的组件,而且在组件内部也保持了高度一致(非常尊重Vue的模板好吧),主要是将一些导航加了上去,实现了跳转各常用链接的功能。具体代码如下

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>
      这是一个供您记录任务并打卡的小小备忘录网站(*^▽^*)<br>
      <!-- Vue官方文档
      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>. -->
    </h2>
    <h3>常用网站链接</h3>
    <ul>
      <li><a href="https://home.code-nav.cn/" target="_blank" rel="noopener">百度</a></li>
      <li><a href="https://www.bilibili.com/" target="_blank" rel="noopener">B站</a></li>
      <li><a href="https://www.code-nav.cn/" target="_blank" rel="noopener">编程导航</a></li>
      <li><a href="https://www.csdn.net/" target="_blank" rel="noopener">CSDN</a></li>
      <li><a href="https://github.com/" target="_blank" rel="noopener">github</a></li>
    </ul>
     <h3>学校相关链接</h3>
    <ul>
      <li><a href="https://www.lnkjzm.cn/" target="_blank" rel="noopener">筑梦辽科</a></li>
      <li><a href="http://cxcyxy.lnist.edu.cn/" target="_blank" rel="noopener">创新创业学院</a></li>
      <li><a href="https://lkyjw.lnist.edu.cn/" target="_blank" rel="noopener">教务在线</a></li>
      <li><a href="http://210.30.224.150/cxxf/" target="_blank" rel="noopener">双创学分系统</a></li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

2、myHeader组件

myHeader组件主要设计了输入框,并利用 @keyup.enter的方法实现回车后检验数据、包装数据之后将数据清空。

其中nanoid是唯一的 JavaScript 字符串ID生成器。用于生成对象的id。

<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',
    props:['addTodo'],
    data() {
      return {
        title:''
      }
    },
    methods: {
      add(){
        // 检验数据
        if (!this.title.trim()) {
          return alert('输入不能为空')
        }
        // 将用户的输入包装成一个todo对象
        const todoNew = {id:nanoid(),title:this.title,done:false}
        // 通知Ap组件去添加一个todo对象
        // this.addTodo(todoNew)
        this.$emit('addTodo',todoNew)
        // 清空输入
        this.title = ''
      }
    },
  }
</script>

3、myFooter组件

主要实现完成任务的功能包括通过定义totaldoneTotal计算属性来计算待办总数。isAll方法则计算是否全选,并定义clearAll方法来清除全选内容。

<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'],
    computed:{
      total(){
        return this.todos.length
      },
      doneTotal(){
        return this.todos.reduce((pre,todo) => pre + (todo.done ? 1 : 0),0)
      },
      isAll:{
        get(){
          return this.doneTotal === this.total && this.total > 0
        },
        set(value){
          this.$emit('checkAllTodo',value)
        }
      }
    },
    methods: {
      clearAll(){
        this.$emit('clearAllTodo')
      }
    },
}
</script>

4、myList组件

此组件内主要实现了动画效果以及遍历列表(待办任务)的功能

动画

<template>
  <ul class="todo-main">
    <transition-group appear name="todo">
      <myItem v-for="todoObj in todos" :key="todoObj.id"  :todo="todoObj" />
    </transition-group>
  </ul>
</template>
<script>
import myItem from './myItem.vue'
export default {
    name:'myList',
    components:{
        myItem
    },
    props:['todos']
}
</script>

5、myItem组件

此组件主要实现了每个列表里的编辑和删除功能。使用全局事件总线进行父子组件通信,将编辑修改后的数据传给myList组件。

动画2

<template>
      <li>
          <label>
              <input type="checkbox" :checked="todo.done" @click="handleCheck(todo.id)"  />
              <span v-show="!todo.isEdit">{{todo.title}}</span>
              <input 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)">删除</button>
          <button v-show="!todo.isEdit" class="btn btn-edit" @click="handleEdit(todo)">编辑</button>
      </li>
</template>
<script>
export default {
    name:'myItem',
    // 声明接收todo对象
    // props:['todo','checkTodo','deleteTodo'],
    props:['todo'],
    methods: {
      handleCheck(id){
        // 通知App组件将对应的todo
        // this.checkTodo(id)
        this.$bus.$emit('checkTodo',id)
      },
      handleDelete(id){
        if (confirm('确定删除吗?')) {
          // this.deleteTodo(id)
          this.$bus.$emit('deleteTodo',id)
          // pubsub.publish('deleteTodo',id)
        }
      },
      handleEdit(todo){
        if(todo.hasOwnProperty.call('isEdit')){
          todo.isEdit = true
        }
        else{
          this.$set(todo,'isEdit',true)
        }
        this.$nextTick(function(){
          this.$refs.inputTitle.focus()
        })

      },
      //失去焦点
      handleBlur(todo,e){
        todo.isEdit = false
        this.$bus.$emit('updateTodo',todo.id,e.target.value)
      }
    },
}
</script>

6、App组件

  • 在App组件中实现各组件的引入注册和使用。
  • 在data中通过本地存储来将数据存储到本地磁盘。
  • 在methods中定义增删改勾的方法。
  • watch监听数据发生的变化从而保证实时同步到localstorage中。
<template>
    <div id="root">
      <div class="todo-container">
      <img id="logo" alt="logo" src="./assets/logo.png">
        <div class="todo-wrap">
          <HelloWorld />
          <myHeader @addTodo="addTodo"/>
          <!-- <myList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/> -->
          <myList :todos="todos" />
          <myFooter :todos="todos" @checkAllTodo="checkAllTodo" @clearAllTodo="clearAllTodo"/>
        </div>
              <img id="logo" alt="logo" src="./assets/chong.jpg">
      </div>
  </div>
</template>

<script>
// import pubsub from 'pubsub-js'
import myHeader from './components/myHeader.vue'
import myList from './components/myList.vue'
import myFooter from './components/myFooter.vue'
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    myHeader,myList,myFooter,HelloWorld
  },
  data() {
    return {
      todos:JSON.parse(localStorage.getItem('todos')) || []
    }
  },
  methods: {
    // 添加一个todo
    addTodo(todoObj){
      this.todos.unshift(todoObj)
    },
    // 勾选or取消勾选一个todo
    checkTodo(id){
      this.todos.forEach((todo)=>{
        if(todo.id === id) todo.done = !todo.done
      })
    },
    //改
    updateTodo(id,title){
      this.todos.forEach((todo)=>{
        if(todo.id === id) todo.title = title
      })
    },
    // 删除一个todo
    deleteTodo(id){
      this.todos=this.todos.filter(todo => todo.id !== id)
    },
    // 全选or全不选
    checkAllTodo(done){
      this.todos.forEach((todo)=>{
        todo.done = done
      })
    },
    //清除所有已经完成的todo
   clearAllTodo(){
      this.todos =  this.todos.filter((todo)=>{
        return !todo.done
      })
   }
  },
  watch:{
    todos:{
      deep:true,
      handler(value){
      localStorage.setItem('todos',JSON.stringify(value))
      }
    }
  },
  mounted(){
    this.$bus.$on('checkTodo',this.checkTodo)
    this.$bus.$on('updateTodo',this.updateTodo)
    this.$bus.$on('deleteTodo',this.deleteTodo)
  },
  beforeDestroy(){
    this.$bus.$off(['checkTodo','deleteTodo','updateTodo'])
  }
}
</script>

以上就是todolist案例的详细解读啦!

打卡在线访问地址http://daka.lnkjzm.cn/

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天海一直在AI

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

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

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

打赏作者

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

抵扣说明:

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

余额充值