把todolist拆分为header、footer、list三个模块
index文件
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>todos</title> 6 <link rel="stylesheet" type="text/css" href="css/index.css"> 7 </head> 8 <body> 9 <section class="todoapp" id="app"> 10 <div> 11 <my-header 12 @addrecord="parentAdd" 13 ></my-header> 14 <section class="main"> 15 <input 16 class="toggle-all" 17 type="checkbox" 18 v-model="all" 19 20 > 21 <List 22 :act="filters" 23 @rmdata="parentRm" 24 > 25 </List> 26 </section> 27 <my-footer 28 v-show="!!arr.length" 29 :n="num" 30 :cn="cnum" 31 ></my-footer> 32 </div> 33 </section> 34 <script src="js/vue.min.js"></script> 35 <script src="component/header.js"></script> 36 <script src="component/footer.js"></script> 37 <script src="component/list.js"></script> 38 <script> 39 /* 40 实现的一些功能: 41 1、输入内容回车添加内容 42 2、全选功能 43 3、勾选任意内容进行删除 44 4、根据hash不同,过滤渲染的数据 45 */ 46 new Vue({ 47 el:'#app', 48 data:{ 49 filters:[],//拿到过滤之后的数据 50 cunm:'/checked',//值根据hash值而改变,且会影响tab的active状态 51 arr:[ 52 { 53 id:0, 54 city:'多伦多', 55 checked:true 56 }, 57 { 58 id:1, 59 city:'悉尼', 60 checked:false 61 }, 62 { 63 id:2, 64 city:'慕尼黑', 65 checked:false 66 }, 67 { 68 id:3, 69 city:'雅加达', 70 checked:false 71 } 72 ] 73 }, 74 methods:{ 75 //把传过来的数据添加到数组中 76 parentAdd(data){ 77 this.arr.unshift(data) 78 }, 79 //利用filter删除(把e.id等于id的过滤掉,留下不等于id的) 80 parentRm(id){ 81 this.arr = this.arr.filter(e=>e.id!==id) 82 }, 83 hashFn(){ 84 //当hash改变时候,过滤数据 85 let H = window.location.hash.split('#')[1]; 86 this.cnum = H; 87 this.filters = this.arr.filter(e=>{ 88 switch(H){ 89 case '/all': 90 return e; 91 break; 92 case '/unchecked': 93 return !e.checked; 94 break; 95 case '/checked': 96 return e.checked; 97 break; 98 default: 99 return e; 100 break 101 } 102 }); 103 } 104 }, 105 computed:{ 106 all:{ 107 get(){ 108 //如果arr的length没有直接返回false 109 if(!this.arr.length){ 110 return false; 111 } 112 //所有checked都是真的,就全部选中 113 return this.arr.every(e=>e.checked) 114 }, 115 set(newVal){ 116 //把所有的checked都等于newVal 117 return this.arr.forEach(e=>{ 118 e.checked = newVal 119 }) 120 } 121 }, 122 num(){ 123 //未选中的个数 124 return this.arr.filter(e=>!e.checked).length; 125 } 126 }, 127 //当点击选中的时候,会改变arr的数据,当arr中的数据改变就重新过滤数组 128 watch:{ 129 arr:{ 130 handler(){ 131 this.hashFn(); 132 }, 133 deep:true 134 } 135 }, 136 created(){ 137 let hash = window.location.hash; 138 //如果没有hash就给他设置 139 if(!hash){ 140 window.location.hash = '#/all'; 141 }else{ 142 this.hashFn(); 143 } 144 window.onhashchange = () =>{ 145 this.hashFn(); 146 } 147 } 148 }); 149 </script> 150 </body> 151 </html>
header.js文件
1 Vue.component('my-header',{ 2 template:` 3 <header class="header" > 4 <h1>todos</h1> 5 <input 6 class="new-todo" 7 placeholder="请输入内容" 8 @keyup.13="add" 9 v-model="val" 10 > 11 12 </header> 13 `, 14 data(){ 15 return{ 16 val:'' 17 } 18 }, 19 methods:{ 20 add(){ 21 //添加数据 22 if(this.val){ 23 this.$emit('addrecord',{ 24 id:+new Date, 25 city:this.val, 26 checked:false 27 }) 28 this.val = ''//把原先输入的内容清空 29 } 30 } 31 } 32 })
list.js文件
1 Vue.component('list',{ 2 //li中class是动态的,需要给个val.checked 3 template:` 4 <ul class="todo-list"> 5 <li 6 v-for="(val,key) in act" 7 :class="{completed:val.checked}" 8 > 9 <div class="view"> 10 <input 11 class="toggle" 12 type="checkbox" 13 v-model="val.checked" 14 > 15 <label>{{val.city}}</label> 16 <button class="destroy" @click="rm(val.id)"></button> 17 </div> 18 </li> 19 </ul> 20 `, 21 props:['act'], 22 methods:{ 23 rm(id){ 24 this.$emit('rmdata',id) 25 } 26 } 27 })
footer.js文件
1 Vue.component('my-footer',{ 2 template:` 3 <footer class="footer"> 4 <span class="todo-count"> 5 <strong>{{n}}</strong> 6 <span>条未选中</span> 7 </span> 8 <ul class="filters"> 9 <li v-for="(val,key) in btns"> 10 <a 11 :href="val.hash" 12 :class="{selected:val.hash.substring(1) == cn}" 13 >{{val.name}}</a> 14 </li> 15 </ul> 16 </footer> 17 `, 18 props:['n','cn'], 19 data(){ 20 return { 21 num:'#/all', 22 btns:[ 23 { 24 hash:'#/all', 25 name:'全部' 26 }, 27 { 28 hash:'#/unchecked', 29 name:'未选中' 30 }, 31 { 32 hash:'#/checked', 33 name:'已选中' 34 }, 35 ] 36 } 37 38 } 39 })