渲染、事件与绑定
请注意:由于该博客是基于vue
开发的,因此代码块中的插值表达式双大括号会被识别,为了将其显示,我们使用
1
{`{ 我是示例}`}
来展示插值表达式
一.引入
Vue
的官方文档:https://cn.vuejs.org
在Webstorm
中,只需要创建一个vue.js
项目即可,时间较长。如果创建完成,我们可以通过下列cmd
命令行来检测安装效果
1
2
3
4
5
6
7
8
9
10
npm run dev
返回内容:
VITE v5.3.5 ready in 335 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help
一个vue
文件的基本样式为:
1
2
3
4
5
6
<template>
</template>
<script>
</script>
由此我们可以写一个简单的HelloWorld
效果
1
2
3
4
5
6
7
8
9
10
11
12
<template>
<p>{`{message}`}</p>
</template>
<script>
export default {
data(){
return{
message:"Hello World",
}
}
}
</script>
如果我们想引入外部的vue
文件的内容,我们可以通过import
语句来实现引入。
1
2
3
4
5
6
<template>
<lesson1/>
</template>
<script setup>
import lesson1 from '../src/components/lesson1.vue'
</script>
上述代码中,import
语句实现了引入页面lesson1
的效果,但如果我们想要将其在页面中显示,则需要在模版中使用该变量,即<lesson1/>
二.模版与渲染
1.文本插值
在vue
中最基本的数据绑定形式就是文本插值,采用双大括号语法。值得注意的是,这种语法在Go
语言的gin
框架中也同样被使用。
在引入中的vue
代码示例中,我们通过``实现了文本插值,将其内部的message
参数与data()
函数内的键值对进行对应。
我们可以在插值内写入javascript
表达式,但请注意:每个绑定仅支持单一表达式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<p>{`{number+1}`}</p>
<p>{`{ok?'yes':'no'}`}</p>
<p>{`{array.split(',')}`}</p>
</template>
<script>
export default {
data(){
return{
number:20,
ok:true,
array:"1,2,3,4,5",
}
}
}
</script>
//输出结果
21
yes
[ "1", "2", "3", "4", "5" ]
如果我们要加入原生HTML
语句,并将其在页面中显示,我们直接使用``只会将原生HTML
语句按字符串输出,要想正常显示,我们需要v-html
语句。
1
2
3
4
5
6
7
8
9
10
11
12
<template>
<p v-html="rawHTML"></p>
</template>
<script>
export default {
data(){
return{
rawHTML:"<a href='https://outercyrex.github.io'>原生HTML</a>"
}
}
}
</script>
二者的区别就类似于javascript
中innerText
和innerHTML
的区别。
2.属性绑定
在vue
中,如果我们想更改一个标签的属性,并且是通过渲染模版的方式来更改的话,我们可以通过v-bind
进行绑定。
1
2
3
4
5
6
7
8
9
10
11
12
<template>
<p v-bind:class="class">我是box</p>
</template>
<script>
export default {
data(){
return{
class:"box",
}
}
}
</script>
其语法为v-bind : 属性名="键"
,且vue
为我们提供了一个语法糖,即v-bind
可以直接简写为:
1
<p :class="class">我是box</p>
上述代码是同样有效的。
这个值也可以是布尔值:
1
2
3
4
5
6
7
8
9
10
11
12
<template>
<button :disabled="isButtonDisabled">Button</button>
</template>
<script>
export default {
data(){
return{
isButtonDisabled:true,
}
}
}
</script>
如果传入的值是一个对象,我们可以使用v-bind
属性来将对象内的键值对按照属性-内容的形式展示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<p v-bind=obj>我是box</p>
</template>
<script>
export default {
data(){
return{
obj:{
class:"box",
id:"box1"
}
}
}
}
</script>
//输出结果
<p class="box" id="box1">我是box</p>
注意,如果键对应的值为null
或者undefine
,则该属性会直接被删除。
3.条件渲染
在vue
中,提供了条件渲染的途径,分别是v-if、v-else、v-else-if、v-show
。
条件渲染即在判断是否进行渲染的前提下,对特定的模版进行渲染。
1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<h3>条件渲染</h3>
<div v-if=flag>v-if测试</div>
</template>
<script>
export default {
data(){
return{
flag:false,
}
}
}
</script>
上述语句中,我们设置了v-if
的值为false
,则该标签不会被渲染,自然不会在页面中显现。
1
2
<div v-if=flag>v-if测试</div>
<div v-else>v-else测试</div>
其v-if、v-else、v-else-if
的语法和流程语句中的if、else、if-else
是一致的,如v-else
会寻找此前与其最接近的v-if
语句。
v-show
与v-if
效果相似,但存在以下的区别:
v-if
是真实的条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。
v-if
也是惰性的:如果在初次渲染时条件值为false
,则不会做任何事。条件区块只有当条件首次变为true
时才被渲染。
相比之下,v-show
简单许多,元素无论初始条件如何,始终会被渲染,只有CSS的display
属性会被切换。
4.列表渲染
列表渲染类似于for
循环,可以将一个数组的所有内容遍历并分别进行渲染。在vue
中,列表渲染使用的是v-for
属性。
其属性的内容为单项 in/of 数组
,注意此处使用in
或of
均可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<p v-for="name in names">{`{ name }`}</p>
</template>
<script>
export default {
data(){
return{
names:["Outer","Cyrex",1,2,3,4]
}
}
}
</script>
//输出效果
Outer
Cyrex
1
2
3
4
此外,v-for
也支持第二项来实现返回索引值。
1
2
3
4
5
6
7
8
9
<p v-for="(name,index) in names">{`{ name }`}——编号为</p>
//输出效果
Outer——编号为0
Cyrex——编号为1
1——编号为2
2——编号为3
3——编号为4
4——编号为5
除了遍历数组外,v-for
还可以遍历一个对象的所有属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<p v-for="(key,value) in names">{`{key}`} : {`{value}`}</p>
</template>
<script>
export default {
data(){
return{
names: {
name:"Outer",
age:19,
work:"backend",
}
}
}
}
</script>
//输出效果
Outer : name
19 : age
backend : work
这个过程中也可以加入第三项,其同样会被返回为index
即索引。
有一个重要的知识点是:vue
默认采取就地更新的策略来更新v-for
渲染的元素列表,即一旦有一个元素发生顺序上的变化,vue
会默认将列表内的所有元素均重新渲染,而非只改变对应的元素。
我们想要减少系统开支,只变化对应元素的顺序,便需要设置对应标签的key
属性
1
<p v-for="value in names" :key="index">{`{value}`}</p>
此处的:
仍然是v-bind:
的缩写。key
属性的内容要求是对应数据的唯一索引,如id
或index
等。
三.事件
1.事件处理
我们可以使用v-on
指令(简写为@
)来监听DOM
事件,并在事件触发时执行对应的javascript
语句。用法on:click="methodName"
或@click=handler"
。
事件监听器(处理器)可以是:
- 内联事件处理器:事件被触发时执行的内联
javascript
语句(与onclick
类似) - 方法事件处理器:一个指向组件上定义的方法的属性名或是路径
1
2
3
4
5
6
7
8
9
10
11
12
<template>
<button @click="count++">{`{count}`}</button>
</template>
<script>
export default {
data(){
return{
count:0
}
}
}
</script>
上述语句便是一个简单的内联事件处理器,可以发现内联事件处理器即在标签内直接写入处理事件的javascript
语句。
方法事件处理器则是通过索引<script>
代码块中对应的方法,来处理对应的事件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<button @click="addCount">{`{count}`}</button>
</template>
<script>
export default {
data(){
return{
count:0
}
},
methods:{
addCount(){
this.count++;
}
}
}
</script>
2.事件传参
事件参数可以获取event
对象和通过事件传输数据。
1
2
3
4
5
6
7
8
9
10
methods:{
addCount(e){
console.log(e.target)
this.count++;
}
}
//输出结果
<button>1</button>
<button>2</button>
...
由于vue
是javascript
的框架,其肯定支持javascript
原生的event
参数的各种属性,如target
等。
上述语句实现了event
的传参,接下来介绍事件传入一定的参数的处理方法。
1
2
3
4
5
6
7
8
9
<button @click="addCount('Hello')">{`{count}`}</button>
<script>
methods:{
addCount(msg){
console.log(msg)
this.count++;
}
}
</script>
如上述内容便传入了一个字符串给msg
参数,并将其输出在控制台中。
如果要同时传入event
参数和其他参数,可以将event
参数按照$event
的形式传参
1
2
3
4
5
6
7
8
9
10
<button @click="addCount('Hello',$event)">{`{count}`}</button>
<script>
methods:{
addCount(msg,e){
console.log(msg)
console.log(e.target)
this.count++;
}
}
</script>
此时我们也可以组合此前的v-for
等内容来实现批量的操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<button @click="output(item)" v-for="(item,index) of count" :key="index">{`{item}`}</button>
</template>
<script>
export default {
data(){
return{
count:[1,2,3,4,5,6,7,8,9,10]
}
},
methods:{
output(msg){
console.log(msg)
}
}
}
</script>
3.事件修饰符
在javascript
中,我们经常会调用event.preventDefault()
或event.stopPropagation
等方法来阻止默认方法或是停止冒泡。
在vue
中,存在许多事件修饰符来简化这些操作。
v-on
属性可以填入.stop、.prevent、once、enter
等事件修饰符来进行更改。
以event.preventDefault()
在vue
中的实现为例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<a @click.prevent="output" href="https://outercyrex.github.io">测试</a>
</template>
<script>
export default {
data(){
return{
count:[1,2,3,4,5,6,7,8,9,10]
}
},
methods:{
output(e){
<!-- e.preventDefault() -->
console.log(e.target)
}
}
}
</script>
我们当然可以通过event.preventDefault()
来实现,只是vue
为我们提供了.prevent
来简化这一步骤。
事件修饰符 | 作用 |
---|---|
.stop | 阻止事件冒泡,等同于event.stopPropagation() |
.prevent | 防止默认操作,等同于event.preventDefault() |
.self | 阻止事件继承,如某按钮内有多个子节点,则点击事件只对该按钮有效,对其子节点无效 |
.capture | 使用.capture 修饰符时,事件监听器会在捕获阶段被触发,即该事件比冒泡阶段的事件监听器更早地接收到事件 |
.once | 该事件只会触发一次 |
.passive | 对应事件的默认行为将立即发生而非等待对应函数完成 |
1
<div @scroll.passive="onScroll">...</div>
以上述代码为例,由于使用了.passive
修饰符,浏览器知道这个方法不会阻止滚动事件的默认行为,因此可以立即执行滚动操作,无需等待javascript
执行完成。
4.数组变化侦查
在javascript
中,存在多种数组方法,有些数组方法会变更原数组,也会影响v-for
的渲染效果,这些方法被称为变更方法,包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<button @click="output">增加数据</button>
<div v-for="(item) of count">{`{item}`}</div>
</template>
<script>
export default {
data(){
return{
count:[1,2,3,4,5,6,7,8,9,10]
}
},
methods:{
output(){
this.count.push(11)
}
}
}
</script>
上述所列举的数组方法均可实现实时更新。
另一部分方法则会创建一个新数组,并不会变更原数组,这些方法被称为替换方法,包括:
filter()
concat()
slice()
这些方法并不会变更原本的数组,而是返回一个新数组。
我们可以给原数组赋值为concat
返回的数组,也可以实现变更方法的效果。
1
2
3
4
5
6
methods:{
output(){
this.count = this.count.concat([11])
console.log(this.count)
}
}
四.计算属性
计算属性的定位类似于函数,用于处理重复且冗杂的代码块,将其单独处理为一个函数,便于调用和更改。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div v-for="item of count">{`{item}`}</div>
<p></p>
</template>
<script>
export default {
data(){
return{
count:[1,2,3,4,5,6,7,8,9,10]
}
},
computed:{
isEmpty:function(){
return this.count.length > 0 ? 'yes' : 'no'
}
}
}
</script>
在vue
中,计算属性都被放入computed
对象内,以函数的形式出现和调用。
注意,计算属性在被调用时,一定传出的是函数本身而不是其调用结果。
其与方法methods
的区别不仅如此,还在缓存上存在区别:
-
计算属性:计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。
-
方法:方法调用总是会在重渲染发生时再次执行函数。
简单而言,计算属性是静态的,其调用结果会被缓存,每次被调用时直接返回对应的结果,而不是重新计算。方法则是每次调用时都会再次执行。
五.特殊绑定
特殊绑定主要是针对class
属性和style
属性而言的。
1.class绑定
我们可以通过在class
的内容中添加限定,来管理class
属性的内容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div :class="{ 'active':isActive }">class绑定展示</div>
</template>
<script>
export default {
data(){
return{
isActive:true,
}
}
}
</script>
<style>
.active{
color:red;
}
</style>
上述代码中,'active'
是否是class
的内容取决于isActive
返回的布尔值。且该class
是可以被css
选择器选中的。
我们也可以通过多对象绑定来简化过程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div :class="classObj">class绑定展示</div>
</template>
<script>
export default {
data(){
return{
classObj:{
active:true,
danger:false,
}
}
}
}
</script>
如上述代码所示,我们直接传入了一个对象,则vue
会根据对应字段的布尔值来判断是否将该字段在class
内渲染。
我们也可以直接传入数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div :class="classObj">class绑定展示</div>
</template>
<script>
export default {
data(){
return{
classObj:['active','danger']
}
}
}
</script>
但数组是无法对应布尔值的,数组内的元素都会被渲染出来。
想对应布尔值便需要再数组内再写入对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div :class="[{active:isActive},danger]">class绑定展示</div>
</template>
<script>
export default {
data(){
return{
isActive:true,
danger:"error",
}
}
}
</script>
注意,一定是数组内写入对象,对象内是不能写入数组的。
2.style绑定
style绑定是针对内联style
属性而言的。其书写规范与class
绑定类似。
且注意,对应的css
属性一定要求是小驼峰命名法,否则就需要加''
,这一点与dom
中更改style
的规范是一致的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div :style="{color:isColor,fontSize:fontsize}">class绑定展示</div>
</template>
<script>
export default {
data(){
return{
isColor:"deepskyblue",
fontsize:'30px',
}
}
}
</script>
我们同样也可以之间传入一个对象即可。
1
2
3
4
5
6
return{
classBind:{
color:'deepskyblue',
fontSize:'30px'
}
}
3.表单输入绑定
在vue
中,我们可以通过v-model
来将表单的输入内容传入给某个变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<form>
<input type="text" v-model="message">
<p> {`{ message }`} </p>
</form>
</template>
<script>
export default {
data(){
return{
message:""
}
}
}
</script>
我们可以认为,v-bind
是单项绑定,而v-model
是双向绑定,将用户输入与对应参数绑定。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<form>
<input type="checkbox" v-model="message">{`{message}`}
</form>
</template>
<script>
export default {
data(){
return{
message:false
}
}
}
</script>
除此之外,表单输入绑定也支持各种修饰符,如.lazy、.number、.trim
修饰符 | 作用 |
---|---|
.lazy | 只有发生change 事件,如按回车等操作,才会传递参数 |
.number | 将表单传入的参数自动转换为数值类型 |
.trim | 去除用户输入末尾的空白字符,如空格 |
1
<input type="text" v-model.lazy="message">
4.模版绑定
如果我们想在vue
的<script>
内获取某个元素的dom
对象,我们便需要给对应的对象添加ref
属性
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
<template>
<div ref="container" class="container">{`{ Hello }`}</div>
<button @click="refDemo">显示</button>
</template>
<script>
export default {
data(){
return{
Hello:"Hello,World!"
}
},
methods:{
refDemo:function(){
console.log(this.$refs.container);
console.log(this.$refs.container.innerText);
}
}
}
</script>
<!-- 输出结果 -->
<div class="container">Hello,World!</div>
Hello,World!
通过$refs
检索获取的对象即是一个dom
节点,我们可以对其进行任何javascript
中的操作,如获取其innerHTML
等。
5.侦听器
我们可以对特定元素的更改进行侦听,检查其状态,判断其是否发生过变化。
主要是通过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
<template>
<div ref="container" class="container">{`{ Hello }`}</div>
<button @click="refDemo">显示</button>
</template>
<script>
export default {
data(){
return{
Hello:"Hello,World!"
}
},
methods:{
refDemo:function(){
this.Hello = "OuterCyrex"
// this.$refs.container.innerText = "OuterCyrex"
}
},
watch:{
Hello(newValue,oldValue){
console.log(`从${oldValue}变为了${newValue}`);
}
}
}
</script>
注意,该方法并不能监听dom
形式的更改,只能针对对应参数的更改。且其watch
内的函数名必须与对应参数的名字一致。
其实际上是检测参数在<script>
内的变化,因此dom
方法无效。