当前位置: 代码迷 >> 综合 >> vue3.0新特性
  详细解决方案

vue3.0新特性

热度:148   发布时间:2023-09-13 11:14:53.0

vue3 新特性

1、初始化开发环境

// 安装 / 更新 vue-cli (保证版本在4.5.0以上)npm install -g @vue/cli// 创建
vue create vue3-basic// 然后选择 Manually select features (因为我们需要使用TS),进入界面后选择TS(按空格选择)// 然后选择Vue3, 后面都保持默认和选择 No

2、ref 的使用

在 vue3 的 script 中不再使用 data 和 methods ,而是使用 setup() 方法

ref, computed 等都是属于 composition API

<template><img alt="Vue logo" src="./assets/logo.png"><div>{
    {count}}</div>    <!-- 此处直接写 count 就能获取到值 --><div>{
    {double}}</div><button @click="increase">点击</button>
</template><script lang="ts">
import { ref, computed } from "vue";export default ({name: 'App',setup() {const count = ref(0)    // ref 接受一个参数,返回的是一个响应式对象const double = computed(() => {return count.value * 2})const increase = () => {count.value ++    // count是对象,这样才能获取到值}return {count,double,increase}}});
</script>

3、reactive 的使用

reactive 可以将需要导出的数据都包裹在一个对象中,而不是单独存在

<template><img alt="Vue logo" src="./assets/logo.png"><div>{
    {count}}</div>    <!-- 此处直接写 count 就能获取到值 --><div>{
    {double}}</div><button @click="increase">点击</button>
</template><script lang="ts">
import { computed, reactive, toRefs } from "vue";interface DataProps {   // 此处是为了解决 data 对象显示为 any 类型报错count: number;increase: () => void;double: number;
}export default ({name: 'App',setup() {const data: DataProps = reactive({    // reactive 是一个方法,接受一个对象count: 0,increase: () => {data.count ++},double: computed(() => {return data.count * 2})})// 如果仅仅将 data 进行展开会丧失响应式,所以用 toRefs把每一项都转化为响应式对象const refData = toRefs(data)    return {...refData    // 展开之后再模板中就不用写 data. 的前缀了}}});
</script>

同时, vue3 还支持直接新增 data 中的数据以及修改 data 中数组和对象的每一项,这样的修改也是响应式的。

4、生命周期钩子

在旧的 beforeCreate 钩子函数之后和 created 的钩子函数之前立即调用 setup 方法。因此,我们不再需要这两个钩子,我们可以简单地将本应有的代码放在 setup() 方法中。

此外,还有 9 个旧的生命周期函数可以在 setup() 中使用,使用前必须先导入

  • onBeforeMount
  • onMounted
  • onBeforeUpdate
  • onUpdated
  • onBeforeUnmount
  • onUnmounted
  • onActivated
  • onDeactivated
  • onErrorCaptured
// 例子import { onMounted, onUpdated } from 'vue'export default {setup() {onMounted(() => {// ... })onUpdated(() => {// ... })}
}

5、 Watch 侦听变化

import { watch } from 'vue'export default {setup() {// 1. 当监听的是 ref 返回的响应式对象watch(data, (newValue, oldValue) => {// ...})// 2. 当监听的是多个数据watch([data1, data2], (newValue, oldValue) => {// ...})// 3. 当监听的是多个对象,且包含 reactive 对象内的数据时watch([data1, () => data.data2], (newValue, oldValue) => {// ...})}
}

6、模块化

以下是两个例子:

鼠标追踪器

由于将代码都写入 setup() 会使代码过于冗余和复杂,故对多次需要使用的代码实现模块化

src / hooks / useMousePosition.ts

import { ref, onMounted, onUnmounted } from 'vue'function useMousePosition() {const x = ref(0)const y = ref(0)const updateMouse = (e: MouseEvent) => {x.value = e.pageXy.value = e.pageY}onMounted(() => {document.addEventListener('click', updateMouse)})onUnmounted(() => {document.removeEventListener('click', updateMouse)})return { x, y }
}export default useMousePosition;

使用

import { useMousePosition } from './hooks/useMousePosition.ts'export default {setup() {const { x, y } = useMousePosition()return {x,y}}
}

useURLLoader

import { reactive, toRefs } from 'vue'
import axios from 'axios'function useURLLoader(url: string) {const data = reactive({result: null,loadState: true,errInfo: null})axios.get(url).then((res) => {data.loadState = falsedata.result = res.data.message}).catch(e => {data.loadState = falsedata.errInfo = e})const refData = toRefs(data)return {...refData}
}export default useURLLoader

7、defineComponent 的使用

使用 defineComponent 能够让传入的对象获得类型以及能够获得自动提示

<script lang="ts">
import { defineComponent } from 'vue';export default defineComponent({name: 'HelloWorld',props: {msg: String,},setup(props, context) {...}
});
</script>

8、Teleport (瞬间移动) 组件的使用

有时在组件中需要用到弹窗时,将弹窗的代码全部写到层层嵌套的组件中,不太符合逻辑也不太方便查看。使用Teleport 能将组件的内容挂在到其他组件上

// 首先需要在父组件中引入该组件// 使用
<template><teleport to="#model">    <!-- 挂载到id为 model 的节点上 --><div>this is a model</div></teleport>
</template>// 挂载
// 在index.html中
<div id="model"></div>

9、 emits向父组件触发事件

// 例子
<template><teleport to="#model"><div v-if="isOpen"><div>this is a model</div><button @click="buttonClick">关闭</button></div></teleport>
</template><script>
import { defineComponent } from "vue";export default defineComponent({name: "Model",props: {isOpen: Boolean,},emits: {"close-modal": (payload: any) => {    // 进行类型的校验,没有就写 nullreturn payload.type === "close";},},setup(props, context) {const buttonClick = () => {context.emit("close-modal", {type: "hello",});};return {buttonClick}},
});
</script>

10、 Suspense 组件

  • 解决异步请求的困境
  • Suspense是Vue3推出的一个内置的特殊组件
  • 如果使用Suspense,要返回一个promise

使用Promise:

<template><div>{
    {result}}</div>     <!--返回后的结果可以直接使用 -->
</template><script>
import {defineComponent} from 'vue'export default defineComponent({setup() {return new Promise((resolve) => {       // 返回的必须是PromisesetTimeout(() => {return resolve({result: 10})},1000)})}
})
</script><!--在父组件中使用该组件 -->
<Suspense><template #default><AsyncTest /></template><!--当还没有请求到结果时显示 --><template #fallback><h1>loading!!!</h1></template>
</Suspense>

使用 async:

<template><div><img :src="result && result.message" alt="123" /></div>
</template><script>
import { defineComponent } from "vue";
import axios from "axios";export default defineComponent({async setup() {const rawData = await axios.get("https://www.example.com/"); // 测试使用return {result: rawData.data,};},
});
</script><!--在父组件中使用该组件同上面的 Promise -->

可以使用 onErrorCaptured() 生命周期函数监听网络请求的错误