文章

03.Vue2模板语法

03.Vue2模板语法

Vue 模板语法

什么是 Vue 模板语法

Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。

Vue.js 的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统。结合响应系统,在应用状态改变时, Vue 能够智能地计算出重新渲染组件的最小代价并应用到 DOM 操作上。

Vue 模板语法有 2 大类:

  • 插值表达式:用于解析标签体内容
  • 指令语法:用于解析标签(包括:标签属性、标签体内容、绑定事件…..)

插值表达式

写法:

1

,xxx 是 js 表达式,且可以直接读取到 data 中的所有属性。
功能:用于解析标签体内容。

文本

数据绑定最常见的形式就是使用(双大括号)的文本插值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
<script src="https://cdn.staticfile.org/vue/2.7.0/vue.min.js"></script>
</head>
<body>
<div id="app">
  <p></p>
</div>
<script>
new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue.js!'
  }
})
</script>
</body>
</html>

表达式

Vue.js 都提供了完全的 JavaScript 表达式支持。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - xxx</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
	{ {5+5} }<br>
	{ { ok ? 'YES' : 'NO' } }<br>
	{ { message.split('').reverse().join('') } }
	<div v-bind:id="'list-' + id">xxx</div>
</div>
	
<script>
new Vue({
  el: '#app',
  data: {
	ok: true,
    message: 'RUNOOB',
	id : 1
  }
})
</script>
</body>
</html>

reib1

data 数据

el 有两种写法

  • new Vue 时候配置 el 属性
  • 先创建 Vue 实例,随后再通过 vm.$mount('#选择器名') 指定 el 的值

data 两种写法

  • 对象式
  • 函数式:推荐用,后续要用到组件化只能用这种

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>el与data的两种写法</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
		data与el的2种写法
			1.el有2种写法
				(1).new Vue时候配置el属性。
				(2).先创建Vue实例,随后再通过vm.$mount('#root')指定el的值。
			2.data有2种写法
				(1).对象式
				(2).函数式
				如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。
			3.一个重要的原则:
				由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h1>你好,</h1>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		// el的两种写法
		// const v = new Vue({
		// 	// el: '#root',	// 第一种写法
		// 	data: {
		// 		name: '张三'
		// 	}
		// })

		// console.log(v);
		// v.$mount('#root')	// 第二种写法

		// data的两种写法
		new Vue({
			el: '#root',
			// data的第一种写法(对象式)
			// data: {
			// 	name: '张三'
			// }

			// data的第二种写法(函数式)

			// data: function() {
			data() {
				console.log("当前的", this);	// this指向的是Vue实例
				return {
					name: '张三'
				}
			}
		})
	</script>
</html>

methods 函数

method 每次调用都会执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

	new Vue({
		el: '#root',
		data: {
			name: '大圣课堂'
		},
		methods: {
			showInfo(e) {
				e.productionTip = false;	// 阻止默认事件, 这里表示阻止打开网址
				alert('同学你好!')
				console.log(e.target)
			},
			showMsg(msg) {
				console.log(msg)
			},
			demo() {
				for (let i = 0; i < 100000; i++) {
					console.log('---')
				}
				console.log('累坏了')
			}
		}
	})
</script>

computed 计算属性

  • 定义:要用的属性不存在,要通过已有属性计算得来。
  • 原理:底层借助了 Objcet.defineproperty 方法提供的 getter 和 setter。
  • get 函数什么时候执行?
    • 初次读取时会执行一次。
    • 当依赖的数据发生改变时会被再次调用。
  • 优势:与 methods 实现相比,内部有缓存机制(复用),效率更高,调试方便。
  • 备注:
    • 计算属性最终会出现在 vm 上,直接读取使用即可。
    • 如果计算属性要被修改,那必须写 set 函数去响应修改,且 set 中要引起计算时依赖的数据发生改变。
    • 引用时不用带 (),否则会被当做函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 计算属性,带缓存
computed: {
  // 计算属性的 getter
  outputContent: function () {
    // `this` 指向 vm 实例
    console.log("call, outputContent!")
    	return "Hello World Vue, outputContent!"
    }
}

// 调用多次,只有第1次会调用
<p>计算属性 </p>
<p> </p>
<p> </p>

computed setter 和 getter

computed 属性默认只有 getter ,不过在需要时你也可以提供一个 setter :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>姓名案例_计算属性实现</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			计算属性:
				1.定义:要用的属性不存在,要通过已有属性计算得来。
				2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
				3.get函数什么时候执行?
					(1).初次读取时会执行一次。
					(2).当依赖的数据发生改变时会被再次调用。
				4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
				5.备注:
					1.计算属性最终会出现在vm上,直接读取使用即可。
					2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
		 -->
		<!-- 准备好一个容器-->
		<div id="root">
			姓:<input type="text" v-model="firstName"> <br/><br/>
			名:<input type="text" v-model="lastName"> <br/><br/>
			测试:<input type="text" v-model="x"> <br/><br/>
			全名:<span></span> <br/><br/>
			<!-- 全名:<span></span> <br/><br/>
			全名:<span></span> <br/><br/>
			全名:<span></span> -->
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		const vm = new Vue({
			el:'#root',
			data:{
				firstName:'',
				lastName:'',
				x:'你好'
			},
			methods: {
				demo(){
					
				}
			},
			computed:{
				fullName:{
					//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
					//get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
					get(){
						console.log('get被调用了')
						// console.log(this) //此处的this是vm
						return this.firstName + '-' + this.lastName
					},
					//set什么时候调用? 当fullName被修改时。
					set(value){
						console.log('set',value)
						const arr = value.split('-')
						this.firstName = arr[0]
						this.lastName = arr[1]
					}
				}
			}
		})
	</script>
</html>

只有 get 函数,只读不改时才能用简写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>姓名案例_计算属性实现</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			姓:<input type="text" v-model="firstName"> <br/><br/>
			名:<input type="text" v-model="lastName"> <br/><br/>
			全名:<span></span> <br/><br/>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		const vm = new Vue({
			el:'#root',
			data:{
				firstName:'',
				lastName:'',
			},
			computed:{
				//完整写法
				/* fullName:{
					get(){
						console.log('get被调用了')
						return this.firstName + '-' + this.lastName
					},
					set(value){
						console.log('set',value)
						const arr = value.split('-')
						this.firstName = arr[0]
						this.lastName = arr[1]
					}
				} */
				//简写,只有get函数,只读不改时才能用简写
				fullName(){
					console.log('get被调用了')
					return this.firstName + '-' + this.lastName
				}
			}
		})
	</script>
</html>

computed vs methods

可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。

watch 侦听属性

watch 基本

监视属性 watch:

  • 当被监视的属性变化时, 回调函数自动调用, 进行相关操作
  • 监视的属性必须存在,才能进行监视!!
  • 监视的两种写法:
    • new Vue 时传入 watch 配置
    • 通过 vm.$watch 监视

示例:watch 变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8" />
	<title>天气案例_监视属性</title>
	<!-- 引入Vue -->
	<script type="text/javascript" src="../js/vue.js"></script>
</head>

<body>
	<!-- 
		监视属性watch:
			1.当被监视的属性变化时, 回调函数自动调用, 进行相关操作
			2.监视的属性必须存在,才能进行监视!!
			3.监视的两种写法:
					(1).new Vue时传入watch配置
					(2).通过vm.$watch监视
		 -->
	<!-- 准备好一个容器-->
	<div id="root">
		<h2>今天天气很</h2>
		<button @click="changeWeather">切换天气</button>
	</div>
</body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

	const vm = new Vue({
		el: '#root',
		data: {
			isHot: true,
		},
		computed: {
			info() {
				return this.isHot ? '炎热' : '凉爽'
			}
		},
		methods: {
			changeWeather() {
				this.isHot = !this.isHot
			}
		},
		watch: {
			isHot: {
				immediate: true, //初始化时让handler调用一下
				//handler什么时候调用?当isHot发生改变时。
				handler(newValue, oldValue) {
					console.log('isHot被修改了, new=%s, old=%s', newValue, oldValue)
				}
			}
		}
	})

	// vm.$watch('isHot', {
	// 	immediate: true, //初始化时让handler调用一下
	// 	// handler什么时候调用?当isHot发生改变时。
	// 	// 参数是新值和旧值
	// 	handler(newValue, oldValue) {
	// 		console.log('isHot被修改了, new=%s, old=%s', newValue, oldValue)
	// 	}
	// })
</script>

</html>

通过 watch 来响应数据的变化

1
2
3
4
5
6
// 侦听器
watch: {
    message: function (newValue, oldValue) {
        console.log("watch newValue: " + newValue + ", oldValue: " + oldValue)
    }
},

深度监视

  • Vue 中的 watch 默认不监测对象内部值的改变(一层)。
  • 配置 deep:true 可以监测对象内部值改变(多层)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8" />
	<title>天气案例_深度监视</title>
	<!-- 引入Vue -->
	<script type="text/javascript" src="../js/vue.js"></script>
</head>

<body>
	<!-- 
		深度监视:
				(1).Vue中的watch默认不监测对象内部值的改变(一层)。
				(2).配置deep:true可以监测对象内部值改变(多层)。
		备注:
				(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
				(2).使用watch时根据数据的具体结构,决定是否采用深度监视。
		 -->
	<!-- 准备好一个容器-->
	<div id="root">
		<h2>今天天气很</h2>
		<button @click="changeWeather">切换天气</button>
		<hr />
		<h3>a的值是:</h3>
		<button @click="numbers.a++">点我让a+1</button>
		<h3>b的值是:</h3>
		<button @click="numbers.b++">点我让b+1</button>
		<button @click="numbers = {a:666,b:888}">彻底替换掉numbers</button>
		
	</div>
</body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

	const vm = new Vue({
		el: '#root',
		data: {
			isHot: true,
			numbers: {
				a: 1,
				b: 1,
				c: {
					d: {
						e: 100
					}
				}
			}
		},
		computed: {
			info() {
				return this.isHot ? '炎热' : '凉爽'
			}
		},
		methods: {
			changeWeather() {
				this.isHot = !this.isHot
			}
		},
		watch: {
			isHot: {
				// immediate:true, //初始化时让handler调用一下
				//handler什么时候调用?当isHot发生改变时。
				handler(newValue, oldValue) {
					console.log('isHot被修改了', newValue, oldValue)
				}
			},
			//监视多级结构中某个属性的变化
			/* 'numbers.a':{
				handler(){
					console.log('a被改变了')
				}
			} */
			//监视多级结构中所有属性的变化
			numbers: {
				// deep:false, // 默认不监测对象内部值的改变(一层)
				// deep:true, // 配置deep:true可以监测对象内部值改变(多层)
				deep: true,
				handler() {
					console.log('numbers改变了')
				}
			}
		}
	})
</script>

</html>

watch 简写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>天气案例_监视属性_简写</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>今天天气很</h2>
			<button @click="changeWeather">切换天气</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		const vm = new Vue({
			el:'#root',
			data:{
				isHot:true,
			},
			computed:{
				info(){
					return this.isHot ? '炎热' : '凉爽'
				}
			},
			methods: {
				changeWeather(){
					this.isHot = !this.isHot
				}
			},
			watch:{
				//正常写法
				/* isHot:{
					// immediate:true, //初始化时让handler调用一下
					// deep:true,//深度监视
					handler(newValue,oldValue){
						console.log('isHot被修改了',newValue,oldValue)
					}
				}, */
				//简写,如果只有handler,可以直接写成函数,不能写成箭头函数,不能使用immediate和deep
				/* isHot(newValue,oldValue){
					console.log('isHot被修改了',newValue,oldValue,this)
				} */
			}
		})

		//正常写法
		/* vm.$watch('isHot',{
			immediate:true, //初始化时让handler调用一下
			deep:true,//深度监视
			handler(newValue,oldValue){
				console.log('isHot被修改了',newValue,oldValue)
			}
		}) */

		//简写,如果只有handler,可以直接写成函数,不能写成箭头函数,不能使用immediate和deep
		/* vm.$watch('isHot',(newValue,oldValue)=>{
			console.log('isHot被修改了',newValue,oldValue,this)
		}) */

	</script>
</html>

computed 和 watch 之间的区别

  1. computed 能完成的功能,watch 都可以完成
  2. watch 能完成的功能,computed 不一定能完成,例如:watch 可以进行异步操作

两个重要的小原则:

  1. 所有被 Vue 管理的函数,最好写成普通函数,这样 this 的指向才是 vm 或 组件实例对象,不要写箭头函数 (=>),否则 this 是 windows。
  2. 所有不被 Vue 所管理的函数(定时器的回调函数、ajax 的回调函数等、Promise 的回调函数),最好写成箭头函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8" />
	<title>姓名案例_watch实现</title>
	<!-- 引入Vue -->
	<script type="text/javascript" src="../js/vue.js"></script>
</head>

<body>
	<!-- 
			computed和watch之间的区别:
				1.computed能完成的功能,watch都可以完成。
				2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
			两个重要的小原则:
				1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
				2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,
					这样this的指向才是vm 或 组件实例对象。
		-->
	<!-- 准备好一个容器-->
	<div id="root">
		姓:<input type="text" v-model="firstName"> <br /><br />
		名:<input type="text" v-model="lastName"> <br /><br />
		全名:<span></span> <br /><br />
		全名2:<span></span> <br /><br />
	</div>
</body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

	const vm = new Vue({
		el: '#root',
		data: {
			firstName: '',
			lastName: '',
			fullName: '张-三'
		},
		watch: {
			firstName(val) {
				setTimeout(() => {
					console.log('firstName被修改了%s', val)
					this.fullName = val + '-' + this.lastName
				}, 1000);
			},
			lastName(val) {
				console.log('lastName被修改了%s', val)
				this.fullName = this.firstName + '-' + val
			}
		}
	})
</script>

</html>

filters 过滤器

filters 定义

Vue.js 允许你自定义过滤器,被用作一些常见的文本格式化。
过滤器可以用在两个地方:双花括号插值v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由 “管道”符号(|) 指示:

1
2
3
4
5
<!-- 在两个大括号中 -->
{ { message | capitalize } }

<!-- 在 v-bind 指令中 -->
<div v-bind:id="rawId | formatId"></div>

注意 :并没有改变原本的数据, 是产生新的对应的数据

局部 filters

1
2
3
4
5
6
7
filters: {
  capitalize: function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}

全局 filters

在创建 Vue 实例之前全局定义过滤器:

1
2
3
4
5
6
7
8
9
Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

new Vue({
  // ...
})

当全局过滤器和局部过滤器重名时,会采用局部过滤器。

filters

  • 过滤器函数接受表达式的值作为第一个参数。

示例:对输入的字符串第一个字母转为大写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Filters</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
  </head>
  <body>
    <div id="app">
      { { message | capitalize } }
    </div>

    <script>
      new Vue({
        el: '#app',
        data: {
          message: 'hacket'
        },
        filters: {
          capitalize: function (value) {
            if (!value) return ''
            value = value.toString()
            return value.charAt(0).toUpperCase() + value.slice(1)
          }
        }
      })
    </script>
  </body>
</html>
  • 过滤器可以串联:
1
{ { message | filterA | filterB } }
  • 过滤器是 JavaScript 函数,因此可以接受参数:
1
2
{ { message | filterA('arg1', arg2) } }
    <!-- message 是第一个参数,字符串 'arg1' 将传给过滤器作为第二个参数, arg2 表达式的值将被求值然后传给过滤器作为第三个参数。 -->
本文由作者按照 CC BY 4.0 进行授权