type
status
date
slug
summary
tags
category
icon
password

基于Vite创建

以前Vue2项目基本上是通过vue-cli(是一款脚手架,用webpack创建vue项目)来创建的,现在Vue3多是使用vite来创建项目。
  • 支持ts开箱即用
  • 按需编译
  • create-vue 是 Vue3 的专用脚手架,使用 vite 创建 Vue3 的项目,也可以选择安装需要的各种插件,使用更简单
  • 用npm引入vite
  • 输入项目名称
  • 选择vue项目
  • 选择vue-ts(或者是选择语言,选TypeScript)
  • 此时已经创建完毕

工程结构

env.d.ts
  • /// <reference types="vite/client" />
    • 让ts能够识别.ts以外的文件
index.html
  • 入口文件
main.ts
  • import { createApp } from 'vue’ 引入创建应用的工具
  • import App from './App.vue' 引入根组件
  • app.mount(’#id’) 将应用挂载在index.html中,id为id的div标签里

OptionAPI & CompositionAPI

  • Vue2是选项式API,而Vue3是组合式API
    • Vue2数据、方法、计算属性是分散在data、methods、computed中的。如果要新增一个需求,就需要分别修改这几个选项,不便于维护和复用
    • 组合式API可以让功能相关的代码更有序地组织在一起

setup

  • 是Vue3中一个新的配置项,值是一个函数,compositionAPI所用到的数据、方法、计算属性、监视等均配置在setup中
  • OptionalAPI和setup配置项是可以同时存在的
    • setup里面的数据比data里面的数据先配置,所以data里面可以使用setup里面的变量(用this.xxx引用)
    • 但是setup 里面不能使用data里面的数据

setup语法糖

在标签里面写setup,就不用写setup() {return xxx}了

响应式数据

ref

定义响应式变量
  • 返回值:一个RefImpl的实例对象,即ref对象或ref,ref的value属性是响应式的
  • 用xxx.value = yyy来修改它的值
定义对象类型的响应式数据
  • RefImpl对象的value属性此时是一个Proxy对象
  • 实际上ref是在reactive的基础上处理对象类型的数据的

reactive

  • 借助proxy实现
  • 从原对象生成响应式对象
  • 直接用xxx.属性修改变量的属性,而不用通过value

ref和reactive对比

  • ref创建的对象必须使用.value来访问其值
  • reactive重新分配一个对象,会失去响应式(可以使用Object.assign去整体替换
  • 但是ref就可以直接重新分配对象且不会失去响应式
总结:
  • 基本类型的响应式数据:ref
  • 层级不深的响应式对象:ref和reactive都可以
  • 层级较深的响应式对象:reactive

toRefs和toRef

解构响应式对象的属性,并且解构出来的变量也具有响应式
如果直接解构响应式的对象,结构出来的变量将丢失响应式!!!!

toRefs

  • 把对象结构为ref类型的响应式变量,这样结构出来的变量也是响应式的ref类型
  • 可以通过修改name来修改person.name,name有点像指针的作用

toRef

  • 只取响应式对象的一个属性

computed计算属性

  • 有缓存,一样的数据只会计算一次;普通的方法来实现计算的话调用几次就会计算几次
  • 只有在计算属性依赖的属性发生变化时,才会重新计算
  • 返回的是一个只读的值,不能直接修改res
    • 使用getter和setter来修改

watch监视

监视以下四种数据的变化:
  • ref定义的数据
    • 回调函数应有两个参数
    • 基本类型数据
      • 监视的是value是否变化,但监视的是refImpl类型的数据
      • vue3的watch终止监听,只需要将watch赋值给一个变量,当达到条件调用watch赋值的那个变量就可以终止监听了。
    • 对象类型数据
      • 监视的是对象的地址值(数据整个被替换),如果想监听对象内部的数据,要手动开启深度监视
      • watch的第三个参数
  • reactive定义的数据
    • 默认开启了深度监视
    • newValue和oldValue是相同的,因为reactive创建的变量就算值变了地址也相同
  • 函数返回一个值(getter函数)
    • 监视响应式对象中的某个属性,且该属性是基本数据类型的,要写成函数式
      • 监视响应式对象中的某个属性,并且该属性是对象时,要写函数式+开启深度监视(开启后才可以监视该属性的属性的变化)
    • 一个包含上述内容的数组

    watchEffect

    • 立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行该函数
      • 不用写明要监视的变量或对象
      • 回调函数在一开始就会执行一次
      • 回调函数用到的变量发生变化时会执行一次

    标签的ref属性

    之前习惯用id来获取一个html标签然后用js改它的值,但是vue里面组件太多可能会出现多个组件里面的不同标签不小心就被命名了同一个id,然后getElementById的时候就会出问题,就可以用ref来解决这个问题。
    之前写的积分商城数据大屏举例:
    就可以实现类似于局部变量的东西
    局部样式则可以这样实现:这样定义的样式就不会选中其他组件里面的标签
    • 如果在组件标签上面写ref,得到的就是组件实例

    生命周期、钩子/生命周期函数

    Vue中实例从创建到销毁的过程就是生命周期,即指从创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程。
    💡
    DOM DOM(Document Object Model)即文档对象模型,是W3C制定的标准接口规范,是一种处理HTML和XML文件的标准API。 DOM提供了对整个文档的访问模型,将文档作为一个树形结构,树的每个结点表示了一个HTML标签或标签内的文本项。 DOM模型不仅描述了文档的结构,还定义了结点对象的行为,利用对象的方法和属性,可以方便地访问、修改、添加和删除DOM树的结点和内容。 DOM的作用就是为了让JavaScript可以对文档中的标签、属性、内容等进行 访增删改 操作。

    Vue2

    创建:
    • 创建前:beforeCreate
    • 创建完毕:created
    挂载:
    • 挂载前:beforeMount
    • 挂载完毕:mounted
    更新:
    • 更新前:beforeUpdate
    • 更新完毕:updated
    销毁:
    • 销毁前:beforeDestroy
    • 销毁完毕:destroyed

    Vue3

    创建:
    创建前和创建完毕合并为setup函数
    挂载:
    生命周期函数需要import引入,挂载前(onBeforeMount)和挂载完毕(onMounted)都是在Vue2的基础上加个on
    挂载完毕后,会调用onMounted指定的回调函数,而不是调用onMounted
    更新:
    生命周期函数跟挂载一样,也是前面加一个on
    卸载:
    • 卸载前:onBeforeUnmount
    • 卸载完毕:onUnmounted

    父子组件的生命周期

    按照Vue的解析流程来理解,有点像深度搜索:
    先看index.html → 发现App.vue → 发现里面引入了子组件 → 解析子组件 → 继续解析父组件
    父:beforeCreate 首先初始化父组件 父:created 父组件挂载数据 父:beforeMounte 父组件开始挂载dom,tpl里遇到子组件 子:beforeCeate 子组件开始挂载数据 子:created 子组件数据挂载成功 子:beforeMount 子组件开始挂载dom 子:mounted 子组件dom挂载结束 父:mounted 父组件dom挂载结束 父:beforeUpdate 下面开始类似于dom事件流 子:beforeUpdate 子:updated 父:updated 父:beforeDestory 子:beforeDestory 子:destroyed 父:destoryed

    自定义Hooks

    💡
    自定义Hooks是一种函数,它接受一些参数,并返回一个或多个响应式的数据和方法。这些Hooks可以包含任意逻辑,如数据获取、状态管理、副作用处理等,而且可以在多个组件中进行共享和复用。通过使用自定义Hooks,我们可以将组件中的共享逻辑提取出来,使得代码更加清晰、可维护性更高。
    就比如说,实现一个功能需要好几个function,但是如果将这些function都混在scripts里面,就跟vue2没有区别了(mixin),因此需要将这好几个function直接封装以实现特定功能——hoos
    hooks实际上就是一个js或者ts文件,但是命名一般叫useXXX
    调用钩子:
    常用的hooks:
    这个钩子需要一个参数url,因此使用它的时候也要传参

    路由

    route就是一条路由,它将一个URL路径和一个函数进行映射,例如:
    这就是两条路由,当访问 /users 的时候,会执行 getAllUsers() 函数;当访问 /users/count 的时候,会执行 getUsersCount() 函数。

    实现路由环境

    • 首先要从vue-router引入createRouter
    • 然后用createRouter创建路由。配置项:
      • history:
        • history 定义了路由使用的历史记录模式。
        • createWebHistory 使应用使用 HTML5 的 History API 来管理路由,使 URL 看起来干净、没有 # 符号。使用这种模式时,页面路径会显示成普通的 URL(例如:/home/about),而不会带有 #(如:/home 而不是 /#/home)。
        • 使用 createWebHistory 时,服务器需要进行配置,以防止直接访问页面时出现 404 错误。
      • routes:
        • 一个数组,即路由器(router)管理的路由(route)
        • 必须包含path、component
    • 在main.ts引入router,这样路由器才可以被整个程序使用
      • 规定不同路由对应的组件放在什么位置
        • 在components.d.ts中显式地定义了RouterView是一个全局组件 这段代码确保了 TypeScript 对 RouterView 这个全局组件有正确的类型支持,尽管在实际开发中,你不需要手动导入 RouterView
          • router-view 自动全局注册: 当你在应用中注册了 vue-router 后,vue-router 自动将 router-view 组件注册为全局组件。因此,在你的任何 Vue 组件中(例如 App.vue),你可以直接使用 <router-view /> 而不需要手动引入它。
        • 然后在App.vue中使用占位符,让Vue Router将对应的页面(组件)渲染到正确的位置

        实现页面的跳转

        • 用router-link来实现
          • 这就表示点击这个按钮时,跳转到name为create的路由对应的页面
          • 并且这个按钮的样式和文字可以在里面规定(不要那个span也可以,这里有是因为有图标要展示)
        • 激活按钮时的样式
          • .router-link-active 的自动添加
            • 当使用 Vue Router 的 router-link 组件时,Vue 会自动为与当前路由匹配的链接添加 .router-link-active 类。因此,不需要手动管理激活状态,Vue Router 会根据用户点击的路由自动处理。
          • 然后,CSS 中针对 .router-link-active 类定义的样式就会生效,改变按钮的背景色、文本颜色等,使得按钮的样式发生变化,提供用户点击后的视觉反馈。

        路由器工作模式

        • history模式
          • URL更美观,不带#
        • hash模式
          • 兼容性好,不需要服务器端处理路径

        参数

        普通的组件是可以用标签来传参的,而靠路由规则展示出来的组件的标签没有机会被写出来,所以需要特殊的方法来给这些组件传参

        query参数

        可以直接写在router-link的 :to 属性里面
        • 这样写了之后参数就会直接体现在url中
        • 接收参数
          • 在要接受参数的组件里面从vue-router引入useRoute
            route里面就会有传进来的query参数,并且将其整理为了一个对象
        • 将js的变量值作为参数,加反引号将里面的内容做成模板字符串,然后用${}嵌入js
          • 此时route里面的query就有个属性是a,值为vara.id并且是动态的
        第二种写法,更简洁易懂
        • 需要使用参数时将query属性给解构出来

          params参数

          也是直接采用query参数的第二种方式
          • 但是不能直接写path,只能写name,否则会被浏览器忽略!!!并且路由配置文件里面的path要写占位符
            • route/index.ts:
          • 在占位符后面加问号表示参数的必要性:id可传可不传

            路由的props配置

            • 将路由收到的所有params参数全部作为props传给路由组件
              • 只需要在路由配置里面加一行props:true,缺点是只能传params类型的参数不能传query类型的参数
                Scan组件:
            • 第二种写法:
              • 可以自己决定将什么作为props传给路由组件,可以传query也可以传params
                Scan组件跟第一种没有区别

            路由的replace属性

            push:往浏览器历史记录的栈里push一个(默认模式)
            replace:直接将历史记录里面的上一个给替换掉(按那个←的时候不会返回上一个页面)
            • router-link标签里面添加replace属性可以将路由变为replace模式

            编程式路由导航

            脱离<RouterLink>标签实现路由跳转
            • 在ts里面实现
              • 在html里面实现,点击按钮就跳转页面
                • 实现翻页:
              • 当然也可以@click之后调用一个函数,然后在ts里面跳转路由

              Pinia

              集中式状态管理:vue2用的vuex,vue3就可以用pinia了。多个组件共享数据有时候很方便
              • Pinia 是 Vuex4 的升级版,也就是 Vuex5
              • Pinia 极大的简化了Vuex的使用,是 Vue3的新的状态管理工具
              • Pinia 对 ts的支持更好,性能更优, 体积更小,无 mutations,可用于 Vue2 和 Vue3
              • Pinia支持Vue Devtools、 模块热更新和服务端渲染
              • 用npm安装pinia
              App.vue引入并创建:
              此时pinia环境已经搭建好了
              拿之前的todolist为例:
              store:从本地存储里面拿数据出来存到lists
              要用lists的地方:

              Pinia与响应式

              • Pinia 与 Vue 的响应式系统: Pinia 使用 Vue 的 reactive API(在 Vue 2 中,它依赖于 Vue.observable)将状态对象变成响应式的。这意味着当你修改 Pinia store 中的数据时,Pinia 会检测到数据的变化并自动触发更新,正如 Vue 处理组件 data 的响应式更新一样。
              • 直接修改 Pinia 的 store 状态: 在 Vue 2 中,Pinia 的 store 本质上是一个响应式对象,所有通过 state() 函数返回的数据都会自动转化为响应式数据。因此,你可以直接修改 store 中的属性,视图会自动更新,因为 Vue 响应式系统会跟踪这些变化。

              修改数据

              方法一:
              • 定义数据时使用响应式
              方法二:$patch,数据很多时批量修改
              • $patch
                方法三:actions
                • 是一个对象,里面放着很多动作函数
                • 写在store目录下的defineStore里面

                  插槽 slot

                  跟组件的复用有关系,有时候需要组件的样式一样但内容不一样,有了插槽就不用新写一个组件了

                  默认插槽

                  现在是想在action-button这个组件里面插入一个图标,插槽的作用就是告诉action-button组件,这个图标具体应该插入在什么位置
                  ActionButton.vue里面有这么一行,就可以告诉组件把它中间夹着的那些内容插入到哪里:

                  具名插槽

                  就是一个槽不够用,需要好几个槽——给槽命名:v-slot,只能放在template或者组件标签上
                  ActionButton.vue里面就有这么一行:

                  作用域插槽

                  就是子组件通过插槽将数据传给父组件
                  假设子组件那里有一个数组,叫games,父组件需要用这个数组
                  • 这样就通过插槽将games数组传出去了
                  父组件接收数据:
                  • 父组件接收到的params是一个对象,里面包含games和a,因此其实可以直接解构param里面的属性
                    • 这样就可以在父组件遍历子组件的数据了
                    • 实现数据子传父的就是作用域插槽

                    TS相关

                    接口 interface

                    • JavaScript: 使用原型链来实现对象的继承,没有类和接口的概念。
                    • TypeScript: 引入了类和接口,支持面向对象的编程风格。
                    定义一个接口的例子:

                    泛型

                    大写,规定变量是个啥,要写具体的内容。这里Array是个泛型

                    自定义类型

                    Rank就是一个数组类型,数组元素都是rank接口规定的样子。让代码更干净清晰
                     
                     
                    HTML/CSS/TS/JS链表
                    • Giscus