效果展示:
源代码:
提取码:rk3qhttp://xn--https-bl8js66z7n7i//pan.baidu.com/s/10UVcXPwb6IGEwsVv13krGQ
**实现静态页面**
1.把数据放在APP组件内,通过props传给子组件TODO,然后遍历。
2.添加事件
子组件heard:
定义键盘事件keyup.enter,空字符串***title:‘ ’***,再把input的value用v-model和title双向绑定,方便我们把新添加的事件追加到静态数据todos里。
添加数据到todos有多种方法,可以用props让父组件传一个函数给子组件(heardView)调用并把新定义的事件对象以参数的形式传给父组件(APP),也可以用$emit触发父组件的自定义事件把新定义的数据传过去。这里我用的是props。
<div id="heard">
<label for="title">ToDoList</label>
<input type="text" id="title" name="title" placeholder="添加ToDo" required="required"
autocomplete="off" @keydown.enter="add" v-model="title"/>
</div>
props: ['addtodo',],
methods: {
add() {
if (!this.title) return alert('输入不能为空')
const todoobj = { id: nanoid(), title: this.title, completed: false }
this.addtodo(todoobj)
this.title = ''
}
},
上面代码中新添加事件的ID是用nanoid插件生成的。
使用方法:在需要使用nanoid生成ID的组件引入,直接调用nanoid()即可。
import { nanoid } from 'nanoid'
(插件的安装方式:在当前文件下 用 npm install nanoid 如果出现报错,则可能是版本不符,推荐安装3.0版本,命令:npm i nanoid@3。补充:npm view (组件名) versions 可以查看插件的所有版本,npm (组件名) -v,可以查看当前安装插件版本。)
也可以用时间戳的方式生成(例如:+new Date())。
父组件APP:
methods: {
addtodo(todoobj) {//添加待做事件
this.todos.unshift(todoobj)
},
}
3.改变input勾选状态
这个功能也可以用props父组件传函数和$emit触发父组件的自定义事件来实现。还有一种更方便的方法,用v-model绑定props传过来的todos遍历的todo.completed。但是这样就改变了props的值,虽然vue没有监测到,但这是不被允许的。
props方法:
父组件APP:
<Todo :todos="todos" :changechecked="changechecked" @removeTodo="removeTodo"></Todo>
changechecked(id) {//改变表单勾选状态
//方法1.获取点击的ID把它的complete值取反
this.todos.forEach(todo => {
if (todo.id == id) {
todo.completed = !todo.completed
}
})
子组件todo:
<ol id="todolist">
<li v-for="todo in todos" :key="todo.id"><!--改变勾选状态放法1-->
<input type="checkbox" @click="change(todo.id)" :checked="todo.completed" />
<!-- <input type="checkbox" v-model="todo.completed" /> -->
<span>{{todo.title}}</span>
<button class="btn btn-danger" @click="delTodo(todo.id)">删除</button>
</li>
</ol>
change(id) {//通过调用props传递的函数把ID给父组件
this.changechecked(id)
},
4.删除事件:
这里也可以使用 props或者$emit,本次演示$emit。通过绑定自定义事件收到子组件传来的发生点击事件 `(<li>)`的ID并筛选出去。
父组件APP:
<Todo :todos="todos" :changechecked="changechecked" @removeTodo="removeTodo"></Todo>
<Done :todos="todos" @removeDone="removeTodo"></Done>
待做事件和已完成都有删除功能,所以自定义事件可以重复使用。
removeTodo(id) {
this.todos = this.todos.filter(todo => {
return todo.id != id;
})
},
动态数据:待做事件,已完成事件切换与计数
1.计数功能:
遍历todos得到done的值,当值为真时已完成事件数量加1,反之待做事件数量加1。方法有很多,这里演示计算属性的方法。补充:通过计算得到的值,一般不做修改,所以这里我只写了getter().
computed: {
num: {//通过循环得到当前值的checked,计算得出待做事件todos的数量
get() {
return this.todos.reduce((total, item) => {
return total+(item.completed?0:1)
},0)
}
},
newnum: {//通过循环得到当前值的checked,计算得出已做事件dones的数量
get() {
return this.todos.reduce((total, item) => {
return total + (item.completed ? 1 : 0)
}, 0)
},
}
2.todo,done动态切换:
因为在实现静态页面3.改变input状态里,我们把发生点击事件的 `<li>里面的input状态取反了,这样我们就可以拿到props传过来的todos,然后用计算属性遍历得到我们想要的input状态的事件数组。`
待做事件Todo:
注意:从props拿到的todos并没有直接使用,而是用计算属性筛选之后得到的newMSg去遍历。
props: ['todos'],
<ul id="donelist">
<li v-for="done in newMsg" :key="done.id">
<input type="checkbox" v-model='done.completed'/>
<span>{{done.title}}</span>
<button class="btn btn-danger" @click="deldo(done.id)">删除</button>
</li>
</ul>
computed: {
newMsg: {
get() {//通过计算父组件用props传来的数据,把checked为false的筛选出去
return this.todos.filter(todo => {
return todo.completed == true
})
},
}
}
已做事件Done;
同上
本地存储
父组件APP:
利用监视属性来对todos进行深度监视,只要todos发生改变就把handler(newval)中的newval保存到本地。
watch: {
todos: {
deep: true,
handler(val) {
localStorage.setItem('Todos',JSON.stringify(val))
}
}
},
拿到本地存储的数据:
export default {
name: 'App',
data() {
return {
todos: JSON.parse(localStorage.getItem('Todos'))||[]
}
},
因为todos默认为空,所以JSON.stringify(val)为null,又因为JSON.parse(null)==null,所以要在JSON.parse(localStorage.getItem('Todos'))为空时把todos赋为【】空数组。