二、Vue基础语法 之 模板语法的深入学习
Lyk 2022/8/21 Vuemustache语法v-oncev-textv-htmlv-prev-cloakv-bindv-on条件渲染v-ifv-else-ifv-elsev-showv-for
# 1、设置VSCode代码片段
- 我们在前面练习Vue的过程中,有些代码片段是需要经常写的,我们再VSCode中我们可以生成一个代码片段,方便我们快速生成。
- VSCode中的代码片段有固定的格式,所以我们一般会借助于一个在线工具来完成。
- 具体的步骤如下:
- 第一步,复制自己需要生成代码片段的代码;
- 第二步,生成VSCode代码片段 (opens new window)在该网站中生成代码片段;
- 第三步,在VSCode中配置代码片段;
- 代码片段过程
# 2、模板语法
- React的开发模式:
- React使用的jsx,所以对应的代码都是编写的类似于js的一种语法;
- 之后通过Babel将jsx编译成 React.createElement 函数调用;
- Vue也支持jsx的开发模式(后续也会学习到):
- 但是大多数情况下,使用基于HTML的模板语法;
- 在模板中,允许开发者以声明式的方式将DOM和底层组件实例的数据绑定在一起;
- 在底层的实现中,Vue将模板编译成虚拟DOM渲染函数,后续会详细学习;
- 所以,对于学习Vue来说,学习模板语法是非常重要的。
# 3、Mustache双大括号语法(掌握)
- 如果我们希望把数据显示到模板(template)中,使用最多的语法是 “Mustache”语法 (双大括号) 的文本插值。
- 并且我们前端提到过,data返回的对象是有添加到Vue的响应式系统中;
- 当data中的数据发生改变时,对应的内容也会发生更新。
- 当然,Mustache中不仅仅可以是data中的属性,也可以是一个JavaScript的表达式。
<div id="app">
<!-- mustache基本使用 -->
<h2>{{ message }}</h2>
<!-- Javascript表达式 -->
<h2>{{ counter * 2 }}</h2>
<h2>{{ message.split(" ").reverse().join(" ") }}</h2>
<!-- 调用一个methods中的函数 -->
<h2>{{ reverse(message) }}</h2>
<h2>{{ reverse(message) }}</h2>
<!-- 使用计算属性 -->
<h2>{{reverseComp}}</h2>
<h2>{{reverseComp}}</h2>
<!-- 三元运算符 -->
<h2>{{ isFlag ? message : counter }}</h2>
<h2> {{name = "Hello Vue"}} </h2>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
message: "Hello Vue3",
counter: 20,
isFlag:false
}
},
computed:{
reverseComp() {
console.log('computed')
return this.message.split(" ").reverse().join("-")
}
},
methods:{
reverse(value) {
console.log('methods')
return value.split(" ").reverse().join(" ")
}
}
})
app.mount("#app")
</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
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
- 另外这些用法是错误的:
<div id="app">
<!-- 2.错误的写法 -->
<!-- 2.1这是一个赋值语句,不是表达式 -->
<h2> {{var name = "Hello Vue"}} </h2>
<!-- 2.2控制流的if语句也是不支持的, 可以使用三元运算符 -->
<h2>{{ if(true) { return message } }}</h2>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
message: "Hello Vue3",
counter: 20,
isFlag:false
}
},
methods:{
reverse(value) {
return value.split(" ").reverse().join(" ")
}
}
})
app.mount("#app")
</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
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
# 4、v-once指令(了解)
- v-once用于指定元素或者组件只渲染一次:
- 当数据发生变化时,元素或者组件以及其所有的子元素将视为静态内容并且跳过;
- 该指令可以用于性能优化;
- 如果是子节点,也是只会渲染一次
<div id="app">
<h2>{{message}}</h2>
<h2 v-once>{{message}}</h2><!-- 该元素只渲染一次 -->
<button @click="increment">切换名字</button>
<!-- 注:如果是子节点,也是只会渲染一次: -->
<div v-once>
<h2>当前计数:{{ counter }}</h2>
<button @click="increment1">+1</button>
</div>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
message:"kobe",
counter:0
}
},
methods: {
increment() {
this.message = "james"
},
increment1() {
this.counter++
}
}
})
app.mount("#app")
</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
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
# 5、v-text指令(了解)
- 用于更新元素的 textContent:
<div id="app">
<h2 v-text="message"></h2>
<!-- 等价于 -->
<h2>{{message}}</h2>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
message:"Hello Vue3"
}
}
}).mount("#app")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 6、v-html
- 默认情况下,如果我们展示的内容本身是 html 的,那么vue并不会对其进行特殊的解析。
- 如果我们希望这个内容被Vue可以解析出来,那么可以使用 v-html 来展示;
<div id="app">
<div v-html="info"></div>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
info:`<span style="color:red;font-size:30px">哈哈哈</span>`
}
}
}).mount("#app")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 7、v-pre
- v-pre用于跳过元素和它的子元素的编译过程,显示原始的Mustache标签:
- 跳过不需要编译的节点,加快编译的速度;
<div id="app">
<h2 v-pre>{{ message }}</h2> <!-- 浏览器显示:{{ message }}; vue会跳过该元素及子元素的编译过程-->
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
message:"Hello Vue3"
}
}
}).mount("#app")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 8、v-cloak
- 这个指令保持在元素上直到关联组件实例结束编译。
- 和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到组件实例准备完毕。
<style>
/* 使用v-cloak指令,需要结合CSS属性选择器使用 */
[v-cloak]{
display: none;
}
</style>
<div id="app">
<h2>{{ message }}</h2>
<h2 v-cloak>{{ message }}</h2>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
setTimeout(() => {
Vue.createApp({
data() {
return {
message: "Hello Vue3"
}
}
}).mount("#app")
}, 2000)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 9、v-memo
- v-memo指令,期望接收的是一个数组[valueA,valueB,...];
- 如果数组中valueA或valueB或...(设置的其他属性) 在操作之后值没有改变;则设置该指令的组件及子组件的所有更新都将被跳过;【但只要v-memo接收的数组中,有一个属性的值改变了,那么设置该指令的组件及子组件都会进行更新】
- 注意:使用
v-memo
和v-for
时,请确保它们用于同一元素。v-memo里面不行v-for。
- 注意:使用
<div id="app">
<!-- 如果没有改变name或age 则此组件及其子组件的所有更新都将被跳过
只要改变了name或age 其中一个;此组件及子组件将会进行更新 -->
<ul v-memo="[name,age]">
<li>{{ name }}</li>
<li>{{ age }}</li>
<li>{{ address }}</li>
</ul>
<hr>
<!-- 跟上面同理 -->
<ul v-memo="[item.name]" v-for="item in friends">
<h4>{{item.title}}</h4>
<li>{{item.name}}</li>
<li>{{item.age}}</li>
<li>{{item.address}}</li>
</ul>
<button @click="updateInfo">改变信息</button>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
message: "Hello Vue3",
name: "kobe",
age: 39,
address: "洛杉矶",
friends: [
{
title: "朋友1:",
name: "lyk",
age: 23,
address: "上海"
},
{
title: "朋友2:",
name: "james",
age: 29,
address: "洛杉矶"
}
]
}
},
methods: {
updateInfo() {
// this.name = "lyk"
this.age = 99
this.address = "中国"
this.friends[0].name = "kobe"
this.friends[0].age = 34
this.friends[0].address = '洛杉矶'
this.friends[1].age = 999
this.friends[1].address = '洛杉矶'
}
}
}).mount("#app")
</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
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
# 10、v-bind动态绑定
# 10.1.v-bind的绑定属性
- 前端讲的一系列指令,主要是将值插入到模板内容中。
- 但是,除了内容需要动态来决定外,某些属性我们也希望动态来绑定。
- 比如动态绑定a元素的href属性;
- 比如动态绑定img元素的src属性;
- 绑定属性我们使用v-bind:
- 缩写(语法糖):
:
- 预期:any (with argument) | Object (without argument)
- 参数:attrOrProp (optional)
- 修饰符:
- .camel - 将 kebab-case attribute 名转换为 camelCase。
- 用法:动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。
# 10.2.绑定基本属性
- v-bind用于绑定一个或多个属性值,或者向另一个组件传递props值(这个学到组件时再介绍);
- 在开发中,有哪些属性需要动态进行绑定呢?
- 还是有很多的,比如图片的链接src、网站的链接href、动态绑定一些类、样式等等
- v-bind有一个对应的语法糖,也就是简写方式。 v-bind的语法糖 为
:
符号 - 在开发中,我们通常会使用语法糖的形式,因为这样更加简洁。
<div id="app">
<!-- 完整的写法 -->
<img v-bind:src="imgUrl" alt="">
<a v-bind:href="url">跳转主页</a>
<!-- 语法糖写法 -->
<img :src="imgUrl" alt="">
<a :href="url">跳转主页</a>
<!-- 注意和上面的区别 -->
<img src="imgUrl" alt="" srcset="">
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
imgUrl: "http://81.68.143.219/img/common/logo.jpg",
url: "http://81.68.143.219"
}
}
}).mount("#app")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 10.3.绑定class介绍
- 在开发中,有时候我们的元素class也是动态的,比如:
- 当数据为某个状态时,字体显示红色。
- 当数据另一个状态时,字体显示黑色。
- 绑定class有两种方式:
- 对象语法
- 数组语法
# 10.4.绑定class – 对象语法
- 对象语法:我们可以传给 :class (v-bind:class 的简写) 一个对象,以动态地切换 class。
<h2 :class={ class类名: Boolean; ... }>标题</h2>
<style>
.active-color {
color: red
}
.class-name {
color: skyblue;
}
.title {
background-color: pink;
}
.title-font {
font-size: 30px;
}
</style>
<div id="app">
<!-- 1.普通的绑定方式 -->
<h2 :class="className">{{message}}</h2>
<!-- 2。对象绑定 -->
<!-- 动态绑定class是否加入:语法:{类名:boolean} -->
<h3 class="title-font" :class="{title:true, 'active-color':false}">你好,李银河</h3>
<!-- 3.案例练习 -->
<h4 :class="{'active-color':isActive}">6666</h4>
<button @click="toggle">切换</button>
<!-- 4.绑定对象 -->
<h4 :class="classObj">动态绑定对象</h4>
<!-- 5.从计算属性中获取 -->
<h4 :class="getCompClassObj">绑定计算属性,并从中获取</h4>
<!-- 6.从methods中获取 ; 注意:这里一定得加()哦 -->
<h4 :class="getMdClassObj()">绑定methods,并从中获取</h4>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
message: "Hello Vue3",
className: "class-name",
isActive: true,
classObj: {
'active-color': true,
title: true
}
}
},
computed: {
getCompClassObj() {
return {
'active-color': this.isActive,
title: true
}
}
},
methods: {
toggle() {
this.isActive = !this.isActive
},
getMdClassObj() {
return {
'active-color': this.isActive,
title: true
}
}
}
}).mount("#app")
</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
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
# 10.5.绑定class – 数组语法
- 数组语法:我们可以把一个数组传给 :class,以应用一个 class 列表
<style>
.class-name {
color: red;
}
.title-bg {
background-color: pink;
}
.title-font {
font-size: 30px;
}
</style>
<div id="app">
<!-- 1.直接传入一个数组 -->
<div :class="['title-bg', 'title-font']">直接传入一个数组</div> <hr>
<!-- 2.数组中也可以使用三元运算符或者绑定变量 -->
<div :class="['title-font', className, isTitleBg ? 'title-bg' : '']">数组中也可以使用三元运算符或者绑定变量</div> <hr>
<!-- 3.数组中也可以使用对象语法 -->
<div :class="['title-font', 'class-name', {'title-bg':isTitleBg}]">数组中也可以使用对象语法</div>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
className: "class-name",
isTitleBg: true
}
},
methods: {
message1(event) {
this.message = event.target.value
}
}
})
app.mount("#app")
</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
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
# 10.6.绑定style介绍
- 我们可以利用v-bind:style来绑定一些CSS内联样式:
- 这次因为某些样式我们需要根据数据动态来决定;
- 比如某段文字的颜色,大小等等;
- CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名;
# 绑定style有两种方式:
- 对象语法
<div id="app">
<!-- 1.基本使用:传入一个对象,并且对象内容都是确定的 -->
<div :style="{color:'red', fontSize:'30px', 'background-color': 'blue'}">基本使用:传入一个对象,并且对象内容都是确定的 </div><hr>
<!-- 2.变量数据:传入一个对象,值来自于data -->
<div :style="{color:'red', fontSize:size +'px', 'background-color': 'blue'}">变量数据:传入一个对象,值来自于data </div><hr>
<div :style="{color:'red', fontSize:sizeStr, backgroundColor: 'blue'}">变量数据:传入一个对象,值来自于data </div><hr>
<!-- 3. 对象数据:直接在data中定义好对象在这里使用-->
<div :style="styleObj">对象数据:直接在data中定义好对象在这里使用</div>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
size: 30,
sizeStr: "30px",
styleObj: {
color: 'red',
'font-size': '30px',
backgroundColor: 'blue'
}
}
}
}).mount("#app")
</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
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
- 数组语法
- :style 的数组语法可以将多个样式对象应用到同一个元素上;
<div id="app">
<!-- 1.将多个样式对象应用到同一个元素上; -->
<h2 :style="[styleObj,styleObj1,{paddingBottom:'30px'}]">将多个样式对象应用到同一个元素上</h2>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
styleObj: {
color: 'red',
'font-size': '30px',
backgroundColor: 'blue'
},
styleObj1: {
paddingTop:'30px'
}
}
}
}).mount("#app")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 10.7.动态绑定属性
- 在某些情况下,我们属性的名称可能也不是固定的:
- 前端我们无论绑定src、href、class、style,属性名称都是固定的;
- 如果属性名称不是固定的,我们可以使用
:[属性名]=“值”
的格式来定义; - 这种绑定的方式,我们称之为动态绑定属性;
<div id="app">
<!-- 这里动态绑定的属性名,浏览器会忽略大小写,解析成:attributename; 所以我们在data中应该这么去定义:attributename -->
<h2 :[attributeName]="{color:'red'}">{{message}}</h2>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
message: "Hello Vue3",
// attributeName:'style'
attributename: 'style'
}
}
}).mount("#app")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 10.8.绑定一个对象
- 如果我们希望将一个对象的所有属性,绑定到元素上的所有属性,应该怎么做呢?
- 非常简单,我们可以直接使用 v-bind 绑定一个 对象;
- 案例:info对象会被拆解成div的各个属性
<div id="app">
<input v-bind="info"> 同意协议
<input :="info"> 同意协议
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
info:{
type:'checkbox',
checked:true,
name:'agreement',
id:'agreement'
}
}
}
}).mount("#app")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 11、v-on绑定事件
# 11.1.v-on绑定事件
- 前面我们绑定了元素的内容和属性,在前端开发中另外一个非常重要的特性就是交互。
- 在前端开发中,我们需要经常和用户进行各种各样的交互:
- 这个时候,我们就必须监听用户发生的事件,比如点击、拖拽、键盘事件等等
- 在Vue中如何监听事件呢?使用v-on指令。
- 接下来我们来看一下v-on的用法:
# 11.2.v-on的用法
v-on的使用:
缩写(语法糖):@
预期:Function | Inline Statement | Object
参数:event
修饰符:
- .stop - 调用 event.stopPropagation()。
- .prevent - 调用 event.preventDefault()。
- .capture - 添加事件侦听器时使用 capture 模式。
- .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
- .{keyAlias} - 仅当事件是从特定键触发时才触发回调。
- .once - 只触发一次回调。
- .left - 只当点击鼠标左键时触发。
- .right - 只当点击鼠标右键时触发。
- .middle - 只当点击鼠标中键时触发。
- .passive - { passive: true } 模式添加侦听器
用法:绑定事件监听
# 11.3.v-on的基本使用
- 我们可以使用v-on来监听一下点击的事件:
- v-on:click可以写成@click,是它的语法糖写法:
- 当然,我们也可以绑定其他的事件:
- 如果我们希望一个元素绑定多个事件,这个时候可以传入一个对象:
- 具体如下:
<div id="app">
<h2>计数:{{counter}}</h2>
<!-- 1.绑定一个表达式 -->
<button v-on:click="counter++">+1</button>
<!-- 2.绑定到一个methods方法中 -->
<button v-on:click="btnClick">+1</button>
<!-- 2.2语法糖写法 -->
<button @click="btnClick">+1</button>
<!-- 3.绑定其他的事件:如:鼠标移动事件 -->
<h2>鼠标移入区域为:【{{message}}】</h2>
<div @mouseenter="mouseEnter" @mouseleave="mouseLeave" data-area="1"
style="width:260px;height:100px;background-color: red;">div区域1</div>
<!-- 4.绑定对象如果我们希望一个元素绑定多个事件,这个时候可以传入一个对象 -->
<div v-on="{mouseenter:mouseEnter,mouseleave:mouseLeave}" data-area="2"
style="width:260px;height:100px;background-color: pink;">div区域2</div>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
counter: 0,
message: "没有移入区域"
}
},
methods: {
btnClick() {
this.counter++
},
mouseEnter(event) {
this.message = `div区域${event.target.dataset.area}`
},
mouseLeave() {
this.message = '没有移入区域'
}
}
}).mount("#app")
</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
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
# 11.4.v-on参数传递
- 当通过methods中定义方法,以供@click调用时,需要注意参数问题:
- 情况【1.1】:如果该方法不需要额外参数,那么方法后的()可以不添加。
- 情况【1.2】:注意:如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去
- 情况【2】:如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件。
<div id="app">
<!-- 1.1默认会把event对象传入 -->
<button @click="btnClick1">点击按钮1</button>
<!-- 1.2注意:如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去 -->
<button @click="btnClick2(message)">点击按钮2</button>
<!-- 2.1内联语句传入其他参数 -->
<button @click="btnClick3(message,'lyk',$event)">点击按钮3</button>
</div>
<script src="../lib/vue.js"></script>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
message: "Hello Vue3"
}
},
methods: {
btnClick1(event) {//情况【1.1】:该方法的形参event可写可不写,该方法内部都可拿到event对象
console.log(event, event.target)
},
btnClick2(value) {//情况【1.2】:该方法的形参event可省略(如写了event形参,该方法内部将拿不到event对象)[如果想写,html元素绑定该方法,在传入其他参数的同时,必须传入$event这个参数;如下btnClick3为例]
console.log(value, event.target)
},
btnClick3(value1, value2, event) {//情况【2】:该方法的形参event可写可不写,该方法内部都可拿到event对象
console.log(value1, value2, event.target)
}
}
}).mount("#app")
</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
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
# 11.5.v-on的修饰符
- v-on支持修饰符,修饰符相当于对事件进行了一些特殊的处理:
- .stop - 调用 event.stopPropagation()。阻止事件进一步传递
- .prevent - 调用 event.preventDefault()。取消事件的默认行为
- .capture - 添加事件侦听器时使用 capture 模式。
- .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
- .{keyAlias} - 仅当事件是从特定键触发时才触发回调。
- .once - 只触发一次回调。
- .left - 只当点击鼠标左键时触发。
- .right - 只当点击鼠标右键时触发。
- .middle - 只当点击鼠标中键时触发。
- .passive - { passive: true } 模式添加侦听器
- 具体修饰符使用如下:
<div id="app">
<button @click.right="btnClick">按钮(请用鼠标右键点击按钮才生效哦)</button>
<!-- 取消了浏览器右键展示相关操作选项的默认行为 -->
<button @click.right.prevent="btnClick">按钮(请用鼠标右键点击按钮才生效哦)+取消默认行为</button>
<!-- 取消了a元素点击默认跳转行为-->
<a href="https://lyk19990226.github.io" @click.prevent>博客地址(取消了a元素的默认跳转行为)</a>
<div @click="btnClick1">
<button @click>按钮2(事件传递-冒泡)</button>
<button @click.stop>按钮3(阻止了事件传递)</button>
</div>
<button @click.once="btnClick">按钮4(该按钮事件只触发一次)</button>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
message: "Hello Vue3"
}
},
methods: {
btnClick() {
alert('你点击了按钮')
},
btnClick1() {
alert('事件传递(冒泡)')
}
}
}).mount("#app")
</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
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
# 12、条件渲染 v-if、v-else、v-else-if、
在某些情况下,我们需要根据当前的条件决定某些元素或组件是否渲染,这个时候我们就需要进行条件判断了。
Vue提供了下面的指令来进行条件判断:
- v-if
- v-else
- v-else-if
- v-show
v-if、v-else、v-else-if用于根据条件来渲染某一块的内容:
- 这些内容只有在条件为true时,DOM才会被渲染出来;
- 这三个指令与JavaScript的条件语句if、else、else if类似;
v-if的渲染原理:
- v-if是惰性的;
- 当条件为false时,其判断的内容完全不会被渲染或者会被销毁掉;
- 当条件为true时,才会真正渲染条件块中的内容;
<div id="app">
<div>
<label for="score">
请输入你的分数(0~100):<input type="text" id="score" v-model="score">
</label>
<h4 v-if="score>=90">优秀</h4>
<h4 v-else-if="score>=80">良好</h4>
<h4 v-else-if="score>=0">及格</h4>
<h4 v-else>不及格</h4>
</div>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
score: 80
}
}
}).mount("#app")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 13、template元素
- 因为v-if是一个指令,所以必须将其添加到一个元素上:
- 但是如果我们希望切换的是多个元素呢?
- 此时我们渲染div,但是我们并不希望div这种元素被渲染;
- 这个时候,我们可以选择使用template元素 -> [Vue3中新增的元素,vue2的版本不可使用];
- template元素可以当做不可见的包裹元素,并且在v-if上使用,但是最终template不会被渲染出来:
- 有点类似于小程序中的block
<div id="app">
<template v-if="isIf">
<h2>啊哈哈</h2>
<h2>啊哈哈</h2>
<h2>啊哈哈</h2>
</template>
<template v-else>
<h2>嘎嘎嘎嘎</h2>
<h2>嘎嘎嘎嘎</h2>
<h2>嘎嘎嘎嘎</h2>
</template>
<button @click="isIf = !isIf">切换</button>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
isIf: true
}
}
}).mount("#app")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 14、条件渲染v-show
- v-show和v-if的用法看起来是一致的,也是根据一个条件决定是否显示元素或者组件:
- 不同的是,v-show不管条件是否为true还是false;其对应的DOM都会被渲染处理;只不过是通过CSS的display属性来进行切换 展示跟隐藏的;
- 条件为true: -> 如果另外你有设置display属性则使用你设置的;如果没有设置则使用元素默认的display属性
- 条件为false: -> 设置内联样式:display:none;
- 不同的是,v-show不管条件是否为true还是false;其对应的DOM都会被渲染处理;只不过是通过CSS的display属性来进行切换 展示跟隐藏的;
<div id="app">
<button @click="isShow = !isShow">切换</button>
<h2 v-show="isShow">哈哈哈</h2>
<span v-show="isShow">呵呵呵</span>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
isShow: true
}
}
}).mount("#app")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 15、v-show和v-if的区别
- 首先,在用法上的区别:
- v-show是不支持template;
- v-show不可以和v-else一起使用;
- 其次,本质的区别:
- v-show元素无论是否需要显示到浏览器上,它的DOM实际都是有存在的,只是通过CSS的display属性来进行切换;
- v-if是惰性的,当条件为false时,其对应的原生压根不会被渲染到DOM中;只有条件为true时,其对应的原生才会被渲染到DOM中
- 开发中如何进行选择呢?
- 如果我们的原生需要在显示和隐藏之间频繁的切换,那么使用v-show;
- 如果不会频繁的发生切换,那么使用v-if;
# 16、v-for列表渲染
# 16.1.列表渲染
- 在真实开发中,我们往往会从服务器拿到一组数据,并且需要对其进行渲染。如下图情况:
- 这个时候我们可以使用v-for来完成;
- v-for类似于JavaScript的for循环,可以用于遍历一组数据;
# 16.2.v-for基本使用
- v-for的基本格式是 "item in 数组";
也可以这么写: ”item of 数组“
- 数组通常是来自data或者prop,也可以是其他方式;
- item是我们给每项元素起的一个别名,这个别名可以自定来定义;
- 我们知道,在遍历一个数组的时候会经常需要拿到数组的索引:
- 如果我们需要索引,可以使用格式: "(item, index) in 数组";
- 注意上面的顺序:数组元素项item是在前面的,索引项index是在后面的;
<div id="app">
<ul>
<h2>书籍列表</h2>
<li v-for="item in books">{{item}}</li><hr>
</ul>
<ul>
<h2>书籍列表</h2>
<li v-for="item of books">{{item}}</li><hr>
</ul>
<ul>
<h2>书籍列表</h2>
<li v-for="item,index in books">{{index}}-{{item}}</li><hr>
</ul>
<ul>
<h2>书籍列表</h2>
<li v-for="(item,index) in books">{{index}}-{{item}}</li><hr>
</ul>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
books: ["Javascript高级程序设计", "你不知道的JavaScript", "追风筝的人"]
}
}
}).mount("#app")
</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
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
# 16.3.v-for支持的类型
- v-for也支持遍历对象,并且支持有一二三个参数:
也可以这么写: ”item of 对象“
- 一个参数: "value in object";
- 二个参数: "(value, key) in object";
- 三个参数: "(value, key, index) in object";
- v-for同时也支持数字的遍历:
- 每一个item都是一个数字;
- v-for也可以遍历其他可迭代对象(Iterable)
<div id="app">
<ul>
<h2>个人信息</h2>
<li v-for="value in info">{{value}}</li>
</ul>
<ul>
<h2>个人信息</h2>
<li v-for="value,key of info">{{value}}-{{key}}</li>
</ul>
<ul>
<h2>个人信息</h2>
<li v-for="(value,key) in info">{{key}}-{{value}}</li>
</ul>
<ul>
<h2>个人信息</h2>
<li v-for="(value,key,index) in info">{{index}}-{{key}}-{{value}}</li>
</ul>
<ul>
<li v-for="item in 6">{{item}}</li>
</ul>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
info: {
name: 'kobe',
age: 44,
address: '洛杉矶'
}
}
}
}).mount("#app")
</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
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
# 16.4.template元素
- 类似于v-if,你可以使用 template 元素来循环渲染一段包含多个元素的内容:
- 我们使用template来对多个元素进行包裹,而不是使用div来完成;
<div id="app">
<template v-for="(value,key) in info">
<span>{{value}}</span> -
<span>{{key}}</span> /
</template>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
info: {
name: 'kobe',
age: 44,
address: '洛杉矶'
}
}
}
}).mount("#app")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 16.5.数组更新检测的一些方法
- Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。
- 即直接用 data函数返回的对象中 定义的数组;直接调用如下方法,也会触发视图更新
- 这些被包裹过的方法包括:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
- 替换数组的方法
- 上面的方法会直接修改原来的数组;
- 但是某些方法不会替换原来的数组,而是会生成新的数组,比如 filter()、concat() 和 slice()等;
<div id="app">
<button @click="pushClick">push</button><br>
<button @click="concatClick">concat</button>
<h2 v-for="item in names">{{item}}</h2>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
names: ['kobe', 'james']
}
},
methods: {
pushClick() {
this.names.push('rose', 'curry')//点击绑定该方法的按钮 可直接触发视图更新
},
concatClick() {
this.names.concat(['lyk', 'tatumu'])//点击绑定该方法的按钮 不会触发视图更新
// this.names = this.names.concat(['lyk','tatumu'])//得这么写,要进行赋值操作,就会触发视图更新
}
}
}).mount("#app")
</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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 16.6.v-for中的key是什么作用?
- 在使用v-for进行列表渲染时,我们通常会给元素或者组件绑定一个key属性。
- 这个key属性有什么作用呢?我们先来看一下官方的解释:
- key属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes;
- 如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法;
- 而使用key时,它会基于key的变化重新排列元素顺序,并且会移除/销毁key不存在的元素;
- 官方的解释对于初学者来说并不好理解,比如下面的问题:
- 什么是新旧nodes,什么是VNode?
- 没有key的时候,如何尝试修改和复用的?
- 有key的时候,如何基于key重新排列的?
<div id="app">
<h2 v-for="item in friends" :key="item.id">{{item.name}}</h2>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
friends: [
{
id: 1018409393,
name: 'kebe'
},
{
id: 1013986733,
name: 'james'
}
]
}
}
}).mount("#app")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 下面我们一起来探个究竟把
# 16.7.认识VNode - 虚拟节点
- 我们先来解释一下VNode的概念:
- 因为目前我们还没有比较完整的学习组件的概念,所以目前我们先理解HTML元素创建出来的VNode;
- VNode的全称是Virtual Node,也就是虚拟节点;
- 事实上,无论是组件还是元素,它们最终在Vue中表示出来的都是一个个VNode;
- VNode的本质是一个JavaScript的对象;如下图:
# 16.8.虚拟DOM
- 如果我们不只是一个简单的div,而是有一大堆的元素,那么它们应该会形成一个VNode Tree(虚拟DOM):
# 16.9.插入F的案例
- 我们先来看一个案例:这个案例是当我点击按钮时会在中间插入一个f;
- 我们可以确定的是,这次更新对于ul和button是不需要进行更新,需要更新的是我们li的列表:
- ➢ 在Vue中,对于相同父元素的子元素节点并不会重新渲染整个列表;
- ➢ 因为对于列表中 a、b、c、d它们都是没有变化的;
- ➢ 在操作真实DOM的时候,我们只需要在中间插入一个f的li即可;
- 那么Vue中对于列表的更新究竟是如何操作的呢?
- ➢ Vue事实上会对于有key和没有key会调用两个不同的方法;
- ➢ 有key,那么就使用 patchKeyedChildren方法;
- ➢ 没有key,那么久使用 patchUnkeyedChildren方法
# 16.10.Vue源码对于key的判断
# 16.11.没有key的操作(源码)
# 16.12.没有key的过程如下
- 我们会发现上面的diff算法效率并不高:
- c和d来说它们事实上并不需要有任何的改动;
- 但是因为我们的c被f所使用了,所有后续所有的内容都要一次进行改动,并且最后进行新增;
# 16.13.有key执行操作(源码)
# 16.14.有key的diff算法如下(一)
- 第一步的操作是从头开始进行遍历、比较:
- a和b是一致的会继续进行比较;
- c和f因为key不一致,所以就会break跳出循环;
- 第二步的操作是从尾部开始进行遍历、比较:
- 第三步是如果旧节点遍历完毕,但是依然有新的节点,那么就新增节点:
- 第四步是如果新的节点遍历完毕,但是依然有旧的节点,那么就移除旧节点:
- 第五步是最特色的情况,中间还有很多未知的或者乱序的节点:
- 所以我们可以发现,Vue在进行diff算法的时候,会尽量利用我们的key来进行优化操作:
- 在没有key的时候我们的效率是非常低效的;
- 在进行插入或者重置顺序的时候,保持相同的key可以让diff算法更加的高效;