总结(尚硅谷Vue3入门到实战,最新版vue3+TypeScript前端开辟教程)

[复制链接]
发表于 2025-10-20 08:48:21 | 显示全部楼层 |阅读模式
1.Vue简介

2020年9月18日,Vue.js发布版3.0版本,代号:One Piece
1.1.性能的提拔

        打包巨细镌汰41%。
        初次渲染快55%, 更新渲染快133%。
        内存镌汰54%。

1.2.源码的升级

        使用Proxy代替defineProperty实现相应式。
         重写假造DOM的实现和Tree-Shaking。

1.3.拥抱TypeScript

  Vue3可以更好的支持TypeScript。

1.4 新的特性

        ref和reactive
        新的生命周期函数

2.创建Vue3工程

基于 vite 创建(保举)
  1. ## 1.创建命令
  2. npm create vue@latest
  3. ## 2.具体配置
  4. ## 配置项目名称
  5. √ Project name: vue3_test
  6. ## 是否添加TypeScript支持
  7. √ Add TypeScript?  Yes
  8. ## 是否添加JSX支持
  9. √ Add JSX Support?  No
  10. ## 是否添加路由环境
  11. √ Add Vue Router for Single Page Application development?  No
  12. ## 是否添加pinia环境
  13. √ Add Pinia for state management?  No
  14. ## 是否添加单元测试
  15. √ Add Vitest for Unit Testing?  No
  16. ## 是否添加端到端测试方案
  17. √ Add an End-to-End Testing Solution? » No
  18. ## 是否添加ESLint语法检查
  19. √ Add ESLint for code quality?  Yes
  20. ## 是否添加Prettiert代码格式化
  21. √ Add Prettier for code formatting?  No
复制代码
3.Vue3核心语法

3.1.OptionsAPI 与 CompositionAPI

        Vue2的APi操持是Options(设置)风格,Vue3则是Composition(组合)风格,让相干功能代码更加有序的组合在一起

3.2.setup

概述

注意:setup函数中访问this是undefined
           全部值和函数都可以界说到setup函数中,但须要通过return“交出去”出来让外界使用
  1. <template>
  2.   <div class="person">
  3.     <h2>姓名:{{name}}</h2>
  4.     <h2>年龄:{{age}}</h2>
  5.     <button @click="changeName">修改名字</button>
  6.     <button @click="changeAge">年龄+1</button>
  7.     <button @click="showTel">点我查看联系方式</button>
  8.   </div>
  9. </template>
  10. <script lang="ts">
  11.   export default {
  12.     name:'Person',
  13.     setup(){
  14.       // 数据,原来写在data中(注意:此时的name、age、tel数据都不是响应式数据)
  15.       let name = '张三'
  16.       let age = 18
  17.       let tel = '13888888888'
  18.       // 方法,原来写在methods中
  19.       function changeName(){
  20.         name = 'zhang-san' //注意:此时这么修改name页面是不变化的
  21.         console.log(name)
  22.       }
  23.       function changeAge(){
  24.         age += 1 //注意:此时这么修改age页面是不变化的
  25.         console.log(age)
  26.       }
  27.       function showTel(){
  28.         alert(tel)
  29.       }
  30.       // 返回一个对象,对象中的内容,模板中可以直接使用
  31.       return {name,age,tel,changeName,changeAge,showTel}
  32.     }
  33.   }
  34. </script>
复制代码
 setup返回值

如果时返回一个对象则正常被调用
如果返回是一个函数,则会自动挂载,无关模板
  1. setup(){
  2.   return ()=> '你好啊!'
  3. }
复制代码
setup语法糖

 一样寻常来说须要使用vite插件简化
step1:npm i vite-plugin-vue-setup-extend -D
step2:修改vite.config.ts
  1. import { defineConfig } from 'vite'
  2. import VueSetupExtend from 'vite-plugin-vue-setup-extend'
  3. export default defineConfig({
  4.   plugins: [ VueSetupExtend() ]
  5. })
复制代码
step3:直接<script setup lang="ts" name="erson">

3.3.ref 创建:根本范例的相应式数据
  1. import {ref} from 'vue'
复制代码
语法:let age = ref(初始值),
返回值:是RefImpl的实例对象,简称ref对象,ref对象的value属性是相应式的
注意
        1.js中利用相应式对象须要用 xx.value ,在模板中直接用即可,无需.value
        2.对于 let age = ref(18)来说,age不是相应式的,age.value是相应式的

3.4.reactive 创建:对象范例的相应式数据
  1. import { reactive } from 'vue'
复制代码
语法:iet 相应式对象 = reactive(源对象)
返回值:proxy的实例对象,简称相应式对象
注意.reactive不能界说根本数据范例

3.5.ref 创建:对象范例的相应式数据

若ref吸收的是对象范例,内部实在也是调用了reactive函数。
注意:调用对象的属性应该是    xx.value.属性
代码能证明齐备
  1. <template>
  2.   <div class="person">
  3.     <h2>汽车信息:一台{{ car.brand }}汽车,价值{{ car.price }}万</h2>
  4.     <h2>游戏列表:</h2>
  5.     <ul>
  6.       <li v-for="g in games" :key="g.id">{{ g.name }}</li>
  7.     </ul>
  8.     <h2>测试:{{obj.a.b.c.d}}</h2>
  9.     <button @click="changeCarPrice">修改汽车价格</button>
  10.     <button @click="changeFirstGame">修改第一游戏</button>
  11.     <button @click="test">测试</button>
  12.   </div>
  13. </template>
  14. <script lang="ts" setup name="Person">
  15. import { ref } from 'vue'
  16. // 数据
  17. let car = ref({ brand: '奔驰', price: 100 })
  18. let games = ref([
  19.   { id: 'ahsgdyfa01', name: '英雄联盟' },
  20.   { id: 'ahsgdyfa02', name: '王者荣耀' },
  21.   { id: 'ahsgdyfa03', name: '原神' }
  22. ])
  23. console.log(car)
  24. function changeCarPrice() {
  25.   car.value.price += 10
  26. }
  27. function changeFirstGame() {
  28.   games.value[0].name = '流星蝴蝶剑'
  29. }
  30. function test(){
  31.   obj.value.a.b.c.d = 999
  32. }
  33. </script>
复制代码
3.6.ref 对比 reactive

使用原则:

  • 若须要一个根本范例的相应式数据,必须使用ref。
  • 若须要一个相应式对象,层级不深,ref、reactive都可以。
  • 若须要一个相应式对象,且层级较深,保举使用reactive。
注意:reactive重新分配一个新对象,会失去相应式(可以使用Object.assign去团体更换)
  1. let stu = reactive({name:'张三',age:18})
  2. stu = {name:'王五',age:19}//这样会失去响应式,
  3. //可以使用Object.assign整体替换
  4. Object.assign(stu,{'王五' ,19})
复制代码
3.7 toRefs 与 toRef

作用:将一个相应式对象中的全部属性转化为ref对象
注意:toRefs与toRef功能划一,但toRefs可以批量转换。
  1. <template>
  2.   <div class="person">
  3.     <h2>姓名:{{person.name}}</h2>
  4.     <h2>年龄:{{person.age}}</h2>
  5.     <h2>性别:{{person.gender}}</h2>
  6.     <button @click="changeName">修改名字</button>
  7.     <button @click="changeAge">修改年龄</button>
  8.     <button @click="changeGender">修改性别</button>
  9.   </div>
  10. </template>
  11. <script lang="ts" setup name="Person">
  12.   import {ref,reactive,toRefs,toRef} from 'vue'
  13.   // 数据
  14.   let person = reactive({name:'张三', age:18, gender:'男'})
  15.        
  16.   // 通过toRefs将person对象中的n个属性批量取出,且依然保持响应式的能力
  17.   let {name,gender} =  toRefs(person)
  18.        
  19.   // 通过toRef将person对象中的gender属性取出,且依然保持响应式的能力
  20.   let age = toRef(person,'age')
  21.   // 方法
  22.   function changeName(){
  23.     name.value += '~'
  24.   }
  25.   function changeAge(){
  26.     age.value += 1
  27.   }
  28.   function changeGender(){
  29.     gender.value = '女'
  30.   }
  31. </script>
复制代码
3.8.computed

只有待盘算的值发生改变,computed才可以重新盘算一次(比力智慧)
默认盘算的值是只读的,只有当写上get()和set()方法,盘算出来的值才是可读可写的
  1. <script setup lang="ts" name="App">
  2.   import {ref,computed} from 'vue'
  3.   let firstName = ref('zhang')
  4.   let lastName = ref('san')
  5.   // 计算属性——只读取,不修改
  6.   /* let fullName = computed(()=>{
  7.     return firstName.value + '-' + lastName.value
  8.   }) */
  9.   // 计算属性——既读取又修改
  10.   let fullName = computed({
  11.     // 读取
  12.     get(){
  13.       return firstName.value + '-' + lastName.value
  14.     },
  15.     // 修改
  16.     set(val){
  17.       console.log('有人修改了fullName',val)
  18.       firstName.value = val.split('-')[0]
  19.       lastName.value = val.split('-')[1]
  20.     }
  21.   })
  22.     //因为前面有了set方法,所以现在可读可写
  23.     fullName.vaule = 'li-si'
  24. </script>
复制代码
3.9. watch

情况一:监督ref界说的根本范例数据
监督函数watch中直接写根本范例,无需加 ‘.value’
  1. <template>
  2.   <div class="watch">
  3.     <h1>{{sum}}</h1>
  4.     <button @click="changeSum">加一</button>
  5.   </div>
  6. </template>
  7. <script lang="ts"  setup name="watch">
  8. import{ref,watch} from 'vue'
  9. let sum = ref(0)
  10. function changeSum(){
  11.     sum.value+=1
  12. }
  13. //直接监视
  14.     watch(sum,(newValue,oldValue)=>{
  15.     console.log('变化了')
  16. })
  17. //有返回值,返回值是一个结束监视函数
  18.     const stopWatch = watch(sum ,(newValue,oldValue)=>{
  19.     if(sum.value>10){
  20.         stopWatch()
  21.         }
  22. })
  23. </script>
复制代码
情况2: 监督ref界说的对象范例数据
默认当对象的某一个属性厘革时,不会触发监督函数回调,只有当整个对象厘革(所在值厘革)才会相应,但是可以开启深度监督
  1.   /*
  2.     监视,情况一:监视【ref】定义的【对象类型】数据,监视的是对象的地址值,若想监视对象内部属性的变化,需要手动开启深度监视
  3.     watch的第一个参数是:被监视的数据
  4.     watch的第二个参数是:监视的回调
  5.     watch的第三个参数是:配置对象(deep、immediate等等.....)
  6.   */
  7.   watch(person,(newValue,oldValue)=>{
  8.     console.log('person变化了',newValue,oldValue)
  9.   },{deep:true})
复制代码
情况3:监督reactive界说的对象范例数据
        和情况2类似,但是默认开启深度监督

情况4:监督ref和reactive界说的对象范例中的某个属性
1.若该属性不是对象范例,须要写成函数情势
2.是对象范例,可以直接写
  1. // 监视,情况四:监视响应式对象中的某个属性,且该属性是基本类型的,要写成函数式
  2.    watch(()=> person.name,(newValue,oldValue)=>{
  3.     console.log('person.name变化了',newValue,oldValue)
  4.   })
  5.   // 监视,情况四:监视响应式对象中的某个属性,且该属性是对象类型的,可以直接写,也能写函数,更推荐写函数
  6.   watch(()=>person.car,(newValue,oldValue)=>{
  7.     console.log('person.car变化了',newValue,oldValue)
  8.   },{deep:true})
复制代码
情况5:监督多个属性
  1. // 监视,情况五:监视上述的多个数据
  2.   watch([()=>person.name,person.car],(newValue,oldValue)=>{
  3.     console.log('person.car变化了',newValue,oldValue)
  4.   },{deep:true})
复制代码
3.10. watchEffect

不消指明监督的属性,函数用到哪个监督哪个
  1. const stopWtach = watchEffect(()=>{
  2.     // 室温达到50℃,或水位达到20cm,立刻联系服务器
  3.     if(temp.value >= 50 || height.value >= 20){
  4.       console.log(document.getElementById('demo')?.innerText)
  5.       console.log('联系服务器')
  6.     }
  7.     // 水温达到100,或水位达到50,取消监视
  8.     if(temp.value === 100 || height.value === 50){
  9.       console.log('清理了')
  10.       stopWtach()
  11.     }
  12.   })
复制代码
3.11.标签的ref属性

差别组件的纵然有雷同的ref也不会辩说
定位到组件上,如果想要取消掩护机制,袒露属性可以用defineExpose
  1. <!-- 子组件Person.vue中要使用defineExpose暴露内容 -->
  2. <script lang="ts" setup name="Person">
  3.   import {ref,defineExpose} from 'vue'
  4.         // 数据
  5.   let name = ref('张三')
  6.   let age = ref(18)
  7.   /****************************/
  8.   /****************************/
  9.   // 使用defineExpose将组件中的数据交给外部
  10.   defineExpose({name,age})
  11. </script>
复制代码
增补:接口界说和使用
界说
  1. // 定义一个接口,限制每个Person对象的格式
  2. export interface PersonInter {
  3. id:string,
  4. name:string,
  5.     age:number
  6.    }
  7.    
  8. // 定义一个自定义类型Persons
  9. export type Persons = Array<PersonInter>
复制代码
 使用
  1. import {type PersonInter} from './types'
  2.   import {type Persons} from './types'
  3.     let person:PersonInter = {id:'asyud7asfd01',name:张三',age:60}
  4.     let personList:Array<PersonInter> = [
  5.     {id:'asyud7asfd01',name:'张三',age:60},
  6.     {id:'asyud7asfd02',name:"李四',age:18},
  7.     {id: asyud7asfd03',name:'王五',age:5}]
  8.        let persons = reactive<Persons>([
  9.      {id:'e98219e12',name:'张三',age:18},
  10.       {id:'e98219e13',name:'李四',age:19},
  11.        {id:'e98219e14',name:'王五',age:20}
  12.      ])
复制代码
3.12. props

让父组件可以大概向子组件通报数据。
<h2 a="1+1" :b="1+1" c="x"  :d="x"  ref="qwe"></h2>
  1. <template>
  2. <div class="person">
  3. <ul>
  4.      <li v-for="item in list" :key="item.id">
  5.         {{item.name}}--{{item.age}}
  6.       </li>
  7.     </ul>
  8.    </div>
  9.    </template>
  10.   
  11. <script lang="ts" setup name="Person">
  12. import {defineProps} from 'vue'
  13. import {type PersonInter} from '@/types'
  14.   
  15.   // 第一种写法:仅接收
  16. const props = defineProps(['list'])
  17.   // 第二种写法:接收+限制类型
  18. const props = defineProps<{list:Persons}>()
  19.   
  20.   // 第三种写法:接收+限制类型+指定默认值+限制必要性
  21. let props = withDefaults(defineProps<{list?:Persons}>(),{
  22.        list:()=>[{id:'asdasg01',name:'小猪佩奇',age:18}]
  23.   })
  24.    console.log(props)
  25.   </script>
复制代码
3.12.生命周期 

注意:使用时间须要从vue中impoort
创建阶段:setup
挂载阶段:onBeforeMount、onMounted
更新阶段:onBeforeUpdate、onUpdated
卸载阶段:onBeforeUnmount、onUnmounted

3.13.自界说hook

 可以在src下创建hooks文件夹存放hook文件,定名一样寻常为“useXxx",把具有接洽的值和函数存放到一个文件夹
         比方
useSum.ts
  1. import {ref,onMounted} from 'vue'
  2. export default function(){
  3.   let sum = ref(0)
  4.   const increment = ()=>{
  5.     sum.value += 1
  6.   }
  7.   const decrement = ()=>{
  8.     sum.value -= 1
  9.   }
  10.   onMounted(()=>{
  11.     increment()
  12.   })
  13.   //向外部暴露数据
  14.   return {sum,increment,decrement}
  15. }       
复制代码
 useDog.ts
  1. import {reactive,onMounted} from 'vue'
  2. import axios,{AxiosError} from 'axios'
  3. export default function(){
  4.   let dogList = reactive<string[]>([])
  5.   // 方法
  6.   async function getDog(){
  7.     try {
  8.       // 发请求
  9.       let {data} = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
  10.       // 维护数据
  11.       dogList.push(data.message)
  12.     } catch (error) {
  13.       // 处理错误
  14.       const err = <AxiosError>error
  15.       console.log(err.message)
  16.     }
  17.   }
  18.   // 挂载钩子
  19.   onMounted(()=>{
  20.     getDog()
  21.   })
  22.        
  23.   //向外部暴露数据
  24.   return {dogList,getDog}
  25. }
复制代码
详细使用
  1. <template>
  2.   <h2>当前求和为:{{sum}}</h2>
  3.   <button @click="increment">点我+1</button>
  4.   <button @click="decrement">点我-1</button>
  5.   <hr>
  6.   <img v-for="(u,index) in dogList.urlList" :key="index" :src="(u as string)">
  7.   <span v-show="dogList.isLoading">加载中......</span><br>
  8.   <button @click="getDog">再来一只狗</button>
  9. </template>
  10. <script setup lang="ts">
  11.   import useSum from './hooks/useSum'
  12.   import useDog from './hooks/useDog'
  13.        
  14.   let {sum,increment,decrement} = useSum()
  15.   let {dogList,getDog} = useDog()
  16. </script>
复制代码


4.路由 

4.1.设置

router文件下设置
  1. import {createRouter,createWebHistory} from "vue-router"
  2. import Home from '@/pages/Home.vue'
  3. import News from '@/pages/News.vue'
  4. import About from '@/pages/About.vue'
  5. const router = createRouter({
  6.     history:createWebHistory(),
  7.     routes:[
  8.         {
  9.             path:'/home'
  10.             component:Home
  11.    
  12.         },
  13.         {
  14.         }
  15. ]
  16. })
复制代码
main.ts文件
  1. import router from './router/index'
  2. app.use(router)
  3. app.mount('#app')
复制代码
App.vue文件
注意<RouterLink to=' '></RouterLink> 和<RouterView><RouterView>

  •         路由组件通常存放在pages 或 views文件夹,一样寻常组件通常存放在components文件夹。
  •         通过点击导航,视觉效果上“消散” 了的路由组件,默认是被卸载掉的,须要的时间再去挂载
  1. <template>
  2.   <div class="app">
  3.     <h2 class="title">Vue路由测试</h2>
  4.     <!-- 导航区 -->
  5.     <div class="navigate">
  6.       <RouterLink to="/home" active-class="active">首页</RouterLink>
  7.       <RouterLink to="/news" active-class="active">新闻</RouterLink>
  8.       <RouterLink to="/about" active-class="active">关于</RouterLink>
  9.     </div>
  10.     <!-- 展示区 -->
  11.     <div class="main-content">
  12.       <RouterView></RouterView>
  13.     </div>
  14.   </div>
  15. </template>
  16. <script lang="ts" setup name="App">
  17.   import {RouterLink,RouterView} from 'vue-router'  
  18. </script>
复制代码
4.2.路由器工作模式


history模式
长处:URL更加雅观,不带有#,更靠近传统的网站URL。
缺点:后期项目上线,须要服务端共同处理惩罚路径题目,否则革新会有404错误。
  1. const router = createRouter({
  2.           history:createWebHistory(), //history模式
  3.           /******/
  4. })
复制代码
hash模式
长处:兼容性更好,由于不须要服务器端处理惩罚路径。
缺点:URL带有#不太雅观,且在SEO优化方面相对较差
  1. const router = createRouter({
  2.           history:createWebHashHistory(), //hash模式
  3.           /******/
  4. })
复制代码
4.3.to的两种写法 
  1. <RouterLink to="/home">主页</RouterLink>
  2. <RouterLink to="{path:'/home'}">主页</RouterLink>
复制代码
4.4.定名路由

在路由表中添加name属性
可以通过<RouterLink to="{name:'zhuye'}"><RouterLink>直接跳转 

 4.5.嵌套路由(子路由)

在一个路由下面增长children属性,再写入其他路由
  1. const router = createRouter({
  2.   history:createWebHistory(),
  3.         routes:[
  4.                 {
  5.                         name:'zhuye',
  6.                         path:'/home',
  7.                         component:Home
  8.                 },
  9.                 {
  10.                         name:'xinwen',
  11.                         path:'/news',
  12.                         component:News,
  13.                         children:[
  14.                                 {
  15.                                         name:'xiang',
  16.                                         path:'detail',
  17.                                         component:Detail
  18.                                 }
  19.                         ]
  20.                 },
  21.                 {
  22.                         name:'guanyu',
  23.                         path:'/about',
  24.                         component:About
  25.                 }
  26.         ]
  27. })
  28. export default router
复制代码
4.6.路由传参

query参数


  •         通报参数
    1. <!-- 跳转并携带query参数(to的字符串写法) -->
    2. <router-link to="/news/detail?a=1&b=2&content=欢迎你">
    3.         跳转
    4. </router-link>
    5.                                
    6. <!-- 跳转并携带query参数(to的对象写法) -->
    7. <RouterLink
    8.   :to="{
    9.     //name:'xiang', //用name也可以跳转
    10.     path:'/news/detail',
    11.     query:{
    12.       id:news.id,
    13.       title:news.title,
    14.       content:news.content
    15.     }
    16.   }"
    17. >
    18.   {{news.title}}
    19. </RouterLink>
    复制代码
  •         吸收参数:
    1. import{useRoute} from 'vue-router'
    2. const route = useRoute()
    3. console.log(route.query)
    复制代码
params参数


  •         通报参数
    1. <!-- 跳转并携带params参数(to的字符串写法) -->
    2. <RouterLink :to="`/news/detail/001/新闻001/内容001`">{{news.title}}</RouterLink>
    3.                                
    4. <!-- 跳转并携带params参数(to的对象写法) -->
    5. <RouterLink
    6.   :to="{
    7.     name:'xiang', //用name跳转
    8.     params:{
    9.       id:news.id,
    10.       title:news.title,
    11.       content:news.title
    12.     }
    13.   }"
    14. >
    15.   {{news.title}}
    16. </RouterLink>
    复制代码
  •         吸收参数:
    1. import {useRoute} from 'vue-router'
    2. const route = useRoute()
    3. // 打印params参数
    4. console.log(route.params)
    复制代码
3.占位
  1. [name:'xinwen',
  2.     path:'/news',
  3.     component:News,
  4.     children:[
  5.         name:'xiang',
  6.            //占位!!!!
  7.         path: 'detail/:id/:title/:content',
  8.         component:Detail[
  9.   ]
复制代码
注意
备注1:通报params参数时,若使用to的对象写法,必须使用name设置项,不能用path。
备注2:通报params参数时,须要提前在规则中占位。


4.7. 路由的prop设置

使传参更优雅
  1. {
  2.         name:'xiang',
  3.         path:'detail/:id/:title/:content',
  4.         component:Detail,
  5.   // props的对象写法,作用:把对象中的每一组key-value作为props传给Detail组件
  6.   // props:{a:1,b:2,c:3},
  7.   // props的布尔值写法,作用:把收到了每一组params参数,作为props传给Detail组件
  8.   // props:true
  9.   
  10.   // props的函数写法,作用:把返回的对象中每一组key-value作为props传给Detail组件
  11.   props(route){
  12.     return route.query
  13.   }
  14. }
复制代码
 4.8.replace属性

控制路由跳转时利用欣赏器汗青记载模式

  •         欣赏器的汗青记载有两种写入方式:分别为push和replace:

    • push是追加汗青记载(默认值)。
    • replace是更换当前记载。
           
  •         开启replace模式:
    1. <RouterLink replace .......>News</RouterLink>
    复制代码

 4.9.编程式导航

在vue3中,$route和$router变成了两个hook,就是在导航区以外的地方通过一些利用实现路由跳转
  1. <template>
  2.   <div>
  3.     当前路由路径: {{ route.path }}
  4.   </div>
  5. </template>
  6. <script setup>
  7. import { useRoute } from 'vue-router';
  8. const route = useRoute();
  9. </script>
复制代码
  1. <template>
  2.   <button @click="goToHome">前往首页</button>
  3. </template>
  4. <script setup>
  5. import { useRouter } from 'vue-router';
  6. const router = useRouter();
  7. const goToHome = () => {
  8.   router.push('/home');
  9. };
  10. </script>
复制代码
增补知识点,定时使命 
  1. //挂载后,页面三秒自动跳转
  2. onMounted(()=>{
  3. router.push('/home')
  4. },3000)
复制代码
 4.10.重定向

将特定的路径,重新定向到已经有的路由,通过redirect
  1. [
  2.     path:'/',
  3.     redirect:'/about'
  4. ]
复制代码
5.pinia

5.1.搭建情况

step1:npm install pinia
step2:利用 src/main.ts
  1. import { createApp } from 'vue'
  2. import App from './App.vue'
  3. /* 引入createPinia,用于创建pinia */
  4. import { createPinia } from 'pinia'
  5. /* 创建pinia */
  6. const pinia = createPinia()
  7. const app = createApp(App)
  8. /* 使用插件 */{}
  9. app.use(pinia)
  10. app.mount('#app')
复制代码
 5.2.存储+读取数据

store是pinia的一个功能部件,我的明白是可以提取公共的数据大概函数供其他组件使用
在src/store中创建文件
详细编码src/store/count.ts
  1. //引入defineStore用于创建store
  2. import {defineStore} from 'pinia'
  3. //定义并暴露一个store
  4. export const useCountstore = defineStore('count',{
  5.     //动作
  6.     actions:{},
  7.     //状态
  8.     state(){
  9.     return {
  10.         sum:6
  11.         }
  12.     },
  13.     //计算
  14.     getters:{}
  15. })
复制代码
使用 
  1. <template>
  2.     <h1>当前的求和为:{{countStore.sum}}</h1>
  3. </template>
  4. <script setup lang="ts" name="count">
  5. //引入对应的useXxxStore
  6. import {useCountStore} from '@/src/store/count'
  7. //调用对应的useXxxStore得到对应的store
  8. const countStore = useCountStore()
  9. </script>
复制代码
5.3.修改数据

1.直接在调用的地方加(vue3特性)
countStore.sum = 666
2.批量修改,通过patch函数
countStore.$patch({
sum:999
age:111        
})
3.通过store内里的action创建修改store数据的方法
  1. import {defineStore} from 'pinia'
  2. export const useCountStore = defineStore('count' ,{
  3. actions: {
  4.     //加
  5.     increment(value:number) {
  6.       if (this.sum < 10) {
  7.         //操作countStore中的sum
  8.         this.sum += value
  9.       }
  10.     },
  11.     //减
  12.     decrement(value:number){
  13.       if(this.sum > 1){
  14.         this.sum -= value
  15.       }
  16.     }
  17.   },
  18.   /*************/
  19. })
复制代码
 5.4.storeToRefs

借助storeToRefs会将store中的数据转化为ref对象,而store中的函数稳定
通过toRefs会将store的全部都转化为ref对象,包罗函数
  1. <template>
  2.         <div class="count">
  3.                 <h2>当前求和为:{{sum}}</h2>
  4.         </div>
  5. </template>
  6. <script setup lang="ts" name="Count">
  7.   import { useCountStore } from '@/store/count'
  8.   /* 引入storeToRefs */
  9.   import { storeToRefs } from 'pinia'
  10.         /* 得到countStore */
  11.   const countStore = useCountStore()
  12.   /* 使用storeToRefs转换countStore,随后解构 */
  13.   const {sum} = storeToRefs(countStore)
  14. </script>
复制代码
5.5.getters

当state中的数据,须要颠末处理惩罚后再使用时,可以使用getters设置。{感觉有点鸡肋,在state不是也可以吗},,记得在使用时和state一起import
  1. // 引入defineStore用于创建store
  2. import {defineStore} from 'pinia'
  3. // 定义并暴露一个store
  4. export const useCountStore = defineStore('count',{
  5.   // 动作
  6.   actions:{
  7.     /************/
  8.   },
  9.   // 状态
  10.   state(){
  11.     return {
  12.       sum:1,
  13.       school:'atguigu'
  14.     }
  15.   },
  16.   // 计算
  17.   getters:{
  18.     bigSum:(state):number => state.sum *10,
  19.     upperSchool():string{
  20.       return this. school.toUpperCase()
  21.     }
  22.   }
  23. })
复制代码
5.6.$subscribe

监督厘革,和watch类似
mutate:关于状态厘革的信息
state:最新的state对象
  1. talkStore.$subscribe((mutate,state)=>{
  2.   console.log('LoveTalk',mutate,state)
  3. })
复制代码
 5.7.store组合式写法

将数据和方法写在一个函数内里,别忘了末了须要return交出去
  1. import {defineStore} from 'pinia'
  2. import { ref } from 'vue';
  3. export const useSumStore = defineStore('sum' ,()=>{
  4. const sum = ref(999)
  5. function add(){
  6.     sum.value++
  7. }
  8. return {sum,add}
  9. })
复制代码
6.组件通讯

6.1.props

父传子,引入子组件的时间直接附带须要通报的值
父传子
  1. <template>
  2.   <div class="father">
  3.     <h3>父组件,</h3>
  4.                 <Child :car="car" :getToy="getToy"/>
  5.   </div>
  6. </template>
  7. <script setup lang="ts" name="Father">
  8.         import Child from './Child.vue'
  9.         import { ref } from "vue";
  10.         // 数据
  11.         const car = ref('奔驰')
  12. </script>
复制代码
子担当,通过defineProps
  1. defineProps(['car'])
复制代码
 
 子传父,须要通过父通报的函数把值通报给父,就像父界说了一个构造函数,但是由子来调用这个构造函数从而获取详细的值
子调用父的函数
  1. <template>
  2.   <div class="child">
  3.     <h3>子组件</h3>
  4.                 <h4>我的玩具:{{ toy }}</h4>
  5.                 <button @click="getToy(toy)">玩具给父亲</button>
  6.   </div>
  7. </template>
  8. <script setup lang="ts" name="Child">
  9.         import { ref } from "vue";
  10.         const toy = ref('奥特曼')
  11.        
  12.         defineProps(['getToy'])
  13. </script>
复制代码
父通过子调用函数获取值
  1. <template>
  2.   <div class="father">
  3.     <h3>父组件,</h3>
  4.                 <h4>儿子给的玩具:{{ toy }}</h4>
  5.                 <Child :getToy="getToy"/>
  6.   </div>
  7. </template>
  8. <script setup lang="ts" name="Father">
  9.         import Child from './Child.vue'
  10.         import { ref } from "vue";
  11.         // 数据
  12.         const toy = ref()
  13.         // 方法
  14.         function getToy(value:string){
  15.                 toy.value = value
  16.         }
  17. </script>
复制代码
6.2 自界说变乱

我以为这又有点像一种高级的监听机制,父组件在子组件绑定一个变乱并声明一个回调函数,只要子组件发生这个变乱,父组件就会调用这个回调函数,而且还会受到子组件的值

重要是注意一些格式,子组件在担当变乱的时间 通过const emits = defineEmits(['send-toy']) 
使用时通过emit('send-toy' ,toy)来相应变乱,从而时父组件担当变乱附带的值并实行回调函数
 
6.3mitt

        好像一个第三方的自界说变乱功能,吸收数据者界说变乱,提供数据者触发变乱,相比自界说变乱,更“自由机动”
step1:npm i mitt
step2:在util文件夹中创建emitter.ts
  1. //引入emit
  2. import mitt from "mitt"
  3. //创建emitter
  4. const emitter = mitt()
  5. //创建并暴露mitt
  6. export default emitter
复制代码
 绑定变乱
emitter.on('send-toy' (value)=>{ console.log("担当value并实行回调函数")})
触发变乱
emitter.emit('send-toy' ,666)
注意,在组件卸载时间,只管解绑当前组件绑定的变乱,制止斲丧内存
onUmMounted(()=>{  emitter.off('send-toy')})


6.4.v-model

v-model的本质
  1. <!-- 使用v-model指令 -->
  2. <input type="text" v-model="userName">
  3. <!-- v-model的本质是下面这行代码 -->
  4. <input
  5.   type="text"
  6.   :value="userName"
  7.   @input="userName =(<HTMLInputElement>$event.target).value"
  8. >
复制代码
 
6.5.$attrs

通常用于父与孙的通报,但是中心的桥梁是子组件,
详细分析:$attrs是一个对象,包罗全部父组件传入的标签属性。(个人明白:动态的资源聚集)
注意:$attrs会打扫props中已经声明的属性(相当于已经被用了),但把剩下的仍在$attrs中
父组件
  1. <template>
  2.   <div class="father">
  3.     <h3>父组件</h3>
  4.                 <Child :a="a" :b="b" :c="c" :d="d" v-bind="{x:100,y:200}" :updateA="updateA"/>
  5.   </div>
  6. </template>
  7. <script setup lang="ts" name="Father">
  8.         import Child from './Child.vue'
  9.         import { ref } from "vue";
  10.         let a = ref(1)
  11.         let b = ref(2)
  12.         let c = ref(3)
  13.         let d = ref(4)
  14.         function updateA(value){
  15.                 a.value = value
  16.         }
  17. </script>
复制代码
子组件
  1. <template>
  2.         <div class="child">
  3.                 <h3>子组件</h3>
  4.                 <GrandChild v-bind="$attrs"/>
  5.         </div>
  6. </template>
  7. <script setup lang="ts" name="Child">
  8.         import GrandChild from './GrandChild.vue'
  9. </script>
复制代码
孙组件
  1. <template>
  2.         <div class="grand-child">
  3.                 <h3>孙组件</h3>
  4.                 <h4>a:{{ a }}</h4>
  5.                 <h4>b:{{ b }}</h4>
  6.                 <h4>c:{{ c }}</h4>
  7.                 <h4>d:{{ d }}</h4>
  8.                 <h4>x:{{ x }}</h4>
  9.                 <h4>y:{{ y }}</h4>
  10.                 <button @click="updateA(666)">点我更新A</button>
  11.         </div>
  12. </template>
  13. <script setup lang="ts" name="GrandChild">
  14.         defineProps(['a','b','c','d','x','y','updateA'])
  15. </script>
复制代码
6.6.$refs,$parent


  •         概述:

    • $refs用于 :父→子。
    • $parent用于:子→父。
                   
  •         原理如下:
            属性分析$refs值为对象,包罗全部被ref属性标识的DOM元素或组件实例。$parent值为对象,当前组件的父组件实例对象。
但是须要用 defineExpose暴袒露去,使用时间不须要显式通报,直接用

6.7. provide和inject

  • 在先人组件中通过provide设置向后代组件提供数据
  • 在后代组件中通过inject设置来声明吸收数据
在父组件中,通过provide提供数据
  1. <template>
  2.   <div class="father">
  3.     <h3>父组件</h3>
  4.     <Child/>
  5.   </div>
  6. </template>
  7. <script setup lang="ts" name="Father">
  8.   import Child from './Child.vue'
  9.   import { ref,reactive,provide } from "vue";
  10.   // 数据
  11.   let money = ref(100)
  12.   let car = reactive({
  13.     brand:'奔驰',
  14.     price:100
  15.   })
  16.   // 用于更新money的方法
  17.   function updateMoney(value:number){
  18.     money.value += value
  19.   }
  20.   // 提供数据
  21.   provide('moneyContext',{money,updateMoney})
  22.   provide('car',car)
  23. </script>
复制代码
后代中通过inject担当数据,只管代码有默认值
  1. <template>
  2.   <div class="grand-child">
  3.     <h3>我是孙组件</h3>
  4.     <h4>资产:{{ money }}</h4>
  5.     <h4>汽车:{{ car }}</h4>
  6.     <button @click="updateMoney(6)">点我</button>
  7.   </div>
  8. </template>
  9. <script setup lang="ts" name="GrandChild">
  10.   import { inject } from 'vue';
  11.   // 注入数据
  12. let {money,updateMoney} = inject('moneyContext',{money:0,updateMoney:(x:number)=>{}})
  13.   let car = inject('car')
复制代码
 
 6.7.solt

1.默认插槽

父组件在声明子组件时会通报一些供以表现的数据,这时间用插槽为这些数据的表现提供位置
  1. 父组件中:
  2.         <Category title="今日热门游戏">
  3.           <ul>
  4.             <li v-for="g in games" :key="g.id">{{ g.name }}</li>
  5.           </ul>
  6.         </Category>
  7. 子组件中:
  8.         <template>
  9.           <div class="item">
  10.             <h3>{{ title }}</h3>
  11.             <!-- 默认插槽 -->
  12.             <slot></slot>
  13.           </div>
  14.         </template>
复制代码
2.具名插槽

指定插在哪个位置,通过v-slot大概#slot
  1. 父组件中:
  2.         <Category title="今日热门游戏">
  3.           <template v-slot:s1>
  4.             <ul>
  5.               <li v-for="g in games" :key="g.id">{{ g.name }}</li>
  6.             </ul>
  7.           </template>
  8.           <template #s2>
  9.             <a href="">更多</a>
  10.           </template>
  11.         </Category>
  12. 子组件中:
  13.         <template>
  14.           <div class="item">
  15.             <h3>{{ title }}</h3>
  16.             <slot name="s1"></slot>
  17.             <slot name="s2"></slot>
  18.           </div>
  19.         </template>
复制代码
3.作用域插槽

数据在组件的自身,但根据数据天生的结构须要组件的使用者来决定
子组件通过在插槽声明的位置声明数据,由使用者利用
  1. 父组件中:
  2.       <Game v-slot="params">
  3.       <!-- <Game v-slot:default="params"> -->
  4.       <!-- <Game #default="params"> -->
  5.         <ul>
  6.           <li v-for="g in params.games" :key="g.id">{{ g.name }}</li>
  7.         </ul>
  8.       </Game>
  9. 子组件中:
  10.       <template>
  11.         <div class="category">
  12.           <h2>今日游戏榜单</h2>
  13.           <slot :games="games" a="哈哈"></slot>
  14.         </div>
  15.       </template>
  16.       <script setup lang="ts" name="Category">
  17.         import {reactive} from 'vue'
  18.         let games = reactive([
  19.           {id:'asgdytsa01',name:'英雄联盟'},
  20.           {id:'asgdytsa02',name:'王者荣耀'},
  21.           {id:'asgdytsa03',name:'红色警戒'},
  22.           {id:'asgdytsa04',name:'斗罗大陆'}
  23.         ])
  24.       </script>
复制代码
7.其他API

7.1.shallowRef 与 shallowReactive 

绕开深度相应,提拔性能


shallowRef

  •         作用:创建一个相应式数据,但只对顶层【属性】举行相应式处理惩罚。
  •         用法:
    1. let myVar = shallowRef(initialValue);
    复制代码
  •         特点:只跟踪引用值的厘革,不关心值内部的属性厘革。
shallowReactive

  •         作用:创建一个浅层相应式对象,只会使对象的【最顶层属性】变成相应式的,对象内部的嵌套属性则不会变成相应式的
  •         用法:
    1. const myObj = shallowReactive({ ... });
    复制代码
  •         特点:对象的顶层属性是相应式的,但嵌套对象的属性不是。
 
7.2.readonly 与 shallowReadonly

readonly

  •         作用:用于创建一个对象的深只读副本。
  •         用法:
    1. const original = reactive({ ... });
    2. const readOnlyCopy = readonly(original);
    复制代码
  •         特点:

    • 对象的全部嵌套属性都将变为只读。
    • 任何实验修改这个对象的利用都会被制止(在开辟模式下,还会在控制台中发出告诫)。
           
  •         应用场景:

    • 创建不可变的状态快照。
    • 掩护全局状态或设置不被修改。
           
shallowReadonly

  •         作用:与 readonly 类似,但只作用于对象的顶层属性。
  •         用法:
    1. const original = reactive({ ... });
    2. const shallowReadOnlyCopy = shallowReadonly(original);
    复制代码
  •         特点:

    •                 只将对象的顶层属性设置为只读,对象内部的嵌套属性仍然是可变的。
    •                 实用于只需掩护对象顶层属性的场景。
           

7.3. toRaw 与 markRaw

toRaw
        作用:用于获取一个相应式对象的原始对象, toRaw 返回的对象不再是相应式的,不会触发视图更新。
markRaw
        作用:标记一个对象,使其永久不会变成相应式的。
  1. import { reactive,toRaw,markRaw,isReactive } from "vue";
  2. /* toRaw */
  3. // 响应式对象
  4. let person = reactive({name:'tony',age:18})
  5. // 原始对象
  6. let rawPerson = toRaw(person)
  7. /* markRaw */
  8. let citysd = markRaw([
  9.   {id:'asdda01',name:'北京'},
  10.   {id:'asdda02',name:'上海'},
  11.   {id:'asdda03',name:'天津'},
  12.   {id:'asdda04',name:'重庆'}
  13. ])
复制代码
7.4.customRef

自界说的ref,可以实现特别的逻辑,一样寻常把自界说的ref封装为一个hook
  1. import {customRef } from "vue";
  2. export default function(initValue:string,delay:number){
  3.   let msg = customRef((track,trigger)=>{
  4.     let timer:number
  5.     return {
  6.       get(){
  7.         track() // 告诉Vue数据msg很重要,要对msg持续关注,一旦变化就更新
  8.         return initValue
  9.       },
  10.       set(value){
  11.         clearTimeout(timer)
  12.         timer = setTimeout(() => {
  13.           initValue = value
  14.           trigger() //通知Vue数据msg变化了
  15.         }, delay);
  16.       }
  17.     }
  18.   })
  19.   return {msg}
  20. }
复制代码
8.Vue3新组件 

8.1.Teleport

将窗口移动到指定位置
  1. <teleport to='body' >
  2.     <div class="modal" v-show="isShow">
  3.       <h2>我是一个弹窗</h2>
  4.       <p>我是弹窗中的一些内容</p>
  5.       <button @click="isShow = false">关闭弹窗</button>
  6.     </div>
  7. </teleport>
复制代码
 
8.2.Suspense


  • 等候异步组件时渲染一些额外内容,让应用有更好的用户体验
    1. <template>
    2.     <div class="app">
    3.         <h3>我是App组件</h3>
    4.         <Suspense>
    5.             //异步组件加载完成后显示内容
    6.           <template v-slot:default>
    7.             <Child/>
    8.           </template>
    9.             
    10.         //异步组件加载过程中显示内容,加载之后消失
    11.           <template v-slot:fallback>
    12.             <h3>加载中.......</h3>
    13.           </template>
    14.         </Suspense>
    15.     </div>
    16. </template>
    复制代码



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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表