当前位置:   article > 正文

利用vue做一个简单的todolist_vue todolist

vue todolist

1.分模块

刚拿到一个项目时,要先想好一个项目可以分为几部分,每一部分怎么规划。这里我们按照最终想要的效果,主要分为四部分,分别为

2.理清楚层次关系

大的App组件中有myHeader,myList,myFooter组件,然后myList组件中包含myItem组件。

3.代码展示

src/App.vue

  1. <template>
  2. <div id="root">
  3. <div class="todo-container">
  4. <div class="todo-wrap">
  5. <myHeader :addTodo="addTodo" />
  6. <myList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo" />
  7. <myFooter :todos="todos" :checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo" />
  8. </div>
  9. </div>
  10. </div>
  11. </template>
  12. <script>
  13. import myHeader from './components/myHeader.vue';
  14. import myFooter from './components/myFooter.vue';
  15. import myList from './components/myList.vue';
  16. export default {
  17. name: 'App',
  18. components: {
  19. myHeader,
  20. myList,
  21. myFooter
  22. },
  23. data() {
  24. return {
  25. todos: [
  26. { id: '001', title: '学习python框架', done: false },
  27. { id: '002', title: 'vue知识点回顾', done: false },
  28. { id: '003', title: '英语PPT制作', done: false },
  29. ]
  30. }
  31. },
  32. methods: {
  33. //添加一个todo
  34. addTodo(todoObj) {
  35. this.todos.unshift(todoObj)
  36. },
  37. //勾选or取消勾选一个todo
  38. checkTodo(id) {
  39. this.todos.forEach((todo) => {
  40. if (todo.id === id) todo.done = !todo.done
  41. })
  42. },
  43. //删除一个todo
  44. deleteTodo(id) {
  45. this.todos = this.todos.filter(todo => todo.id !== id)
  46. },
  47. //全选or取消勾选
  48. checkAllTodo(done) {
  49. this.todos.forEach(todo => todo.done = done)
  50. },
  51. //删除已完成的todo
  52. clearAllTodo() {
  53. this.todos = this.todos.filter(todo => !todo.done)
  54. }
  55. }
  56. }
  57. </script>
  58. <style>
  59. body {
  60. background: #fff;
  61. }
  62. .btn {
  63. display: inline-block;
  64. padding: 4px 12px;
  65. margin-bottom: 0;
  66. font-size: 14px;
  67. line-height: 20px;
  68. text-align: center;
  69. vertical-align: middle;
  70. cursor: pointer;
  71. box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
  72. border-radius: 4px;
  73. }
  74. .btn-danger {
  75. color: #fff;
  76. background-color: #da4f49;
  77. border: 1px solid #bd362f;
  78. }
  79. .btn-danger:hover {
  80. color: #fff;
  81. background-color: #bd362f;
  82. }
  83. .btn:focus {
  84. outline: none;
  85. }
  86. .todo-container {
  87. width: 600px;
  88. margin: 0 auto;
  89. }
  90. .todo-container .todo-wrap {
  91. padding: 10px;
  92. border: 1px solid #ddd;
  93. border-radius: 5px;
  94. }
  95. </style>

src/myHeader.vue

  1. <template>
  2. <div class="todo-header">
  3. <input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add" v-model="title" />
  4. </div>
  5. </template>
  6. <script>
  7. import { nanoid } from 'nanoid'
  8. export default {
  9. name: 'myHeader',
  10. props: ['addTodo'],
  11. data() {
  12. return {
  13. title: ''
  14. }
  15. },
  16. methods: {
  17. // trim去掉前后空格
  18. add() {
  19. if (!this.title.trim()) return
  20. const todoObj = { id: nanoid(), title: this.title, done: false }
  21. this.addTodo(todoObj)
  22. this.title = ''
  23. }
  24. }
  25. }
  26. </script>
  27. <style scoped>
  28. .todo-header input {
  29. width: 560px;
  30. height: 28px;
  31. font-size: 14px;
  32. border: 1px solid #ccc;
  33. border-radius: 4px;
  34. padding: 4px 7px;
  35. }
  36. .todo-header input:focus {
  37. outline: none;
  38. border-color: rgba(82, 168, 236, 0.8);
  39. box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
  40. }
  41. </style>

 src/myList.vue

  1. <template>
  2. <ul class="todo-main">
  3. <myItem v-for="todo in todos" :key="todo.id" :todo="todo" :checkTodo="checkTodo" :deleteTodo="deleteTodo" />
  4. </ul>
  5. </template>
  6. <script>
  7. import myItem from './myItem.vue';
  8. export default {
  9. name: 'myList',
  10. components: {
  11. myItem
  12. },
  13. props: ['todos', 'checkTodo', 'deleteTodo']
  14. }
  15. </script>
  16. <style scoped>
  17. .todo-main {
  18. margin-left: 0px;
  19. border: 1px solid #ddd;
  20. border-radius: 2px;
  21. padding: 0px;
  22. }
  23. .todo-empty {
  24. height: 40px;
  25. line-height: 40px;
  26. border: 1px solid #ddd;
  27. border-radius: 2px;
  28. padding-left: 5px;
  29. margin-top: 10px;
  30. }
  31. </style>

 src/myItem.vue

  1. <template>
  2. <li>
  3. <label>
  4. <input type="checkbox" :checked="todo.done" @click="handleCheck(todo.id)" />
  5. <span>{{ todo.title }}</span>
  6. </label>
  7. <button class="btn btn-danger" @click="handleDelete(todo.id, todo.title)">删除</button>
  8. </li>
  9. </template>
  10. <script>
  11. export default {
  12. name: 'myItem',
  13. props: ['todo', 'checkTodo', 'deleteTodo'],
  14. methods: {
  15. handleCheck(id) {
  16. this.checkTodo(id)
  17. },
  18. handleDelete(id, title) {
  19. if (confirm("确定删除任务:" + title + "吗?")) {
  20. this.deleteTodo(id)
  21. }
  22. }
  23. }
  24. }
  25. </script>
  26. <style scoped>
  27. li {
  28. list-style: none;
  29. height: 36px;
  30. line-height: 36px;
  31. padding: 0 5px;
  32. border-bottom: 1px solid #ddd;
  33. }
  34. li label {
  35. float: left;
  36. cursor: pointer;
  37. }
  38. li label li input {
  39. vertical-align: middle;
  40. margin-right: 6px;
  41. position: relative;
  42. top: -1px;
  43. }
  44. li button {
  45. float: right;
  46. display: none;
  47. margin-top: 3px;
  48. }
  49. li:before {
  50. content: initial;
  51. }
  52. li:last-child {
  53. border-bottom: none;
  54. }
  55. li:hover {
  56. background-color: #eee;
  57. }
  58. li:hover button {
  59. display: block;
  60. }
  61. </style>

 src/myFooter.vue

  1. <template>
  2. <div class="todo-footer" v-show="total">
  3. <label>
  4. <input type="checkbox" v-model="isAll" />
  5. </label>
  6. <span>
  7. <span>已完成{{ doneTotal }}</span> / 全部{{ total }}
  8. </span>
  9. <button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
  10. </div>
  11. </template>
  12. <script>
  13. export default {
  14. name: 'myFooter',
  15. props: ['todos', 'checkAllTodo', 'clearAllTodo'],
  16. // 计算属性,将函数结果返回到模板语法中 reduce是es6知识点
  17. computed: {
  18. doneTotal() {
  19. return this.todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0)
  20. // let i=0
  21. // this.todos.forEach(todo => {
  22. // if (todo.done) i++
  23. // })
  24. // return i
  25. },
  26. total() {
  27. return this.todos.length
  28. },
  29. isAll: {
  30. get() {
  31. return this.total === this.doneTotal && this.total > 0
  32. },
  33. set(value) {
  34. this.checkAllTodo(value)
  35. }
  36. }
  37. },
  38. methods: {
  39. clearAll() {
  40. this.clearAllTodo()
  41. }
  42. }
  43. }
  44. </script>
  45. <style scoped>
  46. .todo-footer {
  47. height: 40px;
  48. line-height: 40px;
  49. padding-left: 6px;
  50. margin-top: 5px;
  51. }
  52. .todo-footer label {
  53. display: inline-block;
  54. margin-right: 20px;
  55. cursor: pointer;
  56. }
  57. .todo-footer label input {
  58. position: relative;
  59. top: -1px;
  60. vertical-align: middle;
  61. margin-right: 5px;
  62. }
  63. .todo-footer button {
  64. float: right;
  65. margin-top: 5px;
  66. }
  67. </style>

 main.js

  1. import Vue from 'vue'
  2. import App from './App.vue'
  3. Vue.config.productionTip = false
  4. new Vue({
  5. render: h => h(App),
  6. }).$mount('#app')

 4.运行结果展示

vscode终端输入npm run serve,就得到了本地的一个网址

http://localhost:8080/

 上面的代码有些方法和函数不太熟的朋友可以查MDN网站哦,上面都有详细的教程和介绍,链接如下:

https://developer.mozilla.org/zh-CN/

5.总结

(1)采用组件嵌套,这个学起来较为简单,只要将要展示的内容,层次结构理清楚。

(2)学习props传数据,让组件接收外部传过来的数据

(3)

  • props适用于:

    1. 父组件 ==> 子组件 通信
    2. 子组件 ==> 父组件 通信(要求父组件先给子组件一个函数)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/223884
推荐阅读
相关标签
  

闽ICP备14008679号