ToB企服应用市场:ToB评测及商务社交产业平台

标题: Vue3底子看这一篇就够了(万字长篇,附实例代码及结果演示) [打印本页]

作者: 渣渣兔    时间: 2024-6-18 19:52
标题: Vue3底子看这一篇就够了(万字长篇,附实例代码及结果演示)
目录
前言
概述
Vue3组合式api  VS  Vue2选项式api
底子部分
setup
选项式api的风格
组合式api的风格
区别
 响应式数据
ref
reactive
shallowReactive 与 shallowRef 
 盘算属性和监听
 computed 函数
 watch 函数
 watchEffect
生命周期
 响应式数据只读
toRaw 返回代理的源
markRaw 标记对象拒旷世理
provide 与 inject 跨组件传值
判断是否为响应式数据
toRef 和 toRefs 解构响应式数据
 新组件
Fragment
Teleport 
Suspense
组合式函数 
全局的api及指令的变动
结语


前言

   vue3已经出了好长一段时间了,近来闲来无事简单学习了一下,新增的东西还是挺多的,写一篇文章来记录一下。
  概述

Vue3组合式api  VS  Vue2选项式api

   谈到 vue3,首先想到的就是组合式api,很大程度的解决了vue2选项式api的缺点,那有啥缺点?当文件中的业务代码非常多的时间,阅读修改代码的时间好坏常痛楚的,data,method,watch另有盘算属性之间来回跳转, 我已经准备拔刀了。
  下面这些图被疯转,很形象的展现了vue2和vue3的区别,可以看到组合式api就是将单个功能的状态,方法,盘算属性等等必要用到的东西都组合在一起抽离成一个hook,也就是对应图4的function,终极再统一引入组合到一起。这样做的利益就是单个功能的代码都在一起,方便调式修改。
  
 

 

底子部分

setup

   setup是vue3的一个新的配置项,只在初始化的时间实验一次,所有的组合式函数都在此使用。setup可以在选项式api的风格中使用也可以通过组合式api的风格 。通过代码简单对比一下。vue3推荐使用组合式。
  选项式api的风格

  1. <script>
  2. import { ref } from 'vue'
  3. export default {
  4.   setup() {
  5.     const sum = ref(1)
  6.     return {
  7.       sum,
  8.     }
  9.   },
  10. }
  11. </script>
  12. <template>
  13.   <div>
  14.     <h1>v3</h1>
  15.     <h3>{{ sum }}</h3>
  16.     <button @click="sum++">+1</button>
  17.   </div>
  18. </template>
  19. <style scoped></style>
复制代码
组合式api的风格

  1. <script setup>
  2. import { ref } from 'vue'
  3. const sum = ref(1)
  4. </script>
  5. <template>
  6.   <div>
  7.     <h1>v3</h1>
  8.     <h3>{{ sum }}</h3>
  9.     <button @click="sum++">+1</button>
  10.   </div>
  11. </template>
  12. <style scoped></style>
复制代码
区别

   官网介绍的比较具体,感兴趣可以查看组合式 API 常见问答 | Vue.js 
   响应式数据

   vue2中 data 函数返回的对象就是响应式的数据,但是在增加删除对象属性时不是响应式的,当然vue2中也有对应的解决方法,this.$set(), this.$delete(), 其实这也能够理解,究竟vue2的响应式式基于 Object.defineProperty 实现的,这个函数只提供了 get 和 set 以及一些描述符 descriptor,并没有提供 add 和 delete 方法。
  vue3中的响应式包含了两种形态, ref(底层还是Object.defineProperty举行数据挟制, 处理简单数据范例),reactive(使用es6的Proxy举行数据挟制,处理复杂数据范例),完全修复了vue2响应式的痛点,vue3的响应式更加的友好。
  ref

   ref 接受一个值,返回一个响应式对象,一样平常用来处理简单数据范例的响应式,但如果传入的值是对象 ref 会告急 reactive,返回RefImpl的实例简称ref对象。 此时可能会有疑惑,既然ref是一个响应式的对象,为什么模板中能正常剖析。这是由于在剖析templete时碰到ref对象会自动取其value属性,但是如果要在方法中修改ref创建的响应式数据,你的写法应该是这样的 state.value = xxx
  1. <script setup>
  2. import { ref } from 'vue'
  3. const sum = ref(1)
  4. function add() {
  5.   sum.value++
  6. }
  7. </script>
  8. <template>
  9.   <div>
  10.     <h1>v3</h1>
  11.     <h3>{{ sum }}</h3>
  12.     <button @click="add">+1</button>
  13.   </div>
  14. </template>
  15. <style scoped></style>
复制代码
reactive

   为对象做深层!!!!响应式代理, 也就是如果对象有多层依旧是响应式的,返回一个Proxy实例, 如果传入一个字符串大概数字,它将不是响应式的。Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自界说(如属性查找、赋值、枚举、函数调用等)Proxy - JavaScript | MDN。Vue使用 Proxy 举行数据挟制, Reflect 举行反射修改 Reflect - JavaScript | MDN
  

  1. <script setup>
  2. import { reactive } from 'vue'
  3. const person = reactive({
  4.   name: '张三',
  5.   age: 12,
  6.   job: {
  7.     j1: {
  8.       jname: '前端开发',
  9.     },
  10.   },
  11. })
  12. function add() {
  13.   person.hobby = ['唱', '跳', 'rap']
  14. }
  15. function deleteHB() {
  16.   delete person.hobby
  17. }
  18. </script>
  19. <template>
  20.   <div>
  21.     <h1>v3</h1>
  22.     <h1>{{ sum }}</h1>
  23.     <h3>姓名:{{ person.name }}</h3>
  24.     <h3>年龄:{{ person.age }}</h3>
  25.     <h3>工作:{{ person.job.j1.jname }}</h3>
  26.     <h3 v-if="person.hobby">爱好: {{ person.hobby }}</h3>
  27.     <button @click="person.name += '-'">修改姓名</button>
  28.     <button @click="person.age++">修改年龄</button>
  29.     <button @click="person.job.j1.jname += '!'">修改工作</button>
  30.     <button @click="add">增加爱好</button>
  31.     <button @click="deleteHB">删除爱好</button>
  32.   </div>
  33. </template>
  34. <style scoped></style>
复制代码
shallowReactive 与 shallowRef 

   shallowRef 直译过来意思是浅层的 ref,shallowRef 传入对象不会告急 reactive,仅仅对ref对象的 value 属性具有响应式。
  shallowReactive 只处理对象第一层的响应式,  如果修改了深层的数据页面是不会响应的,但是会在下次页面更新中渲染出来。
  

  1. <script setup>
  2. import { shallowReactive, shallowRef, ref, reactive } from 'vue'
  3. const shallowRef_jack = shallowRef({ name: 'jack', sex: '女' })
  4. const shallowReactive_ben = shallowReactive({
  5.   name: 'ben',
  6.   sex: '女',
  7.   child: {
  8.     son: {
  9.       name: '张三',
  10.     },
  11.   },
  12. })
  13. const ref_jack = ref({ name: 'jack', sex: '女' })
  14. const reactive_ben = reactive({
  15.   name: 'ben',
  16.   sex: '女',
  17.   child: {
  18.     son: {
  19.       name: '张三',
  20.     },
  21.   },
  22. })
  23. </script>
  24. <template>
  25.   <div>
  26.     <h1>v3</h1>
  27.     <h3>
  28.       shallowRef_jack: {{ shallowRef_jack }}
  29.       <button @click="shallowRef_jack = {}">修改整个对象</button>
  30.       <button @click="shallowRef_jack.name += '!'">修改对象属性</button>
  31.     </h3>
  32.     <h3>
  33.       ref_jack: {{ ref_jack }}
  34.       <button @click="ref_jack = {}">修改整个对象</button>
  35.       <button @click="ref_jack.name += '!'">修改对象属性</button>
  36.     </h3>
  37.     <h3>
  38.       shallowReactive_ben: {{ shallowReactive_ben }}
  39.       <button @click="shallowReactive_ben.child.son.name = '!'">
  40.         修改对象的第三层属性
  41.       </button>
  42.       <button @click="shallowReactive_ben.name += '!'">
  43.         修改对象第一层属性
  44.       </button>
  45.     </h3>
  46.     <h3>
  47.       reactive_ben: {{ reactive_ben }}
  48.       <button @click="reactive_ben.child.son.name += '!'">
  49.         修改对象的第三层属性
  50.       </button>
  51.       <button @click="reactive_ben.name += '!'">修改对象第一层属性</button>
  52.     </h3>
  53.   </div>
  54. </template>
  55. <style scoped>
  56. h3 {
  57.   font-size: 26px;
  58.   border: 1px solid #ccc;
  59.   padding: 20px;
  60.   margin: 20px;
  61. }
  62. button {
  63.   float: right;
  64.   padding: 10px;
  65.   font-size: 20px;
  66. }
  67. </style>
复制代码
 盘算属性和监听

 computed 函数

   盘算属性有两种写法,作用和vue2一样,通过监听某个值的变化盘算出一个新值
  
  1. <script setup>
  2. import { ref, computed } from 'vue'
  3. const count = ref(1)
  4. const num1 = computed(() => count.value + 1)
  5. const num2 = computed({
  6.   get() {
  7.     return count.value + 1
  8.   },
  9.   set(val) {
  10.     count.value = val + 1
  11.   },
  12. })
  13. </script>
  14. <template>
  15.   <div>
  16.     <h1>v3</h1>
  17.     <h2>
  18.       ref 定义的 count: {{ count }} <button @click="count++">count++</button>
  19.     </h2>
  20.     <h2>计算属性 num1: {{ num1 }} <button @click="num1++">num1++</button></h2>
  21.     <h2>计算属性 num2: {{ num2 }} <button @click="num2++">num2++</button></h2>
  22.   </div>
  23. </template>
  24. <style scoped></style>
复制代码

 watch 函数

   watch 函数用来监听数据的变化,和vue2大要上都是相同的。
  参数列表:
     

留意点: 
  1. <script setup>
  2. import { reactive, ref, watch } from 'vue'
  3. const count = ref(1)
  4. const person = reactive({
  5.   name: 'ben',
  6.   child: {
  7.     son: {
  8.       name: 'zs',
  9.     },
  10.   },
  11. })
  12. // 监听 ref 对象
  13. watch(count, (val, preVal) => {
  14.   console.log('count变化了', val, preVal)
  15. })
  16. // 监听 reactive  定义的响应式对象
  17. watch(person, (val, preVal) => {
  18.   console.log('person变化了', val, preVal)
  19. })
  20. watch([count, person], (val, preVal) => {
  21.   console.log('person变化了或count变化了', val, preVal)
  22. })
  23. </script>
  24. <template>
  25.   <div>
  26.     <h1>v3</h1>
  27.     <h2>
  28.       ref 定义的 count: {{ count }} <button @click="count++">count++</button>
  29.     </h2>
  30.     <h2>
  31.       reactive 定义的 person: {{ person }}
  32.       <button @click="person.name += '!'">修改姓名</button>
  33.       <button @click="person.child.son.name += '___'">修改儿子姓名</button>
  34.     </h2>
  35.   </div>
  36. </template>
  37. <style scoped></style>
复制代码
 watchEffect

   watchEffect 函数用于监听传入的函数内访问的所有响应式数据的变化。白话一点就是回调里我用了谁我就监听谁,监听ref界说的响应式数据时,不要忘记 .value ,哥们就是这么智能。
  watch 和 watchEffect 都是监听数据变化的函数,和 react 中的 useState 放入依靠项有着异曲同工之妙。
  例子:切换下拉框中的 name ,模拟哀求后台接口 
  1. <script setup>
  2. import { onMounted, reactive, ref, watchEffect } from 'vue'
  3. const name = ref('jack')
  4. const info = [
  5.   {
  6.     id: 1,
  7.     name: 'jack',
  8.     child: {
  9.       son: {
  10.         name: 'zs',
  11.       },
  12.     },
  13.   },
  14.   {
  15.     id: 2,
  16.     name: 'ben',
  17.     child: {
  18.       son: {
  19.         name: 'zs',
  20.       },
  21.     },
  22.   },
  23. ]
  24. let data = ref([])
  25. async function getInfoByName(name) {
  26.   const res = await new Promise((reslove) => {
  27.     setTimeout(() => {
  28.       reslove(info.filter((item) => item.name === name))
  29.     }, 500)
  30.   })
  31.   data.value = res
  32. }
  33. watchEffect(async () => {
  34.   getInfoByName(name.value)
  35. })
  36. </script>
  37. <template>
  38.   <div>
  39.     <h1>v3</h1>
  40.     <el-select v-model="name" placeholder="请选择">
  41.       <el-option
  42.         v-for="item in info"
  43.         :key="item.name"
  44.         :label="item.name"
  45.         :value="item.name"
  46.       >
  47.       </el-option>
  48.     </el-select>
  49.     <div v-for="item in data" :key="item.id">
  50.       {{ item.name }}的个人信息 {{ item }}
  51.     </div>
  52.   </div>
  53. </template>
  54. <style scoped></style>
复制代码

生命周期

   vue3的生命周期稍有变动,增加了 setup 钩子,且销毁前和销毁后的钩子命名更改为 beforeUnmount 和 unmounted,以下代码是验证的一些示例
  App.vue 
  1. <script setup>
  2. import Demo from './Demo.vue'
  3. import Demo2 from './Demo2.vue'
  4. import { ref } from 'vue'
  5. const isComDestory = ref(true)
  6. const isOptionDestory = ref(true)
  7. </script>
  8. <template>
  9.   <div>
  10.     <h1>
  11.       v3
  12.       <button @click="isComDestory = false">引入组合式子组件</button>
  13.       <button @click="isComDestory = true">销毁组合式子组件</button>
  14.       <button @click="isOptionDestory = false">引入选项式子组件</button>
  15.       <button @click="isOptionDestory = true">销毁选项式子组件</button>
  16.     </h1>
  17.     <Demo v-if="!isComDestory"></Demo>
  18.     <Demo2 v-if="!isOptionDestory"></Demo2>
  19.   </div>
  20. </template>
  21. <style scoped>
  22. button {
  23.   padding: 20px;
  24.   font-size: 16px;
  25. }
  26. </style>
复制代码
Demo.vue 
  1. <script setup>
  2. import {
  3.   onMounted,
  4.   onBeforeMount,
  5.   onBeforeUpdate,
  6.   onUpdated,
  7.   onBeforeUnmount,
  8.   onUnmounted,
  9.   ref,
  10. } from 'vue'
  11. const sum = ref(1)
  12. console.log('子组件1 setup')
  13. onBeforeMount(() => {
  14.   console.log('子组件1 onBeforeMount')
  15. })
  16. onMounted(() => {
  17.   console.log('子组件1 onMounted')
  18. })
  19. onBeforeUpdate(() => {
  20.   console.log('子组件1 onBeforeUpdate')
  21. })
  22. onUpdated(() => {
  23.   console.log('子组件1 onUpdated')
  24. })
  25. onBeforeUnmount(() => {
  26.   console.log('子组件1 onBeforeUnmount')
  27. })
  28. onUnmounted(() => {
  29.   console.log('子组件1 onUnmounted')
  30. })
  31. </script>
  32. <template>
  33.   <div>
  34.     <h2>我是子组件1</h2>
  35.     <h2>{{ sum }} <button @click="sum++">+1</button></h2>
  36.   </div>
  37. </template>
  38. <style scoped>
  39. div {
  40.   border: 1px solid #ccc;
  41. }
  42. </style>
复制代码
Demo2.vue
  1. <script>
  2. import { ref } from 'vue'
  3. export default {
  4.   setup() {
  5.     const sum = ref(1)
  6.     console.log('子组件2 setup')
  7.     return { sum }
  8.   },
  9.   beforeCreate() {
  10.     console.log('子组件2 beforeCreate')
  11.   },
  12.   created() {
  13.     console.log('子组件2 created')
  14.   },
  15.   beforeMount() {
  16.     console.log('子组件2 beforeMount')
  17.   },
  18.   mounted() {
  19.     console.log('子组件2 mounted')
  20.   },
  21.   beforeUpdate() {
  22.     console.log('子组件2 beforeUpdate')
  23.   },
  24.   updated() {
  25.     console.log('子组件2 updated')
  26.   },
  27.   beforeUnmount() {
  28.     console.log('子组件2 beforeUnmount')
  29.   },
  30.   unmounted() {
  31.     console.log('子组件2 unmounted')
  32.   },
  33. }
  34. </script>
  35. <template>
  36.   <div>
  37.     <h2>我是子组件2</h2>
  38.     <h2>{{ sum }} <button @click="sum++">+1</button></h2>
  39.   </div>
  40. </template>
  41. <style scoped>
  42. div {
  43.   border: 1px solid #ccc;
  44. }
  45. </style>
复制代码

由于录频录不了控制台,打印结果看下图


 

 响应式数据只读

   vue3提供了两个api,限制响应式数据为只读,不可修改。分别为 readonly(深层只读) 和shallowReadonly (浅层只读)
  


  1. <script setup>
  2. import { ref, reactive, readonly, shallowReadonly } from 'vue'
  3. const sum = readonly(ref(1))
  4. const p1 = readonly(
  5.   reactive({
  6.     name: 'ben',
  7.     child: {
  8.       son: {
  9.         name: 'jack',
  10.       },
  11.     },
  12.   })
  13. )
  14. const p2 = shallowReadonly(
  15.   reactive({
  16.     name: 'ben',
  17.     child: {
  18.       son: {
  19.         name: 'jack',
  20.       },
  21.     },
  22.   })
  23. )
  24. function edit() {
  25.   sum.value = 2
  26.   p1.name += '!'
  27.   p1.child.son.name += '&'
  28. }
  29. function editShallow() {
  30.   p2.name += '!'
  31.   p2.child.son.name += '&'
  32. }
  33. </script>
  34. <template>
  35.   <div>
  36.     <h1>v3</h1>
  37.     <h2>readonly: {{ sum }}</h2>
  38.     <h2>readonly: {{ p1 }}</h2>
  39.     <h2>shallowReadonly: {{ p2 }}</h2>
  40.     <button @click="edit">修改深层只读数据</button>
  41.     <button @click="editShallow">修改浅层只读数据</button>
  42.   </div>
  43. </template>
  44. <style scoped></style>
复制代码


toRaw 返回代理的源

   toRaw的功能官网的表明很清晰, 可以返回由 reactive()、readonly()、shallowReactive() 大概 shallowReadonly() 创建的代理对应的原始对象
  1. <script setup>
  2. import {
  3.   ref,
  4.   reactive,
  5.   readonly,
  6.   shallowReadonly,
  7.   shallowReactive,
  8.   toRaw,
  9. } from 'vue'
  10. const p1 = readonly(
  11.   reactive({
  12.     name: 'a',
  13.     child: {
  14.       son: {
  15.         name: 'as',
  16.       },
  17.     },
  18.   })
  19. )
  20. const p2 = shallowReadonly(
  21.   reactive({
  22.     name: 'b',
  23.     child: {
  24.       son: {
  25.         name: 'bs',
  26.       },
  27.     },
  28.   })
  29. )
  30. const p3 = reactive({
  31.   name: 'c',
  32.   child: {
  33.     son: {
  34.       name: 'cs',
  35.     },
  36.   },
  37. })
  38. const p4 = shallowReactive({
  39.   name: 'd',
  40.   child: {
  41.     son: {
  42.       name: 'ds',
  43.     },
  44.   },
  45. })
  46. console.log('toRaw p1 readonly', toRaw(p1))
  47. console.log('toRaw p2 shallowReadonly', toRaw(p2))
  48. console.log('toRaw p3 reactive', toRaw(p3))
  49. console.log('toRaw p4 shallowReactive', toRaw(p4))
  50. </script>
  51. <template>
  52.   <div></div>
  53. </template>
  54. <style scoped></style>
复制代码

markRaw 标记对象拒旷世理

   markRaw()将对象标记为不可代理,返回其自己。自己上多了一个 __v_skip 属性表示忽略代理。强行代理代理是无效的,返回的还是其自己而不是响应式对象。
  1. <script setup>
  2. import { markRaw, reactive } from 'vue'
  3. const p1 = {
  4.   name: 'a',
  5.   child: {
  6.     son: {
  7.       name: 'as',
  8.     },
  9.   },
  10. }
  11. const noProxy_p1 = markRaw(p1)
  12. console.log('不可代理对象', noProxy_p1)
  13. console.log('reactive 代理不可代理对象', reactive(noProxy_p1))
  14. </script>
  15. <template>
  16.   <div></div>
  17. </template>
  18. <style scoped></style>
复制代码

 provide 与 inject 跨组件传值

   使用 provide 与 inject 举行跨组件传值非常方便。以父子孙为例,父组件 provide ('name',value) 子组件 inject ('name') 即可
  

 父组件
  1. <script setup>
  2. import { reactive, provide } from 'vue'
  3. import Demo from './Demo.vue'
  4. const obj = {
  5.   name: 'a',
  6.   child: {
  7.     son: {
  8.       name: 'as',
  9.     },
  10.   },
  11. }
  12. const person = reactive(obj)
  13. provide('person', person)
  14. </script>
  15. <template>
  16.   <div class="father">
  17.     <h1>父组件</h1>
  18.     <h3>{{ person }}</h3>
  19.     <Demo></Demo>
  20.   </div>
  21. </template>
  22. <style scoped>
  23. .father {
  24.   padding: 10px;
  25.   background: orange;
  26. }
  27. </style>
复制代码
 子组件
  1. <script setup>
  2. import Demo2 from './Demo2.vue'
  3. </script>
  4. <template>
  5.   <div>
  6.     <h2>子组件</h2>
  7.     <Demo2></Demo2>
  8.   </div>
  9. </template>
  10. <style scoped>
  11. div {
  12.   padding: 10px;
  13.   background: salmon;
  14.   border: 1px solid #ccc;
  15. }
  16. </style>
复制代码
孙组件
  1. <script>
  2. import { ref, inject } from 'vue'
  3. export default {
  4.   setup() {
  5.     const person = inject('person')
  6.     return { person }
  7.   },
  8. }
  9. </script>
  10. <template>
  11.   <div class="sonson">
  12.     <h2>孙组件</h2>
  13.     <h3>{{ person }}</h3>
  14.   </div>
  15. </template>
  16. <style scoped>
  17. .sonson {
  18.   background: sandybrown;
  19.   border: 1px solid #ccc;
  20. }
  21. </style>
复制代码
判断是否为响应式数据

   
  

  1. <script setup>
  2. import {
  3.   reactive,
  4.   readonly,
  5.   ref,
  6.   isProxy,
  7.   isReactive,
  8.   isRef,
  9.   isReadonly,
  10. } from 'vue'
  11. const person = reactive({
  12.   name: 'a',
  13.   child: {
  14.     son: {
  15.       name: 'as',
  16.     },
  17.   },
  18. })
  19. const num = ref(1)
  20. const str = readonly(ref('str'))
  21. console.log(isRef(num))
  22. console.log(isReactive(person))
  23. console.log(isReadonly(str))
  24. console.log(isProxy(person), isProxy(str))
  25. </script>
  26. <template></template>
  27. <style scoped></style>
复制代码
toRef 和 toRefs 解构响应式数据

   当响应式对象的属性过多且页面用到很多次的时间, toRef 和 toRefs 可以举行响应式解构,解构出来的数据依旧具备响应式的本领。下面的例子是在 <script setup> 中举行演示的,setup()中的必要显示的返回
   toRef
  1. <script setup>
  2. import { reactive, toRef } from 'vue'
  3. const person = reactive({
  4.   name: 'a',
  5.   age: 18,
  6.   child: {
  7.     son: {
  8.       name: 'as',
  9.     },
  10.   },
  11. })
  12. const personName = toRef(person, 'name')
  13. const personAge = toRef(person, 'age')
  14. const personSonName = toRef(person.child.son, 'name')
  15. </script>
  16. <template>
  17.   <div>
  18.     <h3>toRef 解构出 person的name ----- {{ personName }}</h3>
  19.     <h3>toRef 解构出 person的age ----- {{ personAge }}</h3>
  20.     <h3>toRef 解构出 person的child的son的name ----- {{ personSonName }}</h3>
  21.     <h3>toRef 解构出 person的name ----- {{ personName }}</h3>
  22.     <h3>toRef 解构出 person的age ----- {{ personAge }}</h3>
  23.     <h3>toRef 解构出 person的child的son的name ----- {{ personSonName }}</h3>
  24.     <h3>toRef 解构出 person的name ----- {{ personName }}</h3>
  25.     <h3>toRef 解构出 person的age ----- {{ personAge }}</h3>
  26.     <h3>toRef 解构出 person的child的son的name ----- {{ personSonName }}</h3>
  27.     <button @click="personName += '!'">修改person的name</button>
  28.     <button @click="personAge += 1">修改person的age</button>
  29.     <button @click="personSonName += '*'">person的child的son的name</button>
  30.   </div>
  31. </template>
  32. <style scoped></style>
复制代码
 

 toRefs
  1. <script setup>
  2. import { reactive, toRefs } from 'vue'
  3. const person = reactive({
  4.   name: 'a',
  5.   age: 18,
  6.   child: {
  7.     son: {
  8.       name: 'as',
  9.     },
  10.   },
  11. })
  12. const { name, age, child } = toRefs(person)
  13. </script>
  14. <template>
  15.   <div>
  16.     <h3>toRefs 解构出 person的name ----- {{ name }}</h3>
  17.     <h3>toRefs 解构出 person的age ----- {{ age }}</h3>
  18.     <h3>toRefs 解构出 person的child的son的name ----- {{ child.son.name }}</h3>
  19.     <h3>toRefs 解构出 person的name ----- {{ name }}</h3>
  20.     <h3>toRefs 解构出 person的age ----- {{ age }}</h3>
  21.     <h3>toRefs 解构出 person的child的son的name ----- {{ child.son.name }}</h3>
  22.     <h3>toRefs 解构出 person的name ----- {{ name }}</h3>
  23.     <h3>toRefs 解构出 person的age ----- {{ age }}</h3>
  24.     <h3>toRefs 解构出 person的child的son的name ----- {{ child.son.name }}</h3>
  25.     <button @click="name += '!'">修改person的name</button>
  26.     <button @click="age += 1">修改person的age</button>
  27.     <button @click="child.son.name += '*'">person的child的son的name</button>
  28.   </div>
  29. </template>
  30. <style scoped></style>
复制代码

 新组件

Fragment

   在vue2中模板标签内必须包裹一层根标签,vue3中则不必要。vue3会为多个跟标签包裹一层Fragment。这是写法上的优化。前面很多例子的代码中我都包裹了一层根标签,这是由于我的编辑器的eslint的题目,去掉根标签也可以正常运行。
  有根标签的编译结果
 没有根标签的编译结果

Teleport 

   Teleport 组件的功能是将元素渲染到任意的页面位置中,直接扣过来官网的例子。
  下列代码主要表达的是:点击按钮将弹框插入到 body 标签下 
 ModalButton.vue
  1. <template>
  2.   <button @click="modalOpen = true">
  3.     Open full screen modal! (With teleport!)
  4.   </button>
  5.   <teleport to="body">
  6.     <div v-if="modalOpen" class="modal">
  7.       <div>
  8.         I'm a teleported modal! (My parent is "body")
  9.         <button @click="modalOpen = false">Close</button>
  10.       </div>
  11.     </div>
  12.   </teleport>
  13. </template>
  14. <script>
  15. import { ref } from 'vue'
  16. export default {
  17.   name: 'modal-button',
  18.   setup() {
  19.     const modalOpen = ref(false)
  20.     return {
  21.       modalOpen,
  22.     }
  23.   },
  24. }
  25. </script>
  26. <style>
  27. .modal {
  28.   position: absolute;
  29.   top: 0;
  30.   right: 0;
  31.   bottom: 0;
  32.   left: 0;
  33.   background-color: rgba(0, 0, 0, 0.5);
  34.   display: flex;
  35.   flex-direction: column;
  36.   align-items: center;
  37.   justify-content: center;
  38. }
  39. .modal div {
  40.   display: flex;
  41.   flex-direction: column;
  42.   align-items: center;
  43.   justify-content: center;
  44.   background-color: white;
  45.   width: 300px;
  46.   height: 300px;
  47.   padding: 5px;
  48. }
  49. </style>
复制代码
 App.vue
  1. <template>
  2.   <h2>App</h2>
  3.   <modal-button></modal-button>
  4. </template>
  5. <script lang="ts">
  6. import ModalButton from './ModalButton.vue'
  7. export default {
  8.   setup() {
  9.     return {}
  10.   },
  11.   components: {
  12.     ModalButton,
  13.   },
  14. }
  15. </script>
复制代码
 


Suspense

   Suspense 组件用于将异步组件包裹,提供一个过渡UI在异步完成之前。
  Suspense 组件提供两个插槽:
    异步组件:
     App.vue
  1. <template>
  2.   <div>
  3.     <h2>App</h2>
  4.     <Suspense>
  5.       <Demo></Demo>
  6.       <template #fallback> 加载中.... </template>
  7.     </Suspense>
  8.   </div>
  9. </template>
  10. <script setup>
  11. import Demo from './Demo.vue'
  12. </script>
复制代码
 Demo.vue
  1. <script setup>
  2. const res = await new Promise((resolve) => {
  3.   setTimeout(() => {
  4.     resolve({ name: 'zs', age: 12, sex: '男' })
  5.   }, 1000)
  6. })
  7. </script>
  8. <template>
  9.   <div>
  10.     <h2>异步组件</h2>
  11.     <h3>{{ res }}</h3>
  12.   </div>
  13. </template>
  14. <style scoped>
  15. div {
  16.   padding: 10px;
  17.   background: salmon;
  18.   border: 1px solid #ccc;
  19. }
  20. </style>
复制代码

组合式函数 

   组合式api的优点之一式将单个功能代码组合在一起,如果是可以复用的逻辑,那么可以抽离为一个组合式函数大概称为自界说hook,在必要该逻辑的地方导入即可
  例子:提供一个组合函数,此函数在当前组件中监听鼠标移动事件,并将坐标显示出来,组件卸载前清掉事件。
App.vue
  1. <template>
  2.   <div>
  3.     <h2>App</h2>
  4.     <h2>
  5.       <button @click="Demo1Visible = false">销毁子组件1</button>
  6.       <button @click="Demo2Visible = false">销毁子组件2</button>
  7.     </h2>
  8.     <Demo v-if="Demo1Visible"></Demo>
  9.     <Demo2 v-if="Demo2Visible"></Demo2>
  10.   </div>
  11. </template>
  12. <script setup>
  13. import { ref } from 'vue'
  14. import Demo from './Demo.vue'
  15. import Demo2 from './Demo2.vue'
  16. const Demo1Visible = ref(true)
  17. const Demo2Visible = ref(true)
  18. </script>
复制代码
Demo1.vue
  1. <template>
  2.   <div class="demo_1">
  3.     <h2>子组件1</h2>
  4.     <p v-if="x && y">x坐标为 {{ x }}, y坐标为{{ y }}</p>
  5.   </div>
  6. </template>
  7. <script setup>
  8. import useMouse from './mouse'
  9. const { x, y } = useMouse('.demo_1')
  10. </script>
  11. <style scoped>
  12. .demo_1 {
  13.   height: 100px;
  14.   background: salmon;
  15. }
  16. </style>
复制代码
Demo2.vue 
  1. <template>
  2.   <div class="demo_2">
  3.     <h2>子组件2</h2>
  4.     <p v-if="x && y">x坐标为 {{ x }}, y坐标为{{ y }}</p>
  5.   </div>
  6. </template>
  7. <script setup>
  8. import useMouse from './mouse'
  9. const { x, y } = useMouse('.demo_2')
  10. </script>
  11. <style scoped>
  12. .demo_2 {
  13.   height: 100px;
  14.   background: salmon;
  15. }
  16. </style>
复制代码
 




全局的api及指令的变动

   API 参考 | Vue.js,大家先自行参考,后续深入学习时再举行更新。
  结语

   

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4