第三节:Vuejs常用特性2和图书案例
一. 常用特性2
1. 监听器
用watch来响应数据的变化, 一般用于异步或者开销较大的操作, watch 中的属性 一定是data 中 已经存在的数据!!! 当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听.
案例1:监听firstName和lastName,当他们发生变化的时候,fullName也发生变化; 该需求也可也把fullName声明成一个计算属性,同样可以达到这个效果。
案例2:输入用户名,当光标离开input标签的时候,进行验证该用户名是否存在。
2. 过滤器
过滤器可以全局注册Vue.filter,也可以局部注册filters。过滤器可以用在两个地方:双花括号插值和v-bind属性表达式。过滤器不改变真正的 data ,而只是改变渲染的结果,并返回过滤后的版本.
(1).第一个参数表示管道符前面的数据,而且过滤器支持级联操作。
比如:{{msg | glq1 | glq2}} 支持多个过滤器
(2).带参数的过滤器: 第一个参数不需要传递,默认就是要过滤的数据,后面可以继续写参数进行传递。
(3).补充一个日期过滤器
3. 实例的生命周期(常用的8个)
(1) beforeCreate: 在实例初始化之后,数据观测和事件配置之前被调用 此时data 和 methods 以及页面的DOM结构都没有初始化 什么都做不了
(2) created: 在实例创建完成后被立即调用此时data 和 methods已经可以使用 但是页面还没有渲染出来
(3) beforeMount: 在挂载开始之前被调用 此时页面上还看不到真实数据 只是一个模板页面而已
(4) mounted: el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。 数据已经真实渲染到页面上在这个钩子函数里面我们可以使用一些第三方的插件,数据的初始化可以放在这里。
(5) beforeUpdate: 数据更新时调用,发生在虚拟DOM打补丁之前。 页面上数据还是旧的
(6) updated: 由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。 页面上数据已经替换成最新的
(7) beforeDestroy: 实例销毁之前调用
(8) destroyed: 实例销毁后调用
4. 变异方法和替换数组、动态响应数据处理
(1).变异方法:
背景:在 Vue 中,直接修改对象属性的值无法触发响应式。当你直接修改了对象属性的值,你会发现,只有数据改了,但是页面内容并没有改变。所以:Vue中引入变异数组方法,即保持数组方法原有功能不变的前提下对其进行功能拓展,使其支持响应式。
常用方法如下:
a. push: 往数组最后面添加一个元素,成功返回当前数组的长度。
b. pop: 删除数组的最后一个元素,成功返回删除元素的值
c. shift: 删除数组的第一个元素,成功返回删除元素的值
d. unshift: 往数组最前面添加一个元素,成功返回当前数组的长度
e. splice: 有三个参数,第一个要删除元素的下标(必选),第二个要删除元素的个数(必选),第三个删除后想在原位置替换的值
f. sort: 将数组按照字符编码从小到大排序,成功返回排序后的数组
g. reverse: 将数组倒序排列,并返回倒叙后的数组
(2).替换数组
含义: 不会影响原始的数组数据,而是形成一个新的数组.
常用方法:
a. filter: 创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
b. concat: 用于连接两个或多个数组,该方法不会改变现有的数组。
c. slice: 从已有的数组中返回选定的元素。该方法并不会修改数组,而是返回一个子数组
eg:从第0个开始,获取两个元素 this.list = this.list.slice(0, 2);
(3).动态响应数据的处理
A. 操作数组
Vue.set(vm.list, 1, 'ypf');
vm.$set(vm.list, 1, 'ypf');
以上两句话是等效的,都表示把list数组中的第二个元素改为ypf。
B. 操作对象
Vue.set(vm.info, 'sex', '女');
vm.$set(vm.info, 'sex', '女');
以上两句话等效,表示给info对象增加一个属性sex,值为‘女’,如果info对象里已经有了sex属性,则执行的是修改操作
代码分享:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>04-常用特性2</title> 6 <style type="text/css"> 7 p { 8 color: #0000FF; 9 font-size: 18px; 10 } 11 12 div { 13 margin-bottom: 10px; 14 } 15 </style> 16 </head> 17 <body> 18 <div id="myApp"> 19 <p>1.监听器的使用</p> 20 <div> 21 <div> 22 <input type="text" v-model="firstName" placeholder="请输入firstName"> 23 <input type="text" v-model="lastName" placeholder="请输入lastName"> 24 </div> 25 <div>我的全名为:{{fullName}}</div> 26 </div> 27 <div> 28 验证用户名是否存在:<input type="text" v-model.lazy="userName"><span>{{tip}}</span> 29 </div> 30 <p>2.过滤器的使用</p> 31 <div> 32 <input type="text" v-model="msg"> 33 <div>我是大写过滤器:{{msg|higher}}</div> 34 <div>我是小写过滤器:{{msg|lower}}</div> 35 <div :myClass="msg | higher">过滤器加在属性上</div> 36 <span>多参数过滤器</span> 37 <input type="text" v-model.number="myNum"> 38 <div>结果为:{{myNum|myadd(10,20)}}</div> 39 <div>日期过滤器:{{myDate|format('yyyy-MM-dd hh:mm:ss')}}</div> 40 </div> 41 <p>4.变异方法和替换数组</p> 42 <div> 43 <ul> 44 <li :key="index" v-for="(item,index) in list">{{item}}</li> 45 </ul> 46 <input type="text" v-model='fname'> 47 <button @click='add'>添加</button> 48 <button @click='del'>删除</button> 49 <button @click='change'>替换</button> 50 </div> 51 <p>5.动态响应处理</p> 52 <div> 53 <button @click='handle1'>响应处理1</button> 54 <div> 55 <div>{{info.name}}</div> 56 <div>{{info.age}}</div> 57 <div>{{info.sex}}</div> 58 </div> 59 <button @click='handle2'>响应处理2</button> 60 </div> 61 </div> 62 <script src="./js/vue.min.js" type="text/javascript" charset="utf-8"></script> 63 <script type="text/javascript"> 64 //全局过滤器(小写过滤器) 65 Vue.filter('lower', function(val) { 66 return val.toLowerCase(); 67 }); 68 //多参数过滤器 69 //val表示要过滤的值,m,n 分别对应传递进来的两个值,对应上面的10和20 70 Vue.filter('myadd', function(val, m, n) { 71 if (val < 10) { 72 return val + m; 73 } else { 74 return val + n; 75 } 76 }); 77 //补充一个日期过滤器 78 Vue.filter('format', function(value, arg) { 79 function dateFormat(date, format) { 80 if (typeof date === "string") { 81 var mts = date.match(/(\/Date\((\d+)\)\/)/); 82 if (mts && mts.length >= 3) { 83 date = parseInt(mts[2]); 84 } 85 } 86 date = new Date(date); 87 if (!date || date.toUTCString() == "Invalid Date") { 88 return ""; 89 } 90 var map = { 91 "M": date.getMonth() + 1, //月份 92 "d": date.getDate(), //日 93 "h": date.getHours(), //小时 94 "m": date.getMinutes(), //分 95 "s": date.getSeconds(), //秒 96 "q": Math.floor((date.getMonth() + 3) / 3), //季度 97 "S": date.getMilliseconds() //毫秒 98 }; 99 100 format = format.replace(/([yMdhmsqS])+/g, function(all, t) { 101 var v = map[t]; 102 if (v !== undefined) { 103 if (all.length > 1) { 104 v = '0' + v; 105 v = v.substr(v.length - 2); 106 } 107 return v; 108 } else if (t === 'y') { 109 return (date.getFullYear() + '').substr(4 - all.length); 110 } 111 return all; 112 }); 113 return format; 114 } 115 return dateFormat(value, arg); 116 }) 117 118 var vm = new Vue({ 119 el: '#myApp', 120 data: { 121 firstName: '', 122 lastName: '', 123 fullName: '', 124 userName:'', 125 tip:'', 126 msg: '', 127 myNum: '', 128 myDate: new Date(), 129 list: ['apple', 'orange', 'banana'], 130 fname: '', 131 info: { 132 name: 'lmr', 133 age: 20 134 } 135 }, 136 methods: { 137 //验证用户名 138 checkUserName:function(uname){ 139 var that=this; 140 //模拟调用后台 141 setTimeout(function(){ 142 if (uname=='admin') { 143 that.tip='存在'; 144 } else{ 145 that.tip='不存在'; 146 } 147 },1500); 148 }, 149 //增加 150 add: function() { 151 this.list.push(this.fname); 152 }, 153 //删除最后一个 154 del: function() { 155 this.list.pop(); 156 }, 157 //替换 158 change: function() { 159 //从第0个开始,获取两个元素 160 this.list = this.list.slice(0, 2); 161 }, 162 handle1: function() { 163 //下面两句话等效,把list数组中的第二个元素改为ypf 164 Vue.set(vm.list, 1, 'ypf'); 165 // vm.$set(vm.list, 1, 'ypf'); 166 }, 167 handle2: function() { 168 //下面两句话等效,表示给info对象增加一个属性sex,值为‘女’ 169 // Vue.set(vm.info, 'sex', '女'); 170 vm.$set(vm.info, 'sex', '女'); 171 } 172 }, 173 computed: { 174 //这里使用计算属性,也可以达到下面监听器的效果 175 // fullName:function(){ 176 // return this.firstName+' '+this.lastName; 177 // } 178 }, 179 //监听器 180 watch: { 181 //val代表该值 182 firstName: function(val) { 183 this.fullName = val + ' ' + this.lastName; 184 }, 185 lastName: function(val) { 186 this.fullName = this.firstName + ' ' + val; 187 }, 188 userName:function(val){ 189 this.tip='正在校验中...'; 190 this.checkUserName(val); 191 } 192 }, 193 filters: { 194 //大写过滤器 195 higher: function(val) { 196 return val.toUpperCase(); 197 } 198 } 199 200 201 202 }); 203 </script> 204 </body> 205 </html>
运行结果:
二. 图书案例
1. 需求
实现图书系统的显示,删除、修改、增加。
2. 用到的几个数组的技术点:
(1). filter: 根据条件过滤返回一个新数组,function(item){}; item为遍历数组中的元素
(2). some: 用于遍历数组 (item)=>{}, return true; 则结束遍历
(3). findIndex: 查找索引,function(item){}; item为遍历数组中的元素
最终运行效果:
代码分享:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>图书系统</title> 6 <style type="text/css"> 7 .grid { 8 margin: auto; 9 width: 530px; 10 text-align: center; 11 } 12 13 .grid table { 14 border-top: 1px solid #C2D89A; 15 width: 100%; 16 border-collapse: collapse; 17 } 18 19 .grid th, 20 td { 21 padding: 10; 22 border: 1px dashed #F3DCAB; 23 height: 35px; 24 line-height: 35px; 25 } 26 27 .grid th { 28 background-color: #F3DCAB; 29 } 30 31 .grid .book { 32 padding-bottom: 10px; 33 padding-top: 5px; 34 background-color: #F3DCAB; 35 } 36 </style> 37 </head> 38 <body> 39 <div id="myApp"> 40 <div class="grid"> 41 <div> 42 <h1>图书管理</h1> 43 <div class="book"> 44 <div> 45 <label for="id"> 46 编号: 47 </label> 48 <input type="text" id="id" v-model='id' :disabled="isEdit"> 49 <label for="name"> 50 名称: 51 </label> 52 <input type="text" id="name" v-model='name' @keyup.enter="handle"> 53 <button @click='handle'>提交</button> 54 </div> 55 </div> 56 </div> 57 <table> 58 <thead> 59 <tr> 60 <th>编号</th> 61 <th>名称</th> 62 <th>时间</th> 63 <th>操作</th> 64 </tr> 65 </thead> 66 <tbody> 67 <tr :key='item.id' v-for='item in books'> 68 <td>{{item.id}}</td> 69 <td>{{item.name}}</td> 70 <td>{{item.date | format('yyyy-MM-dd hh:mm:ss')}}</td> 71 <td> 72 <a href="" @click.prevent="editShow(item.id)">修改</a> 73 <span>|</span> 74 <a href="" @click.prevent="delBook(item.id)">删除</a> 75 </td> 76 </tr> 77 </tbody> 78 </table> 79 </div> 80 </div> 81 82 <script src="./js/vue.min.js" type="text/javascript" charset="utf-8"></script> 83 <script type="text/javascript"> 84 //日期格式化过滤器 85 Vue.filter('format', function(value, arg) { 86 function dateFormat(date, format) { 87 if (typeof date === "string") { 88 var mts = date.match(/(\/Date\((\d+)\)\/)/); 89 if (mts && mts.length >= 3) { 90 date = parseInt(mts[2]); 91 } 92 } 93 date = new Date(date); 94 if (!date || date.toUTCString() == "Invalid Date") { 95 return ""; 96 } 97 var map = { 98 "M": date.getMonth() + 1, //月份 99 "d": date.getDate(), //日 100 "h": date.getHours(), //小时 101 "m": date.getMinutes(), //分 102 "s": date.getSeconds(), //秒 103 "q": Math.floor((date.getMonth() + 3) / 3), //季度 104 "S": date.getMilliseconds() //毫秒 105 }; 106 format = format.replace(/([yMdhmsqS])+/g, function(all, t) { 107 var v = map[t]; 108 if (v !== undefined) { 109 if (all.length > 1) { 110 v = '0' + v; 111 v = v.substr(v.length - 2); 112 } 113 return v; 114 } else if (t === 'y') { 115 return (date.getFullYear() + '').substr(4 - all.length); 116 } 117 return all; 118 }); 119 return format; 120 } 121 return dateFormat(value, arg); 122 }) 123 124 var vm = new Vue({ 125 el: '#myApp', 126 data: { 127 books: [{ 128 id: 1, 129 name: '三国演义', 130 date: 2525609975000 131 }, { 132 id: 2, 133 name: '水浒传', 134 date: 2525609975000 135 }, { 136 id: 3, 137 name: '红楼梦', 138 date: 2525609975000 139 }, { 140 id: 4, 141 name: '西游记', 142 date: 2525609975000 143 }], 144 id: '', 145 name: '', 146 isEdit: false, 147 }, 148 methods: { 149 //增加 或 修改 150 handle: function() { 151 if (this.isEdit == false) { 152 //表示增加 153 var obj = {}; 154 obj.id = this.id; 155 obj.name = this.name; 156 obj.date = 2525609975000; 157 this.books.push(obj); 158 // 清空表单 159 this.id = ''; 160 this.name = ''; 161 } else { 162 //表示修改 163 //根据id查找出来book,然后进行修改,可以用filter,这里用另外一种方式 Some,查找出来的同时直接修改 164 this.books.some((item) => { 165 if (item.id == this.id) { 166 item.name = this.name; 167 //返回true,表示终止循环 168 return true; 169 } 170 }); 171 //清空表单,并恢复可编辑状态 172 this.id = ''; 173 this.name = ''; 174 this.isEdit = false; 175 } 176 }, 177 //把要修改的内容显示在标签内 178 editShow: function(id) { 179 //根据id查找符合条件的book信息 180 var theEditBook = this.books.filter(function(item) { 181 return item.id == id; 182 }); 183 //给标签赋值 184 this.id = theEditBook[0].id; 185 this.name = theEditBook[0].name; 186 //id标签位置不可改 187 this.isEdit = true; 188 }, 189 //删除图书 190 delBook: function(id) { 191 //方案一 192 // //查找索引 193 // var index=this.books.findIndex(function(item){ 194 // return item.id==id; 195 // }); 196 // //第一个参数表示索引,第二个参数表示删除的个数 197 // this.books.splice(index,1); 198 // 方案二 利用filter 199 this.books = this.books.filter(function(item) { 200 return item.id != id; 201 }); 202 } 203 } 204 }); 205 </script> 206 </body> 207 </html>
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。