模板语法

插值表达式

利用插值表达式来输出信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app">
<h1>
{{msg}}
</h1>
</div>

<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
msg:"hello Vue",
},
})
</script>

v-once 属性:

1
<h1 v-once>{{msg}}</h1>

v-once 是只渲染生成一次,此时如果在控制台更改 app.msg 的值则它并不会改变

插值表达式还支持简单运算:

字符串拼接:

1
<h1>{{firstname + lastname}}</h1>

运算:

1
<h1>{{1 + 2}}</h1>

输出结果就是 3 而不是 1 + 2

还支持三元运算:

1
<div>{{isVip?"VIP用户":"普通用户"}}</div>

isViptrue 则显示 VIP用户,反之则显示 普通用户

v-html

v-html 也可以用来输出信息,但是这么做并不推荐,因为不是怎么安全,可能会引发 XSS 问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app">
<div>{{htmlTxt}}</div>
<div v-html="htmlTxt"></div>
</div>

<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
htmlTxt:"<h1>hello</h1>"
},
})
</script>

v-bind 属性绑定

v-bind 是动态属性绑定,可以简写为一个冒号 :

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app">
<div v-bind:id="idName"></div>
<div :id="idName"></div>
</div>

<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
idName: "test"
},
})
</script>

这样就可以对属性就行修改。

v-on 事件绑定

v-on 是事件绑定,可以绑定监听事件,也可简写为 @

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="app">
<button type="button" v-on:click="changeBg">改变背景</button>
<button type="button" @click="changeBg">改变背景</button>
</div>

<script type="text/javascript">
var app = new Vue({
el:"#app",
methods: {
changeBg () {
document.body.style.background = "skyblue";
}
}
})
</script>

举个小例子,按钮每被点击一次,显示的数字就 +1 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="app">
<h1>点击次数:{{count}}</h1>
<button type="button" @click="count+=1">点击</button>
<button type="button" @click="clickEvent">点击</button>
</div>

<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
count: 0
},
methods:{
clickEvent () {
this.count++;
}
}
})
</script>

属性内可以使用简单表达式,所有两个按钮都可以修改 count 的数据

v-model 输入绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="app">
<input type="text" v-model="userName" />
<input type="text" @input="userName = $event.target.value" :value="userName" />

<h3>输入的内容: {{userName}}</h3>
</div>

<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
userName:"",
},
})
</script>

这两种方法都可以获取到输入框内的值,只不过被简化成了 v-model 指令了。

v-if 判断

例如:

1
2
3
4
5
6
7
8
9
10
11
12
<div id="app">
<img src="" v-if="isShow" />
</div>

<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
isShow: true
},
})
</script>

如果把 isShow 的值修改为 false 那么图片就不会显示。

v-for 列表渲染

循环渲染一个列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
<ul>
<li v-for="item in stars">
{{item}}
</li>
</ul>
</div>

<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
stars: ["蔡徐坤", "范冰冰", "李晨", "苏有朋"]
}
})
</script>

这就是一个简单的循环列表,但是这么做是不合理的,Vue 的建议是给列表的每一项加上独一无二的 key 值,循环对象数组:

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
<div id="app">
<ul>
<li v-for="(item,index) in students" :key="index">
<h4>学生姓名:{{item.name}}</h4>
<p>年龄:{{item.age}}------学校:{{item.school}}</p>
</li>
</ul>
</div>

<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
students: [{
name: "小明",
age: 18,
school: "北大",
touxiang: "http://pic1.zhimg.com/50/v2-deff985cfcb7690bc71fdf8676438146_hd.jpg"
}, {
name: "小红",
age: 17,
school: "清华"
}, {
name: "小白",
age: 20,
school: "北大"
}]
}
})
</script>

还是上面那个对象数组,进行循环对象:

1
2
3
<ul>
<li v-for="(item,index) in students[0]" :key="index">{{item}}</li>
</ul>

条件循环渲染:

1
2
3
4
5
6
<ul>
<li v-for="(item,index) in students" v-if="item.age%2==0" :key="index">
<h4>索引值:{{index}}------学生姓名:{{item.name}}</h4>
<p>年龄:{{item.age}}------学校:{{item.school}}</p>
</li>
</ul>

这里是先循环再进行判断,即使把 v-if 写在前面也是先循环再判断

常用的指令就这几个,更多和详细指令请参考官方文档:Vue 官方文档

侦听属性

示例:

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
<div id="app">
{{msg}}
<ul>
<li v-for="(item,index) in arr" :key="index">{{item}}</li>
</ul>
</div>

<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
msg:"hello Vue",
arr:["小红","小黑","小白"]
},
watch:{
msg (val) {
console.log("监听事件被触发---msg");
console.log(val);
},
arr (val) {
console.log("监听事件---arr");
console.log(val);
this.msg="监听到用户数据被修改"
}
}
})
</script>

arr 这个数组的值被修改时,比如增加一条数据时,监听事件 arr 被触发,然后这个事件修改了 this.msg 的值,然后也就触发了监听事件 msg

控制台输出

计算属性

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
<div id="app">
<h1>{{firstname+lastname}}</h1>
<h1>{{fullname}}</h1>

<!-- 逆序显示一个单词 -->
<h1>{{ word.split("").reverse().join("") }}</h1>
<!-- 性能优化。和上面那个例子类似 -->
<h1>{{reverseWord}}</h1>

<!-- 循环性能优化 -->
<ul>
<li v-for="(item,index) in oddStudents" :key="index">
<h2>{{item.name}}</h2>
<h2>{{item.age}}---{{item.school}}</h2>
</li>
</ul>

<!-- set和get属性 -->
<h1>{{msg}}</h1>
<h1>{{reverseMsg}}</h1>
</div>

<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
firstname:"张",
lastname:"三",
word:"music",
students: [{
name: "小明",
age: 18,
school: "北大"
}, {
name: "小红",
age: 17,
school: "清华"
}],
msg:"hello Vue"
},
computed:{
fullname () {
// 会将计算结果进行缓存
return this.firstname+this.lastname;
},
reverseWord () {
return this.word.split("").reverse().join("");
},
oddStudents () {
let results = this.students.filter((item,i)=>{
return item.age%2==0
});
return results;
},
reverseMsg:{
get () {
return this.msg.split("").reverse().join("");
},
set (val) {
console.log(val);
this.msg = val.split("").reverse().join("");
},
// get只能取值然后作用在其他地方,但是set可以设置值本身
}
},
})
</script>

那么在例子中 {{firstname+lastname}}{{fullname}} 有什么区别呢,因为在计算属性中,只要计算一次,就会将计算结果进行缓存,所以当这个数据需要大量显示的时候,我们可以使用计算属性来提高性能,就不用每显示一次就要进行计算一次。

循环优化的原理:在前面的例子中我们有一个条件循环偶数年龄的学生,我们先进行计算得出偶数学生的数组,就不用循环之后再进行判断,直接把偶数的对象先计算出来再使用,只循环需要的,而且它最大的优点就是可以先把计算结果先缓存下来,只要内容不改变他就可以直接拿来用,从而提高性能

事件传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="app">
<ul>
<li v-for="(item,index) in stars" @click="clickEvent(index,item,$event)" :key="index">索引值:{{index}}------内容:{{item}}</li>
</ul>
</div>

<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
stars: ["蔡徐坤", "范冰冰", "李晨", "苏有朋"],
},
methods:{
clickEvent (index,value,$event) {
console.log(index);
console.log(value);
console.log(event);
}
},
})
</script>

既能传入事件对象也能传入参数

输出

事件修饰符

1
2
3
<div @click="one">
<button type="button" @click.stop="two">点击</button>
</div>

事件修饰符 .stop 用来阻止冒泡事件,如果没有加修饰符的话,当点击事件 two 被触发时,事件 one 也会被触发,加上修饰符之后就不会了

1
2
3
4
<form method="post">
<input type="submit" value="提交1"/>
<input @click.prevent="" type="submit" value="提交2"/>
</form>

默认情况下点击 提交1 会有一个 POST 请求被提交,通过 .pervent 修饰符阻止默认行为

1
<button type="button" @click.once="">只触发一次点击</button>

.once 修饰符是只触发一次,第二次点击就没有效果了

1
<input type="text" @keydown.enter="search" value="回车" />

keydown 是按键绑定,监听键盘按键的动作

1
<input type="text" @keydown.enter.f1="search" value="回车和F1" />

同时绑定两个按键

1
<button type="button" @click.ctrl="ctrlEvent">按住Ctrl事件</button>

按住 Ctrl 键再点击按钮才会触发事件,但是如果按住 Ctrl 和其他键也会触发,就需要精确的只识别 Ctrl 键:

1
<button type="button" @click.ctrl.exact="ctrlEvent">按住Ctrl事件</button>
1
2
3
4
5
6
7
8
9
<script type="text/javascript">
Vue.config.keyCodes.f1 = 112
var app = new Vue({
el:"#app",
data:{

},
})
</script>

自定义按键修饰符

Class 与 Style 样式绑定

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
<style type="text/css">
.active {
background: skyblue;
}
.page {
height: 200px;
width: 200px;
}
</style>

<div id="app">
<div class="page" :class="{active:isTrue}"></div>
<!-- 通过对象的方式决定是否存在某个类 -->

<!-- 还可以直接放置对象: -->
<div class="page" :class="styleObj"></div>

<!-- 还可以直接放置数组 -->
<div class="page" :class="styleArr"></div>

<!-- 还可以放置字符串 -->
<div class="page" :class="styleStr"></div>

<!-- 数组和对象混合使用 -->
<div class="page" :class="styleArrObj"></div>
</div>

<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
isTrue:true,
styleObj:{active:true,test:true,"col-g-6":true},//可以写多个
styleArr:["col-xs-12","red-bg"],
styleStr:"abc cde efj",
styleArrObj:["abc",{active:true}]
}
})
</script>

内联样式

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
<div id="app">
<!-- CSS内联样式变量拼接 -->
<div style="width: 100px;height: 100px;background-color: skyblue;"
:style="{border: borderWidth+'px solid red',padding:paddingWidth+'px'}"></div>

<!-- CSS内联样式放置对象 -->
<div :style="styleObj"></div>

<!-- CSS数组的方式拼接 -->
<div :style="styleSrr"></div>
</div>

<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
borderWidth:10,
paddingWidth:30,
styleObj:{
width:"200px",
height:"300px",
"background-color":"skyblue"
},
styleSrr:[
{
width:"200px",
height:"300px",
"background-color":"skyblue"
},{
border:"5px solid yellow"
}
]
}
})
</script>

动态组件

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
<div id="app">
<div>
<component :is="com"></component>
</div>

<button @click="chooseContent(1)">首页</button>
<button @click="chooseContent(2)">列表</button>
<button @click="chooseContent(3)">新闻</button>
<button @click="chooseContent(4)">个人</button>
</div>

<script type="text/javascript">
// 创建组件
let com1 = Vue.component('index-com',{
name:'index', // 可以给组件定义名字,在is的值上使用
template:`<h1>首页内容</h1>`
})
let com2 = Vue.component('list-com',{
template:`<h1>列表内容</h1>`
})
let com3 = Vue.component('new-com',{
template:`<h1>新闻内容</h1>`
})
let com4 = Vue.component('me-com',{
template:`<h1>个人内容</h1>`
})

var app = new Vue({
el:"#app",
data:{
com:com1,
},
methods:{
chooseContent (id) { // 通过获取id来选择注册的组件
this.com = this.$options.components['com'+id]
}
},
// 注册组件
components:{
com1,com2,com3,com4
}
})
</script>

组件传值

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
<div id="app">
<ul>
<!-- 从父组件传值到子组件 -->
<product-com @choosproduct="chooseEvent" v-for="(item,index) in proList" :product="item" :key="'product'+index"></product-com>
</ul>
<h1>选择的产品是:{{chooseProduct}}</h1>
</div>

<script type="text/javascript">
// 产品组件
Vue.component("product-com",{
props:['product'], // 告知传入的数据从根组件过来
template:`<li>
<h3>产品名称:{{product.title}}</h3>
<h4>产品描述:{{product.brief}}</h4>
<p>产品价格:{{product.price}}</p>
<button @click="chooseEvent(product)">选择</button>
</li>`,
data () {
return {

}
},
methods:{
// 子组件向父组件传值必须有一个触发事件
chooseEvent (product) {
this.$emit("choosproduct",product)
}
}
})

// 根组件
var app = new Vue({
el:"#app",
data:{
proList:[
{
title:"产品1",
price:"10",
brief:"描述1"
},{
title:"产品2",
price:"20",
brief:"描述2"
}
],
chooseProduct:""
},
methods:{
chooseEvent (data) {
this.chooseProduct = data.title;
}
}
})
</script>

生命周期

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<div id="app">
<h1>{{msg}}</h1>
<div :class="className"></div>
<hello-com v-if="isShow"></hello-com>
<hello-com v-show="isShow"></hello-com>
</div>

<script type="text/javascript">
let helloCom = Vue.component("hello-com", {
template: "<div><h1>{{hello}}</h1> <button @click='changeData'>修改数据</button> </div>",
data: function() {
return {
hello: 'helloWorld'
}
},
methods:{
changeData () {
this.hello = "helloXiaoMing"
}
},
beforeCreate () {
console.log('brforeCreate')
// 此时数据data和事件方法methods还未绑定到app对象上
},
created() {
console.log('create')
// 数据和方法绑定到应用对象上
},
beforeMount() {
// 渲染之前,根据数据生成的DOM对象是获取不到的
console.log('brforeMount')
},
mounted() {
// 渲染之后,可以获取到生成的DOM对象
console.log('mounted')
},
beforeUpdate() {
console.log('beforeUpdate')
// 数据更改,但内容未更改之前
},
updated() {
console.log('update')
// 内容已经更新完毕
},
beforeDestroy() {
console.log('beforeDestory')
// 应用销毁之前
},
destroyed() {
console.log('destory')
// 应用销毁之后
},
})

var app = new Vue({
el: "#app",
data: {
msg: "helloVue",
className: "redBg",
isShow:true
},
components:{
'hello-com':helloCom
},
beforeCreate() {
console.log('brforeCreate')
// 此时数据data和事件方法methods还未绑定到app对象上
console.log(this)
console.log(this.msg)
},
created() {
console.log('create')
// 数据和方法绑定到应用对象上
console.log(this)
console.log(this.msg)
},
beforeMount() {
// 渲染之前,根据数据生成的DOM对象是获取不到的
console.log('brforeMount')
let dom = document.querySelector("redBg")
console.log(dom)
},
mounted() {
// 渲染之后,可以获取到生成的DOM对象
console.log('mounted')
let dom = document.querySelector("redBg")
console.log(dom)
},
beforeUpdate() {
console.log('beforeUpdate')
// 数据更改,但内容未更改之前
},
updated() {
console.log('update')
// 内容已经更新完毕
},
beforeDestroy() {
console.log('beforeDestory')
// 应用销毁之前
},
destroyed() {
console.log('destory')
// 应用销毁之后
},
methods: {
clickEvent () {

},
isShow () {
this.isShow = !this.isShow
}
}
})
</script>

就先到这里,,,