Vue基础–Options API

hdc-web / 2025-02-18 / 原文

复杂data的处理方式

◼ 我们知道,在模板中可以直接通过插值语法显示一些data中的数据。
◼ 但是在某些情况,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示;
    比如我们需要对多个data数据进行运算、三元运算符来决定结果、数据进行某种转化后显示;
    在模板中使用表达式,可以非常方便的实现,但是设计它们的初衷是用于简单的运算;
    在模板中放入太多的逻辑会让模板过重和难以维护;
    并且如果多个地方都使用到,那么会有大量重复的代码;

例如:

    div id="app">
    <!-- 拼接名字 -->
    <!-- 方式一:使用插值语法表达式直接拼接-->
     <h2>姓名:{{firstName +" "+lastName}}</h2>
     <h2>{{firstName}}{{lastName}}</h2>
    <!-- 2.显示分数等级 -->
     <h2>{{score >=60?"及格":"不及格"}}</h2>
     <!--3.反转单词显示文本 -->
     <h2>{{message.split(" ").reverse().join()}}</h2>
    </div>
    <!-- 引入本地vue文件 -->
    <script src="./lib/vue.js"></script>
    <script>
      // 创建app
      const app = Vue.createApp({
        data(){
          return{
            // message:"Hello Vue"
            //1.姓名
            firstName:"Kobe",
            lastName:"bryant",
            // 2.分数:根据分数显示及格/不及格
            score:80,
            // 2.一串文本:对文本中的单词进行反转显示
            message:"my name is hdc"
          }
        },

      })
      // 挂载app
      app.mount("#app")
    ```
    ◼ 我们有没有什么方法可以将逻辑抽离出去呢?
        可以,其中一种方式就是将逻辑抽取到一个method中,放到methods的options中;
    例如:
      <div id="app">
    <!-- 拼接名字 -->
    <!-- 方式一:使用methods函数调用拼接-->
     <h2>姓名:{{getFullName()}}</h2>
     <h2>{{getFullName()}}</h2>
    <!-- 2.显示分数等级 -->
     <h2>{{scoreLevel()}}</h2>
     <!--3.反转单词显示文本 -->
     <h2>{{formartArr()}}</h2>
  </div>
  <!-- 引入本地vue文件 -->
  <script src="./lib/vue.js"></script>
  <script>
    // 创建app
    const app = Vue.createApp({
      data(){
        return{
          // message:"Hello Vue"
          //1.姓名
          firstName:"Kobe",
          lastName:"bryant",
          // 2.分数:根据分数显示及格/不及格
          score:80,
          // 2.一串文本:对文本中的单词进行反转显示
          message:"my name is hdc"
        }
      },
      methods:{
        getFullName(){
          return this.firstName +" "+this.lastName
        },
        scoreLevel(){
          if(this.score >=60){return "及格"}
          return "不及格"
        },
        formartArr(){
          return this.message.split(" ").reverse().join(" ")
        }
      }

    })
    // 挂载app
    app.mount("#app")
    但是,这种做法有一个直观的弊端,就是所有的data使用过程都会变成了一个方法的调用;
    另外一种方式就是使用计算属性computed;

认识计算属性computed

    <div id="app">
    <!-- 拼接名字 -->
    <!-- 方式一:使用methods函数调用拼接-->
     <h2>姓名:{{fullName}}</h2>
     <h2>{{fullName}}</h2>
    <!-- 2.显示分数等级 -->
     <h2>{{scoreLevel}}</h2>
     <!--3.反转单词显示文本 -->
     <h2>{{formatArr}}</h2>
  </div>
  <!-- 引入本地vue文件 -->
  <script src="./lib/vue.js"></script>
  <script>
    // 创建app
    const app = Vue.createApp({
      data(){
        return{
          // message:"Hello Vue"
          //1.姓名
          firstName:"Kobe",
          lastName:"bryant",
          // 2.分数:根据分数显示及格/不及格
          score:80,
          // 2.一串文本:对文本中的单词进行反转显示
          message:"my name is hdc"
        }
      },
      methods:{
      },
      computed:{
        // 计算属性默认对应的是一个函数
        fullName(){return this.firstName + " " + this.lastName},
        scoreLevel(){return this.score >= 60?"及格":"不及格"}, 
        formatArr(){return this.message.split(" ").reverse().join(" ")},
      }

    })
    // 挂载app
    app.mount("#app")

计算属性vsmethods


计算属性的缓存

计算属性的setter和getter

认识侦听器watch

    <div id="app">
    <h2>{{message}}</h2>
    <button @click="changeMessage">修改message</button>
  </div>
  <!-- 引入本地vue文件 -->
  <script src="./lib/vue.js"></script>
  <script>
    // 创建app
    const app = Vue.createApp({
      data(){
        return{
          message:"Hello Vue",
          info:{name:"hdc",age:21,height:1.88}
        }
      },
      methods:{
        changeMessage(){
          this.message = "你好啊!WEBKing",
          this.info={name:"kobe",age:30,height:1.98}
        }
      },
      watch:{
        // 可以传递两个参数:newValue/oldValue
        message(newValue,oldValue){
          console.log("message发生变化",newValue,oldValue)
        },
        // 对象类型拿到的都是proxy代理对象
        info(newValue,oldValue){
          console.log("info发生变化",newValue,oldValue)
          // 获取原始对象
          //方式一:展开运算符
          console.log({...newValue},{...oldValue})
          //Vue方法:toRaw()
          console.log(Vue.toRaw(newValue),Vue.toRaw(oldValue))
        }
      }
    })
    // 挂载app
    app.mount("#app")

侦听器watch的配置选项

◼ 我们先来看一个例子:
  <div id="app">
    <h2>{{info.name}}</h2>
    <button @click="changeInfo">更改info</button>
  </div>
  <!-- 引入本地vue文件 -->
  <script src="./lib/vue.js"></script>
  <script>
    // 创建app
    const app = Vue.createApp({
      data(){
        return{
          info:{name:"hdc",age:21}
        }
      },
      methods:{
        changeInfo(){
          // 创建一个新对象赋值给info
          // this.info = {name:"kobe"}
          // 2,直接修改原对象某一个属性
          this.info.name = "kobe"
        }
      },
      watch:{
        info(newValue,oldValue){
          console.log("侦听到info发生改变",newValue,oldValue)
        }
      }
    })
    // 挂载app
    app.mount("#app")
    当我们点击按钮的时候会修改info.name的值;
    这个时候我们使用watch来侦听info,可以侦听到吗?答案是不可以。
◼ 这是因为默认情况下,watch只是在侦听info的引用变化,对于内部属性的变化是不会做出响应的:
    但是template模板里面的内容是深度监听的;
    这个时候我们可以使用一个选项deep进行更深层的侦听;
    注意前面我们说过watch里面侦听的属性对应的也可以是一个Object;
◼ 还有另外一个属性,是希望一开始的就会立即执行一次:
    这个时候我们使用immediate选项;
    这个时候无论后面数据是否有变化,侦听的函数都会有限执行一次;
      watch:{
        // 默认watch监听不会进行深度监听的
        // info(newValue,oldValue){
        //   console.log("侦听到info发生改变",newValue,oldValue)
        // }
        // 进行深度监听
        info:{
          handler(newValue,oldValue){
            console.log("侦听到info发生改变",newValue,oldValue)
            // 没有改变info只是改变了info里的属性,所以他们两个是相等的
            console.log(newValue === oldValue)//true
          },
          // 深度监听
          deep:true,
          // 第一次渲染的时候就执行监听器
          immediate:true
          
        }
      }

侦听器watch的配置选项(代码)

侦听器watch的其他方式(一)

侦听器watch的其他方式(二)

◼ 另外一个是Vue3文档中没有提到的,但是Vue2文档中有提到的是侦听对象的属性:
```
  'info.name':function(newValue,oldValue){
      console.log(newValue,oldValue);
    }
```
◼ 还有另外一种方式就是使用$watch 的API:
◼ 我们可以在created的生命周期(后续会讲到)中,使用this.$watch 来侦听;
    第一个参数是要侦听的源;
    第二个参数是侦听的回调函数callback;
    第三个参数是额外的其他选项,比如deep、immediate;
```
  // 生命周期回调函数:当前的组件被创建时自动执行
  //一般在该函数中会进行网络请求
  created(){
    // this.message = []
    this.$watch("message",(newValue,oldValue)=>{
       console.log(newValue,oldValue)
    },{deep:true,immediate:true})
  }
})
```