03 . Vue基础之计算属性,过滤器

vue计算属性

/*
		复杂逻辑,模板难以维护
				1. 基础例子
				2. 计算缓存 VS methods
						- 计算属性是基于他们的依赖进行缓存的.
						- 计算属性只有在他的相关依赖发生改变时才会重新求值
				3. 计算属性VS watch
				    - v-model
*/
侦听器
/*
		数据变化时执行异步开销大的操作
*/

Example

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Document</title>
	</head>
	<body>
		<div id="app">
			<div>
				<span>名:</span>
				<span>
					<input type="text" v-model='firstName'>
				</span>
			</div>
			<div>
				<span>姓:</span>
				<span>
					<input type="text" v-model='lastName'>
				</span>
			</div>
			<div>{{fullName}}</div>
		</div>
		<script type="text/javascript" src="js/vue.js"></script>
		<script type="text/javascript">
			/*
      侦听器
    */
			var vm = new Vue({
				el: '#app',
				data: {
					firstName: 'Jim',
					lastName: 'Green',
					// fullName: 'Jim Green'
				},
				computed: {
					fullName: function() {
						return this.firstName + ' ' + this.lastName;
					}
				},
				watch: {
					// firstName: function(val) {
					//   this.fullName = val + ' ' + this.lastName;
					// },
					// lastName: function(val) {
					//   this.fullName = this.firstName + ' ' + val;
					// }
				}
			});
		</script>
	</body>
</html>

Example2

验证用户名是否可用

<!DOCTYPE html>
<html lang="en">

	<head>
		<meta charset="UTF-8">
		<title>Document</title>
	</head>

	<body>
		<div id="app">
			<span>用户名:</span>
			<span>
				<input type="text" v-model.lazy="uname" />
			</span>

			<span>{{ tip }}</span>
		</div>

		<script type="text/javascript" src="js/vue.js"></script>
		<script type="text/javascript">
			/*
				侦听器
					1. 采用侦听器监听用户名的变化
					2. 调用后台接口进行验证
					3. 根据验证的结果调整提示信息
			*/
			var vm = new Vue({
				el: '#app',
				data: {
					uname: '',
					tip: ''
				},
				methods: {
					checkName: function(uname) {
						// 调用接口,但是可以使用定时任务方式模拟接口调用
						var that = this
						setTimeout(function() {
							// 模拟接口调用
							if (uname == "admin") {
								that.tip = '用户名已经存在,请更换一个'
							} else {
								that.tip = '用户名可以使用'
							}
						}, 2000)
					}
				},
				watch: {
					uname: function(val) {
						/// 调用后台接口验证用户名的合法性
						this.checkName(val)

						// 修改提示信息
						this.tip = '正在用户名验证中'
					}
				}
			})
		</script>
	</body>
</html>
计算属性案例

Example1

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
		<title>Examples</title>
		<meta name="description" content="">
		<meta name="keywords" content="">
		<link href="" rel="stylesheet">
		<script type="text/javascript" src="lib/vue.js"></script>
	</head>
	<body>

		<div id="box">
			<!-- 截取myname字符串将首字母大写,不推荐,请看下面 -->
			{{ myname.substring(0,1).toUpperCase() + myname.substring(1) }}
			
			<!-- 不要加(),否则就是函数 -->
			<p>计算属性:{{ getMyName }}</p>
			<p>普通方法:{{ getMyNameMethod() }}</p>
			
			<div>
				也需要计算结果
				<p>计算属性:{{ getMyName }}</p>
				<!-- 计算属性可以让一个页面多个地方调用一个计算结果只调用一次,而方法多次调用会多次执行  -->
				<!-- 1. 依赖的状态改变了, 计算属性会重新计算一遍  
					 2. 计算属性会缓存  -->
				<p>普通方法:{{ getMyNameMethod() }}</p>
			</div>
		</div>

		<script>
			vm = new Vue({
				el: "#box",
				data: {
					myname: "xiaoming"
				},
				
				methods:{
					getMyNameMethod(){
						console.log("getMyNameMethos-方法调用")
						return this.myname.substring(0,1).toUpperCase() + this.myname.substring(1)					}
				},
				
				computed:{
					getMyName(){
						console.log("getMyName-计算属性调用")
						return this.myname.substring(0,1).toUpperCase() + this.myname.substring(1)
					}
				}
			})
		</script>
	</body>
</html>

Example2

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
		<title>Examples</title>
		<meta name="description" content="">
		<meta name="keywords" content="">
		<link href="" rel="stylesheet">
		<script type="text/javascript" src="lib/vue.js"></script>
	</head>
	<body>
		<div id="box">
			<input type="text" v-model="mytext" />
			<!-- <input type="text" @input="handleInput()" v-model="mytext" /> -->

			<ul>
				<li v-for="data in getMyDatalist">
					{{ data }}
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			var vm = new Vue({
				el: "#box",
				data: {
					mytext: "",
					datalist: ["aaa", "bbb", "ccc", "ddd", "eee", ],
				},

				computed: {
					getMyDatalist() {
						return this.datalist.filter(item => item.indexOf(this.mytext) > -1)
					}
				},
			})
		</script>

	</body>
</html>

Example3

<!DOCTYPE html>
<html lang="en">

	<head>
		<meta charset="UTF-8">
		<title>Document</title>
	</head>

	<body>
		<div id="app">
			<div>{{ reverseString }}</div>
			<div>{{ reverseString }}</div>
			<div>{{ reverseMessage() }}</div>
			<div>{{ reverseMessage() }}</div>
		</div>

		<script type="text/javascript" src="js/vue.js"></script>
		<script type="text/javascript">
			var vm = new Vue({
				el: '#app',
				data: {
					msg: 'hello',
					num: 100
				},
				methods: {
					reverseMessage: function() {
						console.log('methods')
						return this.msg.split('').reverse().join('')
					}
				},
				computed: {
					reverseString: function() {
						// return this.msg.split('').reverse().join()
						console.log('computed')
						var total = 0
						for (var i = 0; i <= this.num; i++) {
							total += i
						}
						return total
					}
				}
			})
		</script>
	</body>
</html>

Vue过滤器

功能
/*
		格式化数据,比如将字符串格式化为首字母大写,将日期格式化为指定的格式等.
*/

13

自定义过滤器
/*
		Vue.filter('过滤器名称',function(value){
			// 过滤业务逻辑
			
		})
*/
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Document</title>
	</head>
	<body>
		<div id="app">
			<input type="text" v-model='msg'>
			<div>{{msg |upper }}</div>
			<div>{{msg |lower }}</div>
			<div :abc='msg |upper'>测试数据</div>
		</div>
		<script type="text/javascript" src="js/vue.js"></script>
		<script type="text/javascript">
			/*
			  过滤器
			  1、可以用与插值表达式和属性绑定
			  2、支持级联操作
			*/
			Vue.filter('upper', function(val) {
				return val.charAt(0).toUpperCase() + val.slice(1)
			})

			Vue.filter('lower', function(val) {
				return val.charAt(0).toLowerCase() + val.slice(1)
			})

			var vm = new Vue({
				el: '#app',
				data: {
					msg: ''
				}
			})
		</script>
	</body>
</html>

带参数的过滤器
Vue.filter('format',function(value,arg1){
	// Value就是过滤器传递过来的参数
})

// 使用
<div>
  {{ date | format{'yyyy-MM-dd' } }}
</div>

日期格式化规则

/*
		y: 	年
		M:  年中的月份(1-12)
		d:  月份中的天(1-31)
		h:  小时(0-23)
		m:  分(0-59)
		s:  秒(0-59)
		S:  毫秒(0-999)
		q:  季度(1-4)
		
		时间格式化为yyyy-MM-dd
*/

使用过滤器格式化日期

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Document</title>
	</head>
	<body>
		<div id="app">
			<div>{{date | format('yyyy-MM-dd hh:mm:ss')}}</div>
		</div>
		<script type="text/javascript" src="js/vue.js"></script>
		<script type="text/javascript">
			/*
      过滤器案例:格式化日期
      
    */
			// Vue.filter('format', function(value, arg) {
			//   if(arg == 'yyyy-MM-dd') {
			//     var ret = '';
			//     ret += value.getFullYear() + '-' + (value.getMonth() + 1) + '-' + value.getDate();
			//     return ret;
			//   }
			//   return value;
			// })
			Vue.filter('format', function(value, arg) {
				function dateFormat(date, format) {
					if (typeof date === "string") {
						var mts = date.match(/(\/Date\((\d+)\)\/)/);
						if (mts && mts.length >= 3) {
							date = parseInt(mts[2]);
						}
					}
					date = new Date(date);
					if (!date || date.toUTCString() == "Invalid Date") {
						return "";
					}
					var map = {
						"M": date.getMonth() + 1, //月份 
						"d": date.getDate(), //日 
						"h": date.getHours(), //小时 
						"m": date.getMinutes(), //分 
						"s": date.getSeconds(), //秒 
						"q": Math.floor((date.getMonth() + 3) / 3), //季度 
						"S": date.getMilliseconds() //毫秒 
					};

					format = format.replace(/([yMdhmsqS])+/g, function(all, t) {
						var v = map[t];
						if (v !== undefined) {
							if (all.length > 1) {
								v = '0' + v;
								v = v.substr(v.length - 2);
							}
							return v;
						} else if (t === 'y') {
							return (date.getFullYear() + '').substr(4 - all.length);
						}
						return all;
					});
					return format;
				}
				return dateFormat(value, arg);
			})
			var vm = new Vue({
				el: '#app',
				data: {
					date: new Date()
				}
			});
		</script>
	</body>
</html>
综合案例
/*
		图书列表
			实现静态列表效果
      基于数据实现模板效果
      处理每行的操作按钮
      
    添加图书
    	实现表单的静态效果
    	添加图书表单域数据绑定
    	添加按钮事件绑定
			实现添加业务逻辑
			
		修改图书
			修改信息填充到表单
			修改后重新提交表单
			重用添加和修改的方法
			
		删除图书
			删除按钮绑定时间处理方法
			实现删除业务逻辑
*/	

常用特性应用场景

/*
		过滤器(格式化日期)
		自定义指令(获取表单焦点)
		计算属性(统计图书数量)
		侦听器(验证图书存在性)
		生命周期(图书数据处理)
*/

Example1

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Document</title>
		<style type="text/css">
			.grid {
				margin: auto;
				width: 530px;
				text-align: center;
			}

			.grid table {
				border-top: 1px solid #C2D89A;
				width: 100%;
				border-collapse: collapse;
			}

			.grid th,
			td {
				padding: 10;
				border: 1px dashed #F3DCAB;
				height: 35px;
				line-height: 35px;
			}

			.grid th {
				background-color: #F3DCAB;
			}

			.grid .book {
				padding-bottom: 10px;
				padding-top: 5px;
				background-color: #F3DCAB;
			}

			.grid .total {
				height: 30px;
				line-height: 30px;
				background-color: #F3DCAB;
				border-top: 1px solid #C2D89A;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<div class="grid">
				<div>
					<h1>图书管理</h1>
					<div class="book">
						<div>
							<label for="id">
								编号:
							</label>
							<input type="text" id="id" v-model='id' :disabled="flag" v-focus>
							<label for="name">
								名称:
							</label>
							<input type="text" id="name" v-model='name'>
							<button @click='handle' :disabled="submitFlag">提交</button>
						</div>
					</div>
				</div>
				<div class="total">
					<span>图书总数:</span>
					<span>{{total}}</span>
				</div>
				<table>
					<thead>
						<tr>
							<th>编号</th>
							<th>名称</th>
							<th>时间</th>
							<th>操作</th>
						</tr>
					</thead>
					<tbody>
						<tr :key='item.id' v-for='item in books'>
							<td>{{item.id}}</td>
							<td>{{item.name}}</td>
							<td>{{item.date | format('yyyy-MM-dd hh:mm:ss')}}</td>
							<td>
								<a href="" @click.prevent='toEdit(item.id)'>修改</a>
								<span>|</span>
								<a href="" @click.prevent='deleteBook(item.id)'>删除</a>
							</td>
						</tr>
					</tbody>
				</table>
			</div>
		</div>
		<script type="text/javascript" src="js/vue.js"></script>
		<script type="text/javascript">
			/*
      图书管理-添加图书
    */
			Vue.directive('focus', {
				inserted: function(el) {
					el.focus();
				}
			});

			Vue.filter('format', function(value, arg) {
				function dateFormat(date, format) {
					if (typeof date === "string") {
						var mts = date.match(/(\/Date\((\d+)\)\/)/);
						if (mts && mts.length >= 3) {
							date = parseInt(mts[2]);
						}
					}
					date = new Date(date);
					if (!date || date.toUTCString() == "Invalid Date") {
						return "";
					}
					var map = {
						"M": date.getMonth() + 1, //月份 
						"d": date.getDate(), //日 
						"h": date.getHours(), //小时 
						"m": date.getMinutes(), //分 
						"s": date.getSeconds(), //秒 
						"q": Math.floor((date.getMonth() + 3) / 3), //季度 
						"S": date.getMilliseconds() //毫秒 
					};
					format = format.replace(/([yMdhmsqS])+/g, function(all, t) {
						var v = map[t];
						if (v !== undefined) {
							if (all.length > 1) {
								v = '0' + v;
								v = v.substr(v.length - 2);
							}
							return v;
						} else if (t === 'y') {
							return (date.getFullYear() + '').substr(4 - all.length);
						}
						return all;
					});
					return format;
				}
				return dateFormat(value, arg);
			})
			var vm = new Vue({
				el: '#app',
				data: {
					flag: false,
					submitFlag: false,
					id: '',
					name: '',
					books: []
				},
				methods: {
					handle: function() {
						if (this.flag) {
							// 编辑图书
							// 就是根据当前的ID去更新数组中对应的数据
							this.books.some((item) => {
								if (item.id == this.id) {
									item.name = this.name;
									// 完成更新操作之后,需要终止循环
									return true;
								}
							});
							this.flag = false;
						} else {
							// 添加图书
							var book = {};
							book.id = this.id;
							book.name = this.name;
							book.date = 2525609975000;
							this.books.push(book);
							// 清空表单
							this.id = '';
							this.name = '';
						}
						// 清空表单
						this.id = '';
						this.name = '';
					},
					toEdit: function(id) {
						// 禁止修改ID
						this.flag = true;
						console.log(id)
						// 根据ID查询出要编辑的数据
						var book = this.books.filter(function(item) {
							return item.id == id;
						});
						console.log(book)
						// 把获取到的信息填充到表单
						this.id = book[0].id;
						this.name = book[0].name;
					},
					deleteBook: function(id) {
						// 删除图书
						// 根据id从数组中查找元素的索引
						// var index = this.books.findIndex(function(item){
						//   return item.id == id;
						// });
						// 根据索引删除数组元素
						// this.books.splice(index, 1);
						// -------------------------
						// 方法二:通过filter方法进行删除
						this.books = this.books.filter(function(item) {
							return item.id != id;
						});
					}
				},
				computed: {
					total: function() {
						// 计算图书的总数
						return this.books.length;
					}
				},
				watch: {
					name: function(val) {
						// 验证图书名称是否已经存在
						var flag = this.books.some(function(item) {
							return item.name == val;
						});
						if (flag) {
							// 图书名称存在
							this.submitFlag = true;
						} else {
							// 图书名称不存在
							this.submitFlag = false;
						}
					}
				},
				mounted: function() {
					// 该生命周期钩子函数被触发的时候,模板已经可以使用
					// 一般此时用于获取后台数据,然后把数据填充到模板
					var data = [{
						id: 1,
						name: '三国演义',
						date: 2525609975000
					}, {
						id: 2,
						name: '水浒传',
						date: 2525609975000
					}, {
						id: 3,
						name: '红楼梦',
						date: 2525609975000
					}, {
						id: 4,
						name: '西游记',
						date: 2525609975000
					}];
					this.books = data;
				}
			});
		</script>
	</body>
</html>
posted @ 2020-11-14 22:54  常见-youmen  阅读(433)  评论(0编辑  收藏  举报