Appearance
Vue的配置选项和全局方法、实例方法
学习目标
- 【掌握】Vue中的双向绑定
- 【掌握】Vue的剩余指令
- 【掌握】Vue的常见配置选项
- 【掌握】Vue的常见全局方法
- 【掌握】Vue的常见实例方法
1. Vue中的双向绑定
1.1 什么是双向绑定?
我们现在应该了解,在Vue框架中data的数据会被绑定到视图模板中,一旦data数据改变,视图也会随之更新,在HTML中一类特殊的元素叫做表单元素,例如<input>
、<textarea>
及 <select>
,它们不仅可以展示数据,还可以输入数据,如果能够将输入的数据保存下来,那便实现了所谓的双向绑定。
1.2 v-model(用于双向绑定)
一起来学习这个指令如何应用在表单元素身上。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 通过v-model指令将msg实现了input的双向绑定 -->
<input type="text" v-model="msg" />
<p>{{msg}}</p>
<!-- 通过v-model指令将home实现了select的双向绑定 -->
你的家乡是
<select v-model="home">
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="武汉">武汉</option>
</select>
<p>{{home}}</p>
</div>
<script src="/vue.js"></script>
<script>
new Vue({
el: '#app',
data() {
return {
msg: '这是输入框的初始内容',
home: '武汉',
}
},
})
</script>
</body>
</html>
后面我们还会对表单的输入绑定做进一步深入学习,现在我们需要掌握v-model
指令的基本使用。
1.3 计算属性和侦听属性的深入
学习完了v-model
指令,我们对昨天学习过的2个重要配置选项来做进一步学习。
我们要完成一个姓名案例,在2个input框中分别输入姓和名,然后在第三个input中展示整体的姓名。利用计算属性能够很方便地实现:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
姓<input type="text" v-model="firstName" />
<br />
名<input type="text" v-model="lastName" />
<br />
姓名 <input type="text" v-model="fullName" />
</div>
<script src="/vue.js"></script>
<script>
new Vue({
el: '#app',
data() {
return {
firstName: '张',
lastName: '三',
}
},
computed: {
fullName() {
return this.firstName + this.lastName
},
},
})
</script>
</body>
</html>
同样地,利用侦听属性,我们也能实现它。
js
new Vue({
el: '#app',
data: {
firstName: '张',
lastName: '三',
fullName: '张三'
},
watch: {
firstName(val) {
this.fullName = val + ' ' + this.lastName
},
lastName (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
通过简单地比较,大家应该能够发现绝大多数情况下,计算属性的实现都比侦听属性实现起来更加简洁一些。
那是不是可以认为在这种场景下侦听属性就没存在的必要呢?并不是,现在把刚才的案例需求改变一下,要求在1S之后第三个input框中输出姓名,你会发现使用计算属性无法实现,因为计算属性必须依赖返回值来展示数据,在处理异步任务的情况下,只能使用侦听属性。
js
new Vue({
el: '#app',
data: {
firstName: '张',
lastName: '三',
fullName: '张三',
},
watch: {
firstName(val) {
setTimeout(() => { //这里的回调必须写成箭头函数的形式
this.fullName = val + ' ' + this.lastName
}, 1000);
},
lastName(val) {
setTimeout(() => {
this.fullName = this.firstName + ' ' + val
}, 1000);
},
},
})
这2个配置选项实在太重要了,我们还需要进一步补充,先来说侦听属性,继续来看上面的姓名案例,我们在设置fullName初始值的时候,手动地设置了'张三',如果设置默认值为空字符串地话,会怎么样呢?可能很多同学会认为侦听属性会计算出来的,大家可以尝试一下,你会发现视图上没有显示任何内容,这说明模板第一次加载的时候侦听属性是没有执行的,那有没有办法让侦听属性一开始加载的时候就执行一次呢?我们可以将侦听属性写成一个对象(完整写法),其中immediate
属性可以让handler
中的函数立即执行一次。默认情况下,immediate
会被设置为false,这也解释了为什么我们使用简写方式(即直接写成函数 其实就是指向了handler
)的时候姓名没有显示。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
姓<input type="text" v-model="firstName" />
<br />
名<input type="text" v-model="lastName" />
<br />
姓名 <input type="text" v-model="fullName" />
</div>
<script src="/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
firstName: '张',
lastName: '三',
fullName: '', //初始值为空的话 视图上不会显示姓名
},
watch: {
firstName: {
immediate: true,//侦听属性的完整写法是一个对象 其中immediate表示可以立即执行侦听的函数(hanlder)
handler(val) {
console.log(val)
this.fullName = val + ' ' + this.lastName
},
},
firstName: {
immediate: true,
handler(val) {
console.log(val)
this.fullName = this.firstName + ' ' + val
},
},
},
})
</script>
</body>
</html>
侦听属性中除开handler
和immediate
2个属性外,还有一个deep
属性,现在来介绍它:
来看下面这个示例,希望通过监听number这个数据源的变化来动态显示段落中的文字,此时number是一个有更深层级的对象,你会发现这时候的侦听似乎不起作用了,即是number.a发生变化,侦听函数并没有执行,有的同学可能会想那直接侦听number.a不就好了吗,但是如果number中有非常多的属性都需要侦听,那岂不是要写非常多的侦听函数吗?有没有一种办法仍然是侦听number这个对象,当它内部变化的时候仍然能够执行handler
呢?那就需要配置刚才介绍的deep
属性,默认情况下它的值为false
,需要手动地设置为true
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<p>{{msg}}</p>
<button @click="number.a++">{{number.a}}</button>
</div>
<script src="/vue.js"></script>
<script>
new Vue({
el:"#app",
data() {
return {
number:{
a:1,
},
msg:"偶数"
}
},
watch:{
number(){
if(this.number.a%2===0){
this.msg='偶数'
}else{
this.msg='奇数'
}
}
}
})
</script>
</body>
</html>
做出一些改进就能实现我们想要的效果了:
js
watch: {
number: {
immediate: true,
deep:true,
handler() {
if (this.number.a % 2 === 0) {
this.msg = '偶数'
} else {
this.msg = '奇数'
}
},
},
},
关于watch侦听属性这个配置选项就讲解完毕了,我们应该了解到大多数情况下,我们可以简写为一个函数,但如果我们希望handler
立刻执行,或者监听的数据是一个深层级的对象时,就需要写成对象形式了,然后正确地设置immediate
和deep
属性了。
再来深入探讨一下计算属性,沿用之前的姓名案例,现在希望在第三个input框的输入也能同步更改前2个input框的值,换个说法,计算属性是否可以手动更改呢?
其实也是可以的,之前我们的计算属性都是采用了简写方式,即只写了getter
,大部分情况下计算属性都是用来做展示,只需getter
即可,我们还可以手动添加setter
来完成刚刚的需求:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
姓<input type="text" v-model="firstName" />
<br />
名<input type="text" v-model="lastName" />
<br />
姓名 <input type="text" v-model="fullName" />
</div>
<script src="/vue.js"></script>
<script>
new Vue({
el: '#app',
data() {
return {
firstName: '张',
lastName: '三',
}
},
computed: {
fullName: {
get() {
return this.firstName + this.lastName
},
set(val) {//val即是设置的值
this.firstName = val.slice(0, 1)
this.lastName = val.slice(1)
},
},
},
})
</script>
</body>
</html>
2.Vue的其他指令
还有一些其他指令,它们的应用没有那么广泛,但我们仍需要了解,一起来看。
2.1 v-pre
Vue在编译视图模板中的插值和指令都需要耗费一定的性能,如果视图中部分区域中没有使用Vue的模板语法,可以通过使用v-pre
指令来跳过编译。
2.2 v-once
如果我们希望视图中的某个数据只在初次渲染时生效,可以使用v-once
命令,它会让随后的重新渲染中,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
2.3 v-slot
后面讲解插槽的时候会使用到这个指令。
3.Vue中的自定义指令
我们学习了Vue中提供了大量指令,但针对具体的业务场景,可能内置的这些指令还不够丰富,Vue同样提供了自定义指令,它是一个配置选项,开发者可以手动来实现具体指令。
例如我们希望编写一条指令,可以让加上指令的元素字体颜色变为红色。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 使用指令的时候必须以v-开头 -->
<h1 v-red>这是一个标题</h1>
</div>
<script src="/vue.js"></script>
<script>
new Vue({
el: '#app',
directives: {
red(el) {
//el表示指令绑定的DOM元素
el.style.color = 'red'
},
},
})
</script>
</body>
</html>
我们还可以进一步优化这个需求,希望让字体颜色变为data数据中指定的颜色。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 使用指令的时候必须以v-开头 -->
<h1 v-red="color">这是一个标题</h1>
</div>
<script src="/vue.js"></script>
<script>
new Vue({
el: '#app',
data() {
return {
color:'blue'
}
},
directives: {
red(el,binding) {
//el表示指令绑定的DOM元素
//binding.value表示指令后指定的值
el.style.color = binding.value
},
},
})
</script>
</body>
</html>
4.Vue中的过滤器
在Vue2版本中,还有一个配置选项filters
,可以实现对于数据的加工,不过在Vue3的最新版本中,这个语法已经被弃用被计算属性代替,不过考虑到Vue2版本仍然具有很大的市场份额,我们仍旧在此来讨论它。·
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 通过|toLower的形式实现对原始msg的"过滤作用" 支持链接写法 -->
{{msg|toLower}}
</div>
<script src="/vue.js"></script>
<script>
new Vue({
el:"#app",
data() {
return {
msg:'HELLO WOLRD'
}
},
filters:{
toLower(val){
//val 即为过滤前的原始数据 通过返回值的形式 返回过滤后的结果 和计算属性语法类似
return val.toLowerCase()
}
}
})
</script>
</body>
</html>
关于更多的配置选项,我们后面在接触到了组件学习后仍然会继续讨论。
5. Vue中的常见全局方法
现在我们来介绍一下Vue中的一批全局API的使用,通过之前的学习,我们应该了解到data中的数据是具有响应性的,只要数据一旦更改,模板中视图会立刻更新,我们现在的需求是这样的,示例中的data数据存放了一个person对象,里面包含了很多个人信息,现在希望在这个peoson对象做一些信息的修改,我们一起观测下是否能够实现响应性。
5.1 Vue.set
实现上面的需求,很多同学可能会这样书写代码:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<h1>{{person.name}}</h1>
<h1>{{person.name}}</h1>
<h1>{{person.age}}</h1>
<button @click="addHeight">点我增加身高信息</button>
<h1 v-if="person.height">{{person.height}}</h1>
</div>
<script src="/vue.js"></script>
<script>
new Vue({
el: '#app',
data() {
return {
person: {
name: '张三',
sex: '男',
age: 30,
},
}
},
methods: {
//按照之前的逻辑 很多同学可能会这么做 通过点击事件的回调 给person对象增加一个属性
addHeight() {
this.person.height = 180
},
},
})
</script>
</body>
</html>
但是在页面中大家会发现身高信息并没有被添加上去,似乎是哪里出了点问题,在Vue中如果希望能够给data中的数据实现响应式的增加不能直接操作,可以通过调用一个全局方法vue.set
的形式来实现,所以上面的代码应该这样改写:
js
methods: {
addHeight() {
// this.person.height = 180//不能直接通过对象操作来增加属性
Vue.set(this.person, 'height', 180)//三个参数分别为 数据对象 新增属性名 新增属性值
},
},
5.2 Vue.delete
在上面的示例中,如果希望删除person对象里的信息,也不能直接调用原始的操作方法,必须调用Vue.delete
这个全局方法来实现,比如给一个按钮绑定点击实现删除年龄信息,可以这样做:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<h1>{{person.name}}</h1>
<h1>{{person.sex}}</h1>
<h1>{{person.age}}</h1>
<button @click="deleteAge">点我删除年龄信息</button>
</div>
<script src="/vue.js"></script>
<script>
new Vue({
el: '#app',
data() {
return {
person: {
name: '张三',
sex: '男',
age: 30,
},
}
},
methods: {
deleteAge(){
Vue.delete(this.person,'age')
}
},
},
)
</script>
</body>
</html>
5.3 Vue.directive
自定义指令的配置选项写法同样可以通过全局方法来试下,我们之前写过的那个自定义指令还可以用Vue.directive
来实现:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 使用指令的时候必须以v-开头 -->
<h1 v-color="color">这是一个标题</h1>
</div>
<script src="/vue.js"></script>
<script>
Vue.directive('color', function (el, binding) {
//el表示指令绑定的DOM元素
//binding.value表示指令后指定的值
el.style.color = binding.value
})
new Vue({
el: '#app',
data() {
return {
color: 'blue',
}
},
})
</script>
</body>
</html>
5.4 Vue.filter
和自定义指令类似,过滤器也可以使用全局方法Vue.filter
来改写,这里的具体代码留给同学们自己来尝试完成。
6.Vue中的常见实例方法
我们刚才了解的以Vue开头的方法一般统称为全局方法,除此之外,Vue中还提供了一类方法叫做实例方法,那应该如何使用呢,一起来看看。
6.1 this.$set
我们之前一直访问的this指向的其实就是我们创建的Vue实例,所以我们当前描述的实例方法可以通过this来获取(也可以将实例化的Vue实例用变量保存起来,继而操作它。)
this.$set
的作用和刚刚介绍的全局方法Vue.set
几乎一致,所以刚才的示例还可以这样改写:
js
methods: {
addHeight() {
this.$set(this.person, 'height', 180)
},
},
6.2 this.$delete
通过方法名称不难猜到,这个实例方法this.$delete
同样对应刚才介绍的全局方法Vue.delete
,对应代码留给大家自己来实现。
6.3 vm.$watch
侦听属性的配置选项也可以改写为对应的实例方法。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
{{msg}}
<button @click="count++">{{count}}</button>
</div>
<script src="/vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data() {
return {
msg: '偶数',
count: 0,
}
},
})
//这里在配置选项外部访问实例 就不可以使用this 可以通过vm 来实现
vm.$watch('count', function (val) {
if (val % 2 === 0) {
vm.msg = '偶数'
} else {
vm.msg = '奇数'
}
})
</script>
</body>
</html>
随着后面的课程内容逐渐深入,我们还会学习到更多的全局方法和实例方法。