Vue50 todolist自界说事件版本

打印 上一主题 下一主题

主题 1018|帖子 1018|积分 3054

代码

MyFooter.vue

  1. <template>
  2.         <div class="todo-footer" v-show="total">
  3.                 <label>
  4.                         <!-- <input type="checkbox" :checked="isAll" @change="checkAll"/> -->
  5.                         <input type="checkbox" v-model="isAll"/>
  6.                 </label>
  7.                 <span>
  8.                         <span>已完成{{doneTotal}}</span> / 全部{{total}}
  9.                 </span>
  10.                 <button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
  11.         </div>
  12. </template>
  13. <script>
  14.         export default {
  15.                 name:'MyFooter',
  16.                 props:['todos'],
  17.                 computed: {
  18.                         //总数
  19.                         total(){
  20.                                 return this.todos.length
  21.                         },
  22.                         //已完成数
  23.                         doneTotal(){
  24.                                 //此处使用reduce方法做条件统计
  25.                                 /* const x = this.todos.reduce((pre,current)=>{
  26.                                         console.log('@',pre,current)
  27.                                         return pre + (current.done ? 1 : 0)
  28.                                 },0) */
  29.                                 //简写
  30.                                 return this.todos.reduce((pre,todo)=> pre + (todo.done ? 1 : 0) ,0)
  31.                         },
  32.                         //控制全选框
  33.                         isAll:{
  34.                                 //全选框是否勾选
  35.                                 get(){
  36.                                         return this.doneTotal === this.total && this.total > 0
  37.                                 },
  38.                                 //isAll被修改时set被调用
  39.                                 set(value){
  40.                                         // this.checkAllTodo(value)
  41.                                         this.$emit('checkAllTodo',value)
  42.                                 }
  43.                         }
  44.                 },
  45.                 methods: {
  46.                         /* checkAll(e){
  47.                                 this.checkAllTodo(e.target.checked)
  48.                         } */
  49.                         //清空所有已完成
  50.                         clearAll(){
  51.                                 // this.clearAllTodo()
  52.                                 this.$emit('clearAllTodo')
  53.                         }
  54.                 },
  55.         }
  56. </script>
  57. <style scoped>
  58.         /*footer*/
  59.         .todo-footer {
  60.                 height: 40px;
  61.                 line-height: 40px;
  62.                 padding-left: 6px;
  63.                 margin-top: 5px;
  64.         }
  65.         .todo-footer label {
  66.                 display: inline-block;
  67.                 margin-right: 20px;
  68.                 cursor: pointer;
  69.         }
  70.         .todo-footer label input {
  71.                 position: relative;
  72.                 top: -1px;
  73.                 vertical-align: middle;
  74.                 margin-right: 5px;
  75.         }
  76.         .todo-footer button {
  77.                 float: right;
  78.                 margin-top: 5px;
  79.         }
  80. </style>
复制代码
MyHeader.vue

  1. <template>
  2.         <div class="todo-header">
  3.                 <input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="add"/>
  4.         </div>
  5. </template>
  6. <script>
  7.         import {nanoid} from 'nanoid'
  8.         export default {
  9.                 name:'MyHeader',
  10.                 data() {
  11.                         return {
  12.                                 //收集用户输入的title
  13.                                 title:''
  14.                         }
  15.                 },
  16.                 methods: {
  17.                         add(){
  18.                                 //校验数据
  19.                                 if(!this.title.trim()) return alert('输入不能为空')
  20.                                 //将用户的输入包装成一个todo对象
  21.                                 const todoObj = {id:nanoid(),title:this.title,done:false}
  22.                                 //通知App组件去添加一个todo对象
  23.                                 this.$emit('addTodo',todoObj,1,2,3)
  24.                                 //清空输入
  25.                                 this.title = ''
  26.                         }
  27.                 },
  28.         }
  29. </script>
  30. <style scoped>
  31.         /*header*/
  32.         .todo-header input {
  33.                 width: 560px;
  34.                 height: 28px;
  35.                 font-size: 14px;
  36.                 border: 1px solid #ccc;
  37.                 border-radius: 4px;
  38.                 padding: 4px 7px;
  39.         }
  40.         .todo-header input:focus {
  41.                 outline: none;
  42.                 border-color: rgba(82, 168, 236, 0.8);
  43.                 box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
  44.         }
  45. </style>
复制代码
MyItem.vue

  1. <template>
  2.         <li>
  3.                 <label>
  4.                         <input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
  5.                         <!-- 如下代码也能实现功能,但是不太推荐,因为有点违反原则,因为修改了props -->
  6.                         <!-- <input type="checkbox" v-model="todo.done"/> -->
  7.                         <span>{{todo.title}}</span>
  8.                 </label>
  9.                 <button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
  10.         </li>
  11. </template>
  12. <script>
  13.         export default {
  14.                 name:'MyItem',
  15.                 //声明接收todo、checkTodo、deleteTodo
  16.                 props:['todo','checkTodo','deleteTodo'],
  17.                 methods: {
  18.                         //勾选or取消勾选
  19.                         handleCheck(id){
  20.                                 //通知App组件将对应的todo对象的done值取反
  21.                                 this.checkTodo(id)
  22.                         },
  23.                         //删除
  24.                         handleDelete(id){
  25.                                 if(confirm('确定删除吗?')){
  26.                                         //通知App组件将对应的todo对象删除
  27.                                         this.deleteTodo(id)
  28.                                 }
  29.                         }
  30.                 },
  31.         }
  32. </script>
  33. <style scoped>
  34.         /*item*/
  35.         li {
  36.                 list-style: none;
  37.                 height: 36px;
  38.                 line-height: 36px;
  39.                 padding: 0 5px;
  40.                 border-bottom: 1px solid #ddd;
  41.         }
  42.         li label {
  43.                 float: left;
  44.                 cursor: pointer;
  45.         }
  46.         li label li input {
  47.                 vertical-align: middle;
  48.                 margin-right: 6px;
  49.                 position: relative;
  50.                 top: -1px;
  51.         }
  52.         li button {
  53.                 float: right;
  54.                 display: none;
  55.                 margin-top: 3px;
  56.         }
  57.         li:before {
  58.                 content: initial;
  59.         }
  60.         li:last-child {
  61.                 border-bottom: none;
  62.         }
  63.         li:hover{
  64.                 background-color: #ddd;
  65.         }
  66.        
  67.         li:hover button{
  68.                 display: block;
  69.         }
  70. </style>
复制代码
MyList.vue

  1. <template>
  2.         <ul class="todo-main">
  3.                 <MyItem
  4.                         v-for="todoObj in todos"
  5.                         :key="todoObj.id"
  6.                         :todo="todoObj"
  7.                         :checkTodo="checkTodo"
  8.                         :deleteTodo="deleteTodo"
  9.                 />
  10.         </ul>
  11. </template>
  12. <script>
  13.         import MyItem from './MyItem'
  14.         export default {
  15.                 name:'MyList',
  16.                 components:{MyItem},
  17.                 //声明接收App传递过来的数据,其中todos是自己用的,checkTodo和deleteTodo是给子组件MyItem用的
  18.                 props:['todos','checkTodo','deleteTodo']
  19.         }
  20. </script>
  21. <style scoped>
  22.         /*main*/
  23.         .todo-main {
  24.                 margin-left: 0px;
  25.                 border: 1px solid #ddd;
  26.                 border-radius: 2px;
  27.                 padding: 0px;
  28.         }
  29.         .todo-empty {
  30.                 height: 40px;
  31.                 line-height: 40px;
  32.                 border: 1px solid #ddd;
  33.                 border-radius: 2px;
  34.                 padding-left: 5px;
  35.                 margin-top: 10px;
  36.         }
  37. </style>
复制代码
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'
  14.         import MyList from './components/MyList'
  15.         import MyFooter from './components/MyFooter.vue'
  16.         export default {
  17.                 name:'App',
  18.                 components:{MyHeader,MyList,MyFooter},
  19.                 data() {
  20.                         return {
  21.                                 //由于todos是MyHeader组件和MyFooter组件都在使用,所以放在App中(状态提升)
  22.                                 todos:JSON.parse(localStorage.getItem('todos')) || []
  23.                         }
  24.                 },
  25.                 methods: {
  26.                         //添加一个todo
  27.                         addTodo(todoObj){
  28.                                 this.todos.unshift(todoObj)
  29.                         },
  30.                         //勾选or取消勾选一个todo
  31.                         checkTodo(id){
  32.                                 this.todos.forEach((todo)=>{
  33.                                         if(todo.id === id) todo.done = !todo.done
  34.                                 })
  35.                         },
  36.                         //删除一个todo
  37.                         deleteTodo(id){
  38.                                 this.todos = this.todos.filter( todo => todo.id !== id )
  39.                         },
  40.                         //全选or取消全选
  41.                         checkAllTodo(done){
  42.                                 this.todos.forEach((todo)=>{
  43.                                         todo.done = done
  44.                                 })
  45.                         },
  46.                         //清除所有已经完成的todo
  47.                         clearAllTodo(){
  48.                                 this.todos = this.todos.filter((todo)=>{
  49.                                         return !todo.done
  50.                                 })
  51.                         }
  52.                 },
  53.                 watch: {
  54.                         todos:{
  55.                                 deep:true,
  56.                                 handler(value){
  57.                                         localStorage.setItem('todos',JSON.stringify(value))
  58.                                 }
  59.                         }
  60.                 },
  61.         }
  62. </script>
  63. <style>
  64.         /*base*/
  65.         body {
  66.                 background: #fff;
  67.         }
  68.         .btn {
  69.                 display: inline-block;
  70.                 padding: 4px 12px;
  71.                 margin-bottom: 0;
  72.                 font-size: 14px;
  73.                 line-height: 20px;
  74.                 text-align: center;
  75.                 vertical-align: middle;
  76.                 cursor: pointer;
  77.                 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
  78.                 border-radius: 4px;
  79.         }
  80.         .btn-danger {
  81.                 color: #fff;
  82.                 background-color: #da4f49;
  83.                 border: 1px solid #bd362f;
  84.         }
  85.         .btn-danger:hover {
  86.                 color: #fff;
  87.                 background-color: #bd362f;
  88.         }
  89.         .btn:focus {
  90.                 outline: none;
  91.         }
  92.         .todo-container {
  93.                 width: 600px;
  94.                 margin: 0 auto;
  95.         }
  96.         .todo-container .todo-wrap {
  97.                 padding: 10px;
  98.                 border: 1px solid #ddd;
  99.                 border-radius: 5px;
  100.         }
  101. </style>
复制代码

运行



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

曂沅仴駦

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表