案例说明:

  1. ![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的版本来完成

目标功能:

  1. 渲染列表数据 v-for
  2. 点击删除当前列表 splice + index
  3. 回车添加新项目 @keyup.enter=”addTodo”list.unshift
  4. 选择状态切换 v-model
  5. 多选和取消多选 计算属性的set和get
  6. 未完成任务数量统计 computed



vue2的版本

1. 模板

  1. <template>
  2. <section class="todoapp">
  3. <!-- 头部输入框区域 -->
  4. <header class="header">
  5. <h1>todos</h1>
  6. // 第1个v-model: 这里是input输入框 v-model="flag"绑定的是用户输入的内容
  7. <input v-model="flag" class="new-todo" placeholder="请输入要完成的任务" autofocus
  8. @keyup.enter="hAdd" />
  9. </header>
  10. <section class="main">
  11. // 第2个v-model: 全选切换的input v-model="isDoneAll" 绑定的是多选和取消多选的计算属性
  12. <input v-model="isDoneAll" id="toggle-all" class="toggle-all" type="checkbox" />
  13. <label for="toggle-all">标记所有已经完成</label>
  14. <ul class="todo-list">
  15. <!-- 任务列表 -->
  16. <li v-for="(item,idx) in list" :key="item.id">
  17. <div class="view">
  18. // 第3个v-model: v-model="item.isDone" 绑定的是状态的切换
  19. <input v-model="item.isDone" class="toggle" type="checkbox" checked />
  20. <label>{{item.flag}}</label>
  21. <button class="destroy" @click="hDel(idx)"></button>
  22. </div>
  23. </li>
  24. </ul>
  25. </section>
  26. <footer class="footer">
  27. <span class="todo-count">
  28. 还未完成的任务有:<strong>{{isUnOk}}</strong>项
  29. </span>
  30. </footer>
  31. </section>
  32. </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. 完成的功能

  1. data () {
  2. return {
  3. list: [
  4. { id: 1, flag: '吃饭', isDone: true },
  5. { id: 2, flag: '睡觉', isDone: false },
  6. { id: 3, flag: '打豆豆', isDone: false },
  7. ],
  8. flag: '', // 绑定的是输入框的内容
  9. }
  10. },
  11. // 核心代码
  12. computed: {
  13. // 计算属性监听选择状态 全选和反选的功能
  14. isDoneAll: {
  15. get () {
  16. return this.list.every(item => item.isDone === true)
  17. },
  18. set (val) {
  19. return this.list.forEach(item => item.isDone = val)
  20. }
  21. },
  22. // 计算属性统计未完成的数量
  23. isUnOk () {
  24. return this.list.filter(item => item.isDone === false).length
  25. }
  26. },
  27. methods: {
  28. // 删除
  29. hDel (idx) {
  30. this.list.splice(idx, 1)
  31. },
  32. // 按下回车新增
  33. // vue2的双向绑定input 就是在模板里面v-mdel="xxx" 然后在data中定义一下
  34. hAdd () {
  35. this.list.unshift({ id: Date.now, flag: this.flag, isDone: false })
  36. }
  37. }
  38. }

在上面中,这一步是全选和反选的关键步骤:

其他的代码我就不讲了 ,这里主要讲的就是如何完成全选和反选的功能

  1. ![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. 模板

  1. <template>
  2. <section class="todoapp">
  3. <!-- 头部输入框区域 -->
  4. <header class="header">
  5. <h1>todos</h1>
  6. // 第1个v-model: 这里是input输入框 v-model="flag"绑定的是用户输入的内容
  7. <input v-model="flag" class="new-todo" placeholder="请输入要完成的任务" autofocus
  8. @keyup.enter="hAdd" />
  9. </header>
  10. <section class="main">
  11. // 第2个v-model: 全选切换的input v-model="isDoneAll" 绑定的是多选和取消多选的计算属性
  12. <input v-model="isDoneAll" @click="toggleAll" id="toggle-all" class="toggle-all" type="checkbox" />
  13. <label for="toggle-all">标记所有已经完成</label>
  14. <ul class="todo-list">
  15. <!-- 任务列表 -->
  16. <li v-for="(item,idx) in list" :key="item.id">
  17. <div class="view">
  18. // 第3个v-model: v-model="item.isDone" 绑定的是状态的切换
  19. <input v-model="item.isDone" class="toggle" type="checkbox" checked />
  20. <label>{{item.flag}}</label>
  21. <button class="destroy" @click="hDel(idx)"></button>
  22. </div>
  23. </li>
  24. </ul>
  25. </section>
  26. <footer class="footer">
  27. <span class="todo-count">
  28. 还未完成的任务有:<strong>{{isUnOk}}</strong>项
  29. </span>
  30. </footer>
  31. </section>
  32. </template>

注意: 这里和上面的vue2版本是一样的, 同样是绑定了3个v-model

2. 功能

  1. import { computed, ref, watch } from 'vue'
  2. export default {
  3. setup () {
  4. // 定义数据
  5. const list = ref([
  6. { id: 1, flag: '吃饭', isDone: true },
  7. { id: 2, flag: '睡觉', isDone: true },
  8. { id: 3, flag: '打豆豆', isDone: false },
  9. ])
  10. // 点击删除当前的列表
  11. const hDel = idx => {
  12. list.value.splice(idx, 1)
  13. }
  14. // 注意区别vue2中的双向绑定 在vue3中如何做表单的双向绑定? 就是在模板中v-model="flag" 然后在下面定义一下const flag = ref('') 在新增里面 直接就是.value
  15. // 定义v-model绑定当前输入的内容
  16. // 模板中要绑定flag 实现响应式的
  17. const flag = ref('')
  18. // 回车事件里面 新增
  19. const hAdd = () => {
  20. list.value.unshift({
  21. id: Date.now(), flag: flag.value, isDone: false
  22. })
  23. }
  24. // 未完成的还有几项
  25. const unOkTodo = computed(() => {
  26. return list.value.filter(item => item.isDone === false).length
  27. })
  28. // 用watch监听来做 全选和反选
  29. let isDoneAll = ref(false)
  30. watch(
  31. list,
  32. (newValue) => {
  33. console.log(newValue.every((item) => item.isDone))
  34. if (newValue.every((item) => item.isDone)) {
  35. (isDoneAll.value = true)
  36. } else {
  37. (isDoneAll.value = false)
  38. }
  39. },
  40. { immediate: true, deep: true }
  41. )
  42. // 切换按钮
  43. const toggleAll = () => {
  44. if (!isDoneAll.value) {
  45. list.value.forEach(item => item.isDone = true)
  46. } else {
  47. list.value.forEach(item => item.isDone = false)
  48. }
  49. }
  50. return { list, hDel, flag, hAdd, unOkTodo, isDoneAll, toggleAll }
  51. }
  52. }

全选和反选的第1种方法: wacth 侦听器来完成

image.png

第2种方法: computed来完成

image.png