Vue实现Todo_list备忘录及导航
文章目录
1、前言
去年在学习Vue的时候做了一个todoList案例,这里我简单的对其进行了一些改造,并加了些导航,如果做得更完善一些的话可以做成个人浏览器主页。
、
2、主要用到的技术及依赖
- Vue
- core-js
- nanoid
- 手
3、关于项目
https://github.com/GitHub-Ninghai/Todo_list_vue
🌟引入:npm init
🚀运行: npm run serve
daka1文件夹为打包后的文件夹
4、代码实现
首先将页面拆分为五个小组件,为了方便理解我绘制了一份容器图。
由于主要以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组件
主要实现完成任务的功能包括通过定义total
和doneTotal
计算属性来计算待办总数。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组件。
<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/