案例说明:
![image.png](https://cdn.nlark.com/yuque/0/2021/png/21762447/1626189034168-302199be-b4d9-4afa-8407-8573af9214dc.png#clientId=ubd116926-3ee6-4&from=paste&height=339&id=u5ba2deb8&margin=%5Bobject%20Object%5D&name=image.png&originHeight=339&originWidth=570&originalType=binary&ratio=1&size=38740&status=done&style=none&taskId=u1c25b937-dfa9-46b7-b627-566c7237f4d&width=570)<br /> ![image.png](https://cdn.nlark.com/yuque/0/2021/png/21762447/1626189046324-767de24e-11f7-4eed-8ac5-45467ca1ea2b.png#clientId=ubd116926-3ee6-4&from=paste&height=353&id=u4fa2aed1&margin=%5Bobject%20Object%5D&name=image.png&originHeight=353&originWidth=584&originalType=binary&ratio=1&size=22116&status=done&style=none&taskId=uf93abbdf-786a-4a5e-b029-c0204524371&width=584)
业务: 全选和反选功能:
1. 使用vue2的版本来完成
2. 使用vue3的版本来完成
目标功能:
- 渲染列表数据 v-for
- 点击删除当前列表 splice + index
- 回车添加新项目 @keyup.enter=”addTodo”list.unshift
- 选择状态切换 v-model
- 多选和取消多选 计算属性的set和get
- 未完成任务数量统计 computed
vue2的版本
1. 模板
<template>
<section class="todoapp">
<!-- 头部输入框区域 -->
<header class="header">
<h1>todos</h1>
// 第1个v-model: 这里是input输入框 v-model="flag"绑定的是用户输入的内容
<input v-model="flag" class="new-todo" placeholder="请输入要完成的任务" autofocus
@keyup.enter="hAdd" />
</header>
<section class="main">
// 第2个v-model: 全选切换的input v-model="isDoneAll" 绑定的是多选和取消多选的计算属性
<input v-model="isDoneAll" id="toggle-all" class="toggle-all" type="checkbox" />
<label for="toggle-all">标记所有已经完成</label>
<ul class="todo-list">
<!-- 任务列表 -->
<li v-for="(item,idx) in list" :key="item.id">
<div class="view">
// 第3个v-model: v-model="item.isDone" 绑定的是状态的切换
<input v-model="item.isDone" class="toggle" type="checkbox" checked />
<label>{{item.flag}}</label>
<button class="destroy" @click="hDel(idx)"></button>
</div>
</li>
</ul>
</section>
<footer class="footer">
<span class="todo-count">
还未完成的任务有:<strong>{{isUnOk}}</strong>项
</span>
</footer>
</section>
</template>
注意: 上面有3个v-model 弄清楚它们的用途
a) 第1个v-model: 这里是input输入框 v-model=”flag”绑定的是用户输入的内容
b) 第2个v-model: 全选切换input v-model=”isDoneAll” 绑定的是多选和取消多选的计算属性
c) 第3个v-model: v-model=”item.isDone” 绑定的是状态的切换
2. 完成的功能
data () {
return {
list: [
{ id: 1, flag: '吃饭', isDone: true },
{ id: 2, flag: '睡觉', isDone: false },
{ id: 3, flag: '打豆豆', isDone: false },
],
flag: '', // 绑定的是输入框的内容
}
},
// 核心代码
computed: {
// 计算属性监听选择状态 全选和反选的功能
isDoneAll: {
get () {
return this.list.every(item => item.isDone === true)
},
set (val) {
return this.list.forEach(item => item.isDone = val)
}
},
// 计算属性统计未完成的数量
isUnOk () {
return this.list.filter(item => item.isDone === false).length
}
},
methods: {
// 删除
hDel (idx) {
this.list.splice(idx, 1)
},
// 按下回车新增
// vue2的双向绑定input 就是在模板里面v-mdel="xxx" 然后在data中定义一下
hAdd () {
this.list.unshift({ id: Date.now, flag: this.flag, isDone: false })
}
}
}
在上面中,这一步是全选和反选的关键步骤:
其他的代码我就不讲了 ,这里主要讲的就是如何完成全选和反选的功能
![image.png](https://cdn.nlark.com/yuque/0/2021/png/21762447/1626189961708-c78957ac-f8db-46b3-bb28-2f7c38f69d91.png#clientId=ubd116926-3ee6-4&from=paste&height=202&id=uca9ddc8d&margin=%5Bobject%20Object%5D&name=image.png&originHeight=202&originWidth=486&originalType=binary&ratio=1&size=12637&status=done&style=none&taskId=u6db59c8f-ca85-4311-851f-8705dd91620&width=486)
vue3版本
1. 模板
<template>
<section class="todoapp">
<!-- 头部输入框区域 -->
<header class="header">
<h1>todos</h1>
// 第1个v-model: 这里是input输入框 v-model="flag"绑定的是用户输入的内容
<input v-model="flag" class="new-todo" placeholder="请输入要完成的任务" autofocus
@keyup.enter="hAdd" />
</header>
<section class="main">
// 第2个v-model: 全选切换的input v-model="isDoneAll" 绑定的是多选和取消多选的计算属性
<input v-model="isDoneAll" @click="toggleAll" id="toggle-all" class="toggle-all" type="checkbox" />
<label for="toggle-all">标记所有已经完成</label>
<ul class="todo-list">
<!-- 任务列表 -->
<li v-for="(item,idx) in list" :key="item.id">
<div class="view">
// 第3个v-model: v-model="item.isDone" 绑定的是状态的切换
<input v-model="item.isDone" class="toggle" type="checkbox" checked />
<label>{{item.flag}}</label>
<button class="destroy" @click="hDel(idx)"></button>
</div>
</li>
</ul>
</section>
<footer class="footer">
<span class="todo-count">
还未完成的任务有:<strong>{{isUnOk}}</strong>项
</span>
</footer>
</section>
</template>
注意: 这里和上面的vue2版本是一样的, 同样是绑定了3个v-model
2. 功能
import { computed, ref, watch } from 'vue'
export default {
setup () {
// 定义数据
const list = ref([
{ id: 1, flag: '吃饭', isDone: true },
{ id: 2, flag: '睡觉', isDone: true },
{ id: 3, flag: '打豆豆', isDone: false },
])
// 点击删除当前的列表
const hDel = idx => {
list.value.splice(idx, 1)
}
// 注意区别vue2中的双向绑定 在vue3中如何做表单的双向绑定? 就是在模板中v-model="flag" 然后在下面定义一下const flag = ref('') 在新增里面 直接就是.value
// 定义v-model绑定当前输入的内容
// 模板中要绑定flag 实现响应式的
const flag = ref('')
// 回车事件里面 新增
const hAdd = () => {
list.value.unshift({
id: Date.now(), flag: flag.value, isDone: false
})
}
// 未完成的还有几项
const unOkTodo = computed(() => {
return list.value.filter(item => item.isDone === false).length
})
// 用watch监听来做 全选和反选
let isDoneAll = ref(false)
watch(
list,
(newValue) => {
console.log(newValue.every((item) => item.isDone))
if (newValue.every((item) => item.isDone)) {
(isDoneAll.value = true)
} else {
(isDoneAll.value = false)
}
},
{ immediate: true, deep: true }
)
// 切换按钮
const toggleAll = () => {
if (!isDoneAll.value) {
list.value.forEach(item => item.isDone = true)
} else {
list.value.forEach(item => item.isDone = false)
}
}
return { list, hDel, flag, hAdd, unOkTodo, isDoneAll, toggleAll }
}
}