Skip to content
On this page

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>

侦听属性中除开handlerimmediate2个属性外,还有一个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立刻执行,或者监听的数据是一个深层级的对象时,就需要写成对象形式了,然后正确地设置immediatedeep属性了。

再来深入探讨一下计算属性,沿用之前的姓名案例,现在希望在第三个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>

随着后面的课程内容逐渐深入,我们还会学习到更多的全局方法和实例方法。

版权声明 鄂ICP备2022000216号-2