Vue3:新特性详解

news2024/11/25 13:10:13

本文目录:

  • 1.特性函数setup
  • 2.Ref 语法
  • 3.Reactive 函数
  • 4.Vue3 生命周期
  • 5.侦测变化 - watch
  • 6.Vue3的模块化开发
  • 7.弹窗类组件优化:Teleport
  • 8.异步组件优化:Suspense
  • 9.全局API优化

1.特性函数setup

1、setup函数是处于 生命周期函数 beforeCreate 和 Created 两个钩子函数之间的函数 也就说在 setup函数中是无法 使用 data 和 methods 中的数据和方法的
2、setup函数是 Composition API(组合API)的入口
3、在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用

setup第一个参数props会自动推论成props里面定义的类型
第二个参数context,在setup中无法直接访问vue2最常用的this对象,context提供了vue2中最常用的三个属性
context.attrs
context.slots
context.emit

2.Ref 语法

ref 是一个函数,它接受一个参数,返回的就是一个神奇的 响应式对象 。我们初始化的这个 0 作为参数包裹到这个对象中去,在未来可以检测到改变并作出对应的相应。

<template>
  <h1>{{count}}</h1>
  <h1>{{double}}</h1>
  <button @click="increase">+1</button>
</template>
import { ref } from "vue"
setup() {
  const count = ref(0)
  const double = computed(() => {
    return count.value * 2
  })
  const increase = () => {
    count.value++
  }
  return {
    count,
    increase,
    double
  }
}

3.Reactive 函数

reactive的用法与ref的用法相似,也是将数据变成响应式数据,当数据发生变化时UI也会自动更新。不同的是ref用于基本数据类型,而reactive是用于复杂数据类型,比如对象和数组

import { ref, computed, reactive, toRefs } from 'vue'

interface DataProps {
  count: number;
  double: number;
  increase: () => void;
}

setup() {
  const data: DataProps  = reactive({
    count: 0,
    increase: () => { data.count++},
    double: computed(() => data.count * 2)
  })
  const refData = toRefs(data)
  return {
    ...refData
  }
}

使用 ref 还是 reactive 可以选择这样的准则
第一,就像刚才的原生 javascript 的代码一样,像你平常写普通的 js 代码选择原始类型和对象类型一样来选择是使用 ref 还是 reactive。
第二,所有场景都使用 reactive,但是要记得使用 toRefs 保证 reactive 对象属性保持响应性。

4.Vue3 生命周期

在vue3中,生命周期在hook中的变化

  • beforeCreate -> 不需要
  • created -> 不需要
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeUnmount -> onBeforeUnmount
  • unmounted -> onUnmounted
  • errorCaptured -> onErrorCaptured
  • renderTracked -> onRenderTracked
  • renderTriggered -> onRenderTriggered

为了更好的Tree-shaking,Vue3的生命周期函数都是从 vue 中导入,再进行直接调用
从 vue 中引入 多个生命周期函数

import {onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, unMounted} from 'vue'
export default {
  name: 'App',
  setup() {
    onBeforeMount(() => {
      // 在挂载前执行
    })
    onMounted(() => {
      // 在挂载后执行
    })
    onBeforeUpdate(() => {
      // 在更新前前执行
    })
    onUpdated(() => {
      // 在更新后执行
    })
    onBeforeUnmount(() => {
      // 在组件销毁前执行
    })
    unMounted(() => {
      // 在组件销毁后执行
    })
    return {}
  }
}

onErrorCaptured可以捕捉错误,同时捕捉错误需要返回一个布尔值,表示错误是否向上传播

import { onErrorCaptured } from 'vue'
setup(){
  const error = ref(null)
  onErrorCaptured ((e:any)=>{
    error.value = e
    return true
  })
}

5.侦测变化 - watch

watch的第一个参数是一个响应式的对象,如果要监听多个对象,则第一个参数也可以是一个数组
watch 多个值,返回的也是多个值的数组

watch([greetings, data], (newValue, oldValue) => {
  console.log('old', oldValue)
  console.log('new', newValue)
  document.title = 'updated' + greetings.value + data.count
})

如果是打算监听data中的一个属性,比如data.count,则不能直接去watch([greetings, data.count]这样写,而是要使用 getter 的写法 watch reactive 对象中的一项

watch([greetings, () => data.count], (newValue, oldValue) => {
  console.log('old', oldValue)
  console.log('new', newValue)
  document.title = 'updated' + greetings.value + data.count
})

6.Vue3的模块化开发

使用composition API 的好处

  • 将相关的逻辑代码组合在一起,不要分散在代码的各个地方
  • 可以非常容易的重用代码,比mixin有更高的灵活度

实践:记录鼠标的位置
利用vue3进行初步的实现,将所有的代码都写在setup中

const x = ref(0)
const y = ref(0)
const updateMouse = (e: MouseEvent) => {
  x.value = e.pageX
  y.value = e.pageY
}
onMounted(() => {
  document.addEventListener('click', updateMouse)
})
onUnmounted(() => {
  document.removeEventListener('click', updateMouse)
})

但是上方的代码还不能做到很方便的重用,所以接下来需要对代码进行改造,将组件内逻辑抽象成可复用的函数
新建一个文件hooks文件夹,里面就存放我们抽离出来的所有的逻辑模块,新建一个useMousePosition.ts

import { ref, onMounted, onUnmounted } from 'vue'
function useMouseTracker() {
  // const positions = reactive<MousePostion>({
  //   x: 0,
  //   y: 0
  // })
  const x = ref(0)
  const y = ref(0)
  const updatePosition = (event: MouseEvent) => {
    x.value = event.clientX
    y.value = event.clientY 
  }
  onMounted(() => {
    document.addEventListener('click', updatePosition)
  })
  onUnmounted(() => {
    document.removeEventListener('click', updatePosition)
  })
  return { x, y }
}
export default useMouseTracker

在需要使用这个逻辑的页面进行引用

import useMousePosition from './hooks/useMousePosition'

这里引用到的就是一段函数代码,然后调用函数,取其返回值就可以了

const { x, y } = useMousePosition()

vue3 这种实现方式的优点

  • 第一:它可以清楚的知道 xy 这两个值的来源,这两个参数是干什么的,他们来自 useMouseTracker 的返回,那么它们就是用来追踪鼠标位置的值。
  • 第二:我们可以xy 可以设置任何别名,这样就避免了命名冲突的风险。
  • 第三:这段逻辑可以脱离组件存在,因为它本来就和组件的实现没有任何关系,我们不需要添加任何组件实现相应的功能。只有逻辑代码在里面,不需要模版。

将请求接口的逻辑抽离出去:

import { ref } from 'vue'
import axios from 'axios'
// 添加一个参数作为要使用的 地址
const useURLLoader = (url: string) => {
// 声明几个ref,代表不同的状态和结果
  const result = ref(null)
  const loading = ref(true)
  const loaded = ref(false)
  const error = ref(null)
// 发送异步请求,获得data
// 由于 axios 都有定义,所以rawData 可以轻松知道其类型
  axios.get(url).then((rawData) => {
    loading.value = false
    loaded.value = true
    result.value = rawData.data
  }).catch((e) => {
    error.value = e
  })
  // 将这些ref 一一返回
  return {
    result,
    loading,
    error,
    loaded
  }
}
export default useURLLoader

在要使用接口的页面进行引用:

const { result, loading, loaded } = useURLLoader('https://dog.ceo/api/breeds/image/random')
...
<h1 v-if="loading">Loading!...</h1>
<img v-if="loaded" :src="result.message" >

模块化结合typescript - 泛型改造:

function useURLLoader<T>(url: string) {
  const result = ref<T | null>(null)

在应用中的使用,可以定义不同的数据类型

// 在应用中的使用,可以定义不同的数据类型
interface DogResult {
  message: string;
  status: string;
}
interface CatResult {
  id: string;
  url: string;
  width: number;
  height: number;
}
const { result, loading, loaded } = useURLLoader<CatResult[]>('https://api.thecatapi.com/v1/images/search?limit=1')

组件的定义和导出的都是一个普通的object

const component = {
  name: 'HelloWorld',
  props: {
    ...
  }
}

export default component;

而普通的对象在书写代码的时候自然不会获得ts的提示支持,vue3提供了defineComponent来让普通的object变为支持ts的对象

const component = 
  defineComponent({
    name: 'HelloWorld',
    props: {
      ...
    }
})

export default component;

7.弹窗类组件优化:Teleport

Vue2在弹窗组件开发中,Dialog被包裹在其他组件之中,容易被干扰,样式也在其他组件中,容易变得非常混乱。
vue3 新添加了一个默认的组件就叫 Teleport,我们可以拿过来直接使用,它上面有一个 to 的属性,它接受一个css query selector 作为参数,这就是代表要把这个组件渲染到哪个 dom 元素中

<template>
  <teleport to="#modal">
    <div id="center">
      <h1>this is a modal</h1>
    </div>
  </teleport>
</template>

特别适合弹窗类的元素渲染,这样页面的所有元素就不用所有的元素都挤在一个div中了
在index.html添加一个modal元素

<div id-"app"></div>
<div id-"modal"></div>

实际应用中,在使用弹窗类元素的组件中需要手动控制该元素的渲染与否。
定义一个isOpen来控制,
子组件内部通过context.emit('close-modal')去触发根组件中定义的事件,注意在vue3中子组件需要通过emit引入该事件。

<template>
<teleport to="#modal">
  <div id="center" v-if="isOpen">
    <h2><slot>this is a modal</slot></h2>
    <button @click="buttonClick">Close</button>
  </div>
</teleport>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
  props: {
    isOpen: Boolean,
  },
  emits: {
    'close-modal': null
  },
  setup(props, context) {
    const buttonClick = () => {
      context.emit('close-modal')
    }
    return {
      buttonClick
    }
  }
})

在 App.vue 组件中使用

const modalIsOpen = ref(false)
const openModal = () => {
  modalIsOpen.value = true
}
const onModalClose = () => {
  modalIsOpen.value = false
}

<button @click="openModal">Open Modal</button><br/>
<modal :isOpen="modalIsOpen" @close-modal="onModalClose"> My Modal !!!!</modal>

8.异步组件优化:Suspense

Suspense是Vue3推出的一个内置的特殊组件
Suspense内部默认有两个自定义的slot,刚开始的会渲染#default部分,达到某个条件之后才会去渲染#fallback的内容。
如果要使用Suspense,组件中要返回一个Promise
可以非常方便为异步请求的等待界面进行个性化的定制。
定义一个异步组件,在 setup 返回一个 Promise,AsyncShow.vue

<template>
  <h1>{{result}}</h1>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
  setup() {
    return new Promise((resolve) => {
      setTimeout(() => {
        return resolve({
          result: 42
        })
      }, 3000)
    })
  }
})
</script>

在 App.vue 中使用

<Suspense>
  <template #default>
    <async-show />
  </template>
  <template #fallback>
    <h1>Loading !...</h1>
  </template>
</Suspense>

default可以存放多个异步组件,这样会等到所有的异步组件都拿到结果之后才去渲染里面的内容。

<template>
  <img :src="result && result.message">
</template>

<script lang="ts">
import axios from 'axios'
import { defineComponent } from 'vue'
export default defineComponent({
  async setup() {
    const rawData = await axios.get('https://dog.ceo/api/breeds/image')
    return {
      result: rawData.data
    }
  }
})
</script>

Suspense 中可以添加多个异步组件

<Suspense>
  <template #default>
    <async-show />
    <dog-show />
  </template>
  <template #fallback>
    <h1>Loading !...</h1>
  </template>
</Suspense>

9.全局API优化

vue2全局API的写法
1.从vue中导出一个全局对象Vue

import Vue from 'vue'
import App from './App.vue'

2.然后在Vue中进行一系列的配置

Vue.config.ignoredElements = [/^app-/]
Vue.use(/* ... */)
Vue.mixin(/* ... */)
Vue.component(/* ... */)
Vue.directive(/* ... */)

3.新建vue实例,然后调用$mount方法将其挂在到app节点上

new Vue({
  render: h => h(App)
}).$mount('#app')

Vue2 这样写在一定程度上修改了 Vue 对象的全局状态。
第一,在单元测试中,全局配置非常容易污染全局环境,用户需要在每次 case 之间,保存和恢复配置。有一些 api (vue use vue mixin)甚至没有方法恢复配置,这就让一些插件的测试非常的困难。
第二,在不同的 APP 中,如果想共享一份有不同配置的 vue 对象,也变得非常困难。

vue3新增加了createApp,先将createApp引入,然后利用createApp生成一个app实例,

const app = createApp(App)

接下来增加配置就不需要直接给Vue添加了,而是给app添加就行了

app.config.isCustomElement = tag => tag.startsWith('app-')
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)

现在再设置任何的配置都会是在不同的app实例上,不同的设置就不会发生冲突。
当配置结束以后,我们再把 App 使用 mount 方法挂载到固定的 DOM 的节点上。

app.mount(App, '#app')
最后编辑于:2024-10-27 15:58:36


喜欢的朋友记得点赞、收藏、关注哦!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2234121.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux scp命令 | 菜鸟教程-从本地复制到远程/从远程复制到本地

目录 Linux scp命令 语法 实例 1、从本地复制到远程 2、从远程复制到本地 说明 文章来源&#xff1a;Linux scp命令 | 菜鸟教程 Linux scp命令 nux scp 命令用于 Linux 之间复制文件和目录。 scp 是 secure copy 的缩写, scp 是 linux 系统下基于 ssh 登陆进行安全的远…

计算机毕业设计Python+大模型膳食推荐系统 知识图谱 面向慢性病群体的膳食推荐系统 健康食谱推荐系统 机器学习 深度学习 Python爬虫 大数据毕业设计

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

大数据集群中实用的三个脚本文件解析与应用

目录 一、jps - cluster.sh 脚本文件 &#xff08;一&#xff09;背景与功能 &#xff08;二&#xff09;使用方法 二、集群文件分发脚本 xsync.sh &#xff08;一&#xff09;背景与问题 &#xff08;二&#xff09;功能与实现原理 &#xff08;三&#xff09;脚本编写…

【数据分享】1981-2024年我国逐日平均气温栅格数据(免费获取)

气象数据一直是一个价值很高的数据&#xff0c;它被广泛用于各个领域的研究当中。这其中&#xff0c;又以平均气温数据最为常用&#xff01;之前我们分享过来源于美国国家海洋和大气管理局&#xff08;NOAA&#xff09;下设的国家环境信息中心(NCEI)发布的1929-2024年全球站点的…

多模态PaliGemma——Google推出的基于SigLIP和Gemma的视觉语言模型

前言 本文怎么来的呢&#xff1f;其实很简单&#xff0c;源于上一篇文章《π0——用于通用机器人控制的流匹配VLA模型&#xff1a;一套框架控制7种机械臂(改造了PaliGemma和ACT的3B模型)》中的π0用到了PaliGemma 故本文便来解读下这个PaliGemma 第一部分 PaliGemma 1.1 Pal…

开源模型应用落地-glm模型小试-glm-4-9b-chat-Gradio集成(三)

一、前言 GLM-4是智谱AI团队于2024年1月16日发布的基座大模型&#xff0c;旨在自动理解和规划用户的复杂指令&#xff0c;并能调用网页浏览器。其功能包括数据分析、图表创建、PPT生成等&#xff0c;支持128K的上下文窗口&#xff0c;使其在长文本处理和精度召回方面表现优异&a…

ABAP开发学习——OLE

目录 1.概览 2.OEL的实现方式 3.OLE的配置 4.OLE的实现 4.1 OLE Demo 4.2 OLE实现的步骤 5.OLE实现样例 5.1 OLE中的的类型转换 5.2 变量定义 5.3 创建对象 5.4 表单页的操作 5.5 设置文件保存路径 5.6 文件是否可见 5.7 单元格操作 5.7.1 给单元格赋值 5.7.2…

在Java中,实现数据库连接通常使用JDBC

学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中……&#xff09; 4、牛逼哄哄的 IDEA编程利器技巧(编写中……&#xff09; 5、面经吐血整理的 面试技…

单臂路由实现不同VLAN之间设备通信

转载请注明出处 本实验为单臂路由配置&#xff0c;目的为让不同VLAN之间的设备能够互相通信。 1.首先&#xff0c;按照要求配置两个pc的ip地址&#xff0c;以pc0为例子&#xff1a; 2在交换机创建vlan10和vlan20 3.划分vlan&#xff0c;pc0为vlan10的设备&#xff0c;pc1为vla…

前后端交互通用排序策略

目录 排序场景 排序实现思路 1. 静态代码排序实现 2.数据库驱动排序实现 3. 基于Java反射的动态排序实现 通用排序工具 SortListUtil 结语 排序场景 在面向前端数据展示的应用场景中&#xff0c;我们旨在实现一个更加灵活的排序机制&#xff0c;该机制能够支持对从后端传递…

【华为云-云驻共创】UCS跨云多活容灾:让业务高可用不再是难题

【摘要】云原生应用深入到企业各个业务场景&#xff0c;云原生正在走向分布式化&#xff0c;跨云跨域统一协同治理&#xff0c;保证一致应用体验&#xff0c;这些新的需求日益凸显。而容灾是确保服务高可用的保障&#xff0c;但即使应用部署在云上&#xff0c;也无法避免市政方…

Linux内核编程(十九)SPI子系统的应用与驱动编写

本文目录 一、 SPI驱动框架图二、编写SPI驱动device框架三、编写SPI驱动driver框架四、实验一编写mcp2515驱动1. 注册字符设备或杂项设备框架2. SPI写数据3. SPI读寄存器数据 4. MCP2515相关配置 对于SPI基础知识这里不做过多讲解&#xff0c;详情查看&#xff1a;SPI基础知识实…

谍影重重5.0

打开流量包可以发现&#xff0c;流量中含有大量的smb加密通信&#xff0c;并且使用了ntlm v2加密协议进行身份认证 包过滤ntlmssp 认证后smb协议进行了大量的数据传输 取出tom的包内数据 得到以下数据 username:tomdomain: .NTProofStr: ca32f9b5b48c04ccfa96f35213d63d75NT…

qt QAbstractItemModel详解

1. 概述 QAbstractItemModel是Qt框架中的一个核心抽象基类&#xff0c;在Qt的模型/视图架构中扮演着至关重要的角色。这个类提供了一个接口&#xff0c;用于表示和管理数据&#xff0c;但不直接处理数据的存储。它的主要功能是为视图组件&#xff08;如QListView、QTableView和…

华为OD机试 - 无重复字符的元素长度乘积的最大值(Python/JS/C/C++ 2024 C卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

【C++之STL】一文学会使用 string

文章目录 1. STL导读1. 1 什么是STL1. 2 STL的版本1. 3 STL六大组件1. 4 STL的重要性1. 5 STL的学习1. 6 STL系列博客的规划 2. string2. 1 为什么学习string类?2. 2 标准库中的string2. 3 基本构造2. 4 尾插与输出运算符重载2. 5 构造函数2. 6 赋值运算符重载2. 7 容量操作2.…

【分布式】分布式锁设计与Redisson源码解析

分布式锁 分布式锁是一种在分布式计算环境中用于控制多个节点&#xff08;或多个进程&#xff09;对共享资源的访问的机制。在分布式系统中&#xff0c;多个节点可能需要协调对共享资源的访问&#xff0c;以防止数据的不一致性或冲突。分布式锁允许多个节点在竞争访问共享资源…

【实测有效】两个Ubuntu系统通过网线传输文件

基本思路是&#xff1a;连接网线后&#xff0c;通过设置静态IP&#xff0c;将两台电脑配置在同一个局域网内&#xff0c;再进行文件传输。 一、物理连接 使用网线将两台电脑的网口连接起来。 二、静态IP设置 两台电脑均需要对各自的静态IP进行设置。 1、查看电脑的IP地址 1&a…

Android camera2

一、序言 为了对阶段性的知识积累、方便以后调查问题&#xff0c;特做此文档&#xff01; 将以camera app 使用camera2 api进行分析。 (1)、打开相机 openCamera (2)、创建会话 createCaptureSession (3)、开始预览 setRepeatingRequest (4)、停止预览 stopRepeating (5)、关闭…

【Redis_Day3】Redis通用命令

【Redis_Day3】Redis通用命令 redis客户端的三种形态redis的快与慢redis通用命令阅读redis官方文档redis中两个核心命令set命令get命令 redis全局命令keys命令&#xff1a;查询当前服务器上的key生产环境 exists命令&#xff1a;判定key是否存在del命令&#xff1a;删除指定的k…