Vue3教程 - 4 Vue3的API

更好的阅读体验:点这里www.foooor.com

4 Vue3的API

4.1 Vue2和Vue3的API风格

通过前面的 HelloWorld 程序,你如果学习过 Vue2,会发现 Vue3 的 API 和 Vue2 的区别很大。

Vue2 中的称为选项式 API (Options API):

vue 复制代码
<!-- Vue2 -->
<script>
export default {
  data() {  // 组件中用到的数据
    return {
      count: 0
    }
  },
  methods: {  // 组件中用到的方法
    increment() {
      this.count++
    }
  },
  watch:{},  // 监听器
  computed:{}  // 计算属性
}
</script>

组件中的 datamethodswatchcomputed 相当于一个个选项,选项式 API 可能会存在的问题是,一个功能的实现可能分布在多个选项中,不够集中,如果要修改就要分别修改多个选项,所以不易维护。

在 Vue3 中的称为组合式 API (Composition API),后面我们将以这种方式来学习,其实在 Vue3 中也是可以以选项式 API 来编程的,也就是 Vue3 是兼容 Vue2 的语法。

在 HelloWorld 中使用了 setup 选项,setup 选项的执行时机是很早的,比组件生命周期函数 beforeCreate 还要早(生命周期后面再讲),所以在 Vue2 的选项式 API 中是可以获取到 setup 返回的信息的,但是 setup 中无法获取 Vue2 选项中的数据。

举个栗子:

如果你有 Vue2 的基础,肯定能看得懂下面的代码;如果你没有 Vue2 的基础,也没有关系,这里是一个比较,后面我们还是以 Vue3 中的组合式 API 进行学习,但是老的项目肯定是 Vue2 的,如果有时间,可以多了解一些。

看一下下面的代码,在 Vue2 的选项式 API 中获取 Vue3 组合式 API 中的数据:

vue 复制代码
<template>
  <!-- 结构 -->
  <div class="my-app">
    <button @click="printMsg">打印msg</button>
  </div>
</template>

<script lang="ts">
  // 脚本
  export default {
    name: "App",
    methods: {
      printMsg() {
        console.log(this.msg);  // 通过this.name获取
      }
    },
    setup() {
      let msg = "Hello world";

      return {
        "msg": msg,
      }
    }
  }
</script>

4.2 setup

前面 HelloWorld 中已经使用了 setup, 它是 Vue3 中新的配置项,它的值是一个函数,在 Vue3 中,组件的数据、方法、计算属性、监视器等等,都配置在 setup 中。

setup 主要有以下特点,前面也介绍了几个:

  • setup 函数返回的对象,可以直接在<template>模板中使用;
  • setup 函数会在 beforeCreate 之前执行,也就是在所有的生命周期回调函数之前执行;
  • setup 函数中是没有 this 的,这个和 Vue2 中的有区别;

下面来实现一个功能,点击页面的按钮,计数+1。

代码如下:

vue 复制代码
<template>
  <!-- 结构 -->
  <div class="my-app">
    <div>{{ count }}</div>
    <button @click="increment">增加</button>
  </div>
</template>

<script lang="ts">
  import { ref } from 'vue'
  // 脚本
  export default {
    name: "App",
    setup() {
      // 响应式状态
      const count = ref(0)

      // 用来修改状态、触发更新的函数
      function increment() {
        count.value++
      }

      return {count, increment}
    }
  }
</script>

在上面的代码中:

  • const count = ref(0) 定义一个响应式变量 count,初始值为 0。count 实际上是一个对象,这个对象内部有一个.value属性,它持有实际的数值(在这个例子中是0)。
  • 在 setup 中将 countincrement() 函数返回,这样就可以在 HTML 模板中使用它们了。
  • 在模板中,通过差值表达式 {``{ count }} 读取到 count 的值,通过 @click 给元素绑定事件(后面再讲),当点击按钮时,调用 increment 函数,修改 count 的值,count 是响应式变量,修改 count 的值,页面会自动渲染。

通过上面的代码可以看到,使用响应式编程,我们不用去获取和操作 DOM 元素,只需要修改数据,就可以实现页面的自动渲染,和传统的前端开发相比,非常的方便。

4.3 setup语法糖

在前面使用 setup 的时候,需要将模板中使用的变量和方法返回,这样会很麻烦,因为不小心就忘掉了。

针对这种情况,可以使用 setup 语法糖。

需要单独使用一个 <script> 标签, 举个栗子:

vue 复制代码
<template>
  <!-- 结构 -->
  <div class="my-app">
    <div>{{ count }}</div>
    <button @click="increment">增加</button>
  </div>
</template>

<script lang="ts">
  // 脚本
  export default {
    name: "App"
  }
</script>

<!-- setup -->
<script lang="ts" setup>
import { ref } from 'vue'

// 响应式状态
const count = ref(0)

// 用来修改状态、触发更新的函数
function increment() {
  count.value++
}
</script>

在上面的代码中,只是将 setup 中的内容放到了一个新的 <script> 标签中,这个标签的类型需要和之前的类型一致 lang="ts" 并添加 setup 属性。setup 的 <script> 标签中变量和方法自动返回。

但是上面有两个 <script> 标签,显得很冗余啊,可以将第一个标签删掉:

vue 复制代码
<template>
  <!-- 结构 -->
  <div class="my-app">
    <div>{{ count }}</div>
    <button @click="increment">增加</button>
  </div>
</template>

<!-- setup -->
<script lang="ts" setup>
import { ref } from 'vue'

// 响应式状态
const count = ref(0)

// 用来修改状态、触发更新的函数
function increment() {
  count.value++
}
</script>

删掉以后,是可以正常工作的,但是删掉以后,组件的名称没有办法定义了,组件的名称默认就是文件的名称,也就是 App.vueApp 。正常情况下,这是没问题的。

但是非得要自定义名称,或者不同模块有相同的 .vue 文件,就会出现问题,导致组件名称相同,所以如何定义组件名称呢?

需要借助 vite-plugin-vue-setup-extend 插件,首先安装插件

bash 复制代码
# 安装插件
npm install -D vite-plugin-vue-setup-extend 

然后在项目的 vite.config.ts 文件中添加配置:

ts 复制代码
import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 1. 导入
import VueSetupExtend from 'vite-plugin-vue-setup-extend'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    // 2. 调用
    VueSetupExtend()
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

导入并调用插件。

最后在 <script> 标签上添加 name 属性:

vue 复制代码
<!-- setup -->
<script lang="ts" setup name="App123">
// ...略
</script>

通过浏览器开发者工具就可以看到组件的名称了:

4.4 ref

在 Vue2 中,只需要将数据放在 data(){} 中,就可以实现响应式数据。

在 Vue3 中需要使用 refreactive (待会再讲)来创建响应式数据。

使用 ref 来创建基本类型对象类型 的响应式数据,如果你想让哪个数据是响应式数据,使用 ref 包裹一下。

举个栗子:

创建基本类型的响应式数据。

vue 复制代码
<template>
    <div>{{ name }}</div>
    <div>{{ age }}</div>
    <div>{{ phoneNumber }}</div>
  
    <div>
      <button @click="changeName">修改姓名</button>
      <button @click="changeAge">修改年龄</button>
    </div>
  </template>
  
  <!-- setup -->
  <script lang="ts" setup>
  import { ref } from 'vue'
  
  let name = ref("doubi");  // 使用ref创建响应式数据
  let age = ref(13);  // 使用ref创建响应式数据
  let phoneNumber = "137xxxxxxxx";  // 不需要变化,则不需要ref
  
  // 修改姓名
  function changeName() {
    name.value = "niubi";
  }
  
  // 修改年龄
  function changeAge() {
    age.value = 14;
  }
  </script>

创建对象类型的响应式数据,一样的用法:

vue 复制代码
<template>
  <div> {{ person.name }} - {{ person.age }}</div>
  <div>
      <button @click="changePerson">修改Person</button>
  </div>
</template>

<!-- setup -->
<script lang="ts" setup>
import { ref } from 'vue'

// 对讲对象类型的响应式数据
let person = ref({"name": "doubi", "age": 13, "phoneNumber": "137xxxxxxxx"})

// 修改person
function changePerson() {
  person.value.name = "niubi"
  person.value.age = 15
}
</script>

在上面的代码中,使用 ref 创建响应式的数据,ref 将实际的数据包裹起来,实际变成了一个新的对象。

注意 :在代码中修改的时候,修改的是 变量.value 的值,但是在模板中引用的时候,引用的是变量的名称,不需要 .value

如果觉得每次首先 .value 很麻烦,可以通过插件自动添加。

点击 VSCode 左下角的设置按钮 -> 设置 -> 扩展 -> Vue -> Auto Insert:Dot Value

勾选配置后,每次写响应式扩展名,会自动补全 .value

4.5 reactive

reactive 只能用来定义对象类型(数组、函数等都是对象)的响应式数据。

用法和上面使用 ref 一样,将对象包裹起来就可以。

举个栗子:

vue 复制代码
<template>
  <div>{{ person.name }}</div>
  <div>{{ person.age }}</div>

  <div>
    <button @click="changeName">修改姓名</button>
    <button @click="changeAge">修改年龄</button>
  </div>
</template>

<!-- setup -->
<script lang="ts" setup>
import { reactive } from 'vue'  // 1.引入reactive

// 2.通过reactive定义响应式数据
let person = reactive({"name": "doubi", "age": 13})

// 修改姓名
function changeName() {
  person.name = "niubi"
}

// 修改年龄
function changeAge() {
  person.age = 14;
}
</script>

在上面的代码中,使用 reactive 将对象包裹起来,此时打印 person 变成了 Proxy 代理的对象。

其实 ref 在创建对象类型的响应式数据的时候,底层使用的也是 reactive

这样修改对象的数据,就可以让 Vue 重新渲染页面了。

在使用 reactive 的时候,有一个地方需要注意,就是重新分配一个新对象,会失去响应式。

举个栗子:

下面的 person 在创建的时候是响应式数据,如果重新给 person 赋值,会失去响应式。

vue 复制代码
<template>
  <div> {{ person.name }} - {{ person.age }}</div>
  <div>
    <button @click="changePerson">修改Person</button>
  </div>
</template>

<!-- setup -->
<script lang="ts" setup>
import { reactive } from 'vue'

// 对讲对象类型的响应式数据
let person = reactive({ "name": "doubi", "age": 13, "phoneNumber": "137xxxxxxxx" })

// 修改person
function changePerson() {
  // 页面不更新,不是响应式数据
  // person = {"name": "niubi", "age": 15, "phoneNumber": "137xxxxxxxx"}
  // 页面也不行,也是不可以的
  // person = reactive({"name": "niubi", "age": 15, "phoneNumber": "186xxxxxxxx"})

  // 需要单独修改person的属性,但是如果有很多的属性,依次赋值就很麻烦
  // person.name = "niubi"
  // 可以使用assign函数,将一个对象的属性赋值给另一个对象
  let newPerson = { "name": "niubi", "age": 15, "phoneNumber": "137xxxxxxxx" }
  Object.assign(person, newPerson)  // 将newPerson的属性赋值给person
}
</script>

所以需要使用 Object.assign 来进行属性赋值。

如果使用的是 ref ,就可以这个问题,应为直接是给 value 赋值:

vue 复制代码
// 使用ref,是给.value赋值,不是失去响应式
person.value = { "name": "niubi", "age": 15, "phoneNumber": "137xxxxxxxx" }

后面在创建响应式数据的时候,如果是基本数据类型,使用 ref,对象类型使用 refreactive 都可以。

4.6 toRefs和toRef

在 Vue 3 中,toRefstoRef 是两个用于响应式转换的 API,它们提供了将对象或对象的某个属性转换为响应式引用(refs)的方法。

1 toRefs

toRefs 用于将一个响应式对象的所有属性转换为响应式引用(refs),可以帮助我们解构响应式对象时保持其响应性。

举个例子,先查看一下下面的代码:

下面的代码将响应式对象 person 结构赋值给变量。

vue 复制代码
<template>
  <div> {{ person.name }} </div>
  <div> {{ person.age }} </div>

  <div> {{ name }} </div>
  <div> {{ age }} </div>

  <div>
    <button @click="changePerson">修改Person</button>
    <button @click="changeNameAndAge">修改name和age</button>
  </div>
</template>

<!-- setup -->
<script lang="ts" setup>
import { reactive } from 'vue'

// 对讲对象类型的响应式数据
let person = reactive({ "name": "doubi", "age": 13})

// 结构对象给变量赋值!!!
let {name, age} = person

// 修改person
function changePerson() {
  person.name = "niubi"
  person.age = 15
}

function changeNameAndAge() {
  name = "niubi"
  age = 15
}

</script>

此时 name 和 age 变量不是响应式变量了,修改 person 对象和修改变量本身,页面都不会有响应。

此时可以使用 toRefs,将结构的属性变成响应式变量。

举个栗子:

vue 复制代码
<template>
  <div> {{ person.name }} </div>
  <div> {{ person.age }} </div>

  <div> {{ name }} </div>
  <div> {{ age }} </div>

  <div>
    <button @click="changePerson">修改Person</button>
    <button @click="changeNameAndAge">修改name和age</button>
  </div>
</template>

<!-- setup -->
<script lang="ts" setup>
import { reactive, toRefs } from 'vue'

// 对讲对象类型的响应式数据
let person = reactive({ "name": "doubi", "age": 13})

// 结构对象给变量赋值
let {name, age} = toRefs(person)  // 转换为响应式变量

// 修改person
function changePerson() {
  person.name = "niubi"
  person.age = 15
}

function changeNameAndAge() {
  name.value = "niubi"  // 修改为.value
  age.value = 15
}

</script>

此时修改 person 对象还是 name 和 age 变量,person 的数据还是 name 和 age 变量都会同步变化。

通过 toRefs 的转换,不只是person对象,person 对象中的属性都变成了响应式对象

2 toRef

toRef 和 toRefs 功能是一样的,只是用来将对象的单个属性的响应式对象。

js 复制代码
// 将person对象的name属性转换为响应式对象
let name = toRef(person, "name") 

举个栗子:

vue 复制代码
<template>
  <div> {{ person.name }} </div>

  <div> {{ name }} </div>

  <div>
    <button @click="changePerson">修改Person</button>
    <button @click="changeNameAndAge">修改name和age</button>
  </div>
</template>

<!-- setup -->
<script lang="ts" setup>
import { reactive, toRef } from 'vue'

// 对讲对象类型的响应式数据
let person = reactive({ "name": "doubi", "age": 13})

// 将person对象的name属性转换为响应式对象
let name = toRef(person, "name")  

// 修改person
function changePerson() {
  person.name = "niubi"
}

function changeNameAndAge() {
  name.value = "niubi"  // 修改为.value
}

</script>

平时可能 toRefs 用的多一些

相关推荐
tester Jeffky3 分钟前
深入探索Vue.js中的class绑定:动态样式管理的核心机制
前端·javascript·vue.js
kk爱闹19 分钟前
弹窗组件嵌套弹窗组件问题
前端·javascript·vue.js
这可不简单19 分钟前
vue2 和 vue3 :关于keep-alive 使用的不同
前端·vue.js·vue
Benson叔19 分钟前
Vue3动态表单实现
前端·javascript·vue.js
lmxnsI21 分钟前
修改层级较深的数据导致页面没有实时渲染
vue.js·vue
雪芽蓝域zzs27 分钟前
Vue Web开发(十)
前端·javascript·vue.js
__十七35 分钟前
使用html2canvas库对可滚动的dom节点导出全量的图片
前端·javascript·vue.js·elementui
Cachel wood36 分钟前
Vue.js前端框架教程6:Element UI框架
前端·vue.js·git·elasticsearch·ui·前端框架
小码快撩43 分钟前
VUE的缓存问题
前端·vue.js·缓存
小彭努力中1 小时前
32.在 Vue 3 中上传 KML 文件并在地图上显示
前端·javascript·vue.js·深度学习·openlayers