VUE3

VUE3

和angular相同,vue同样具有vue-cli来初始化工程,但官方更推荐的工具为Vite

Vite

Home | Vite中文网

Vite是新一代前端构建工具,在angular-cli和vue-cli中,都是使用webpack来作为构建工具的

# 创建基于vite的vue项目
npm create vue@latest

项目结构

  • .vscode:提供一些关于vscode的相关配置文件夹
  • public:页签图标存放位置文件夹
  • src:源代码文件文件夹
  • .gitignore:git忽略文件
  • env.d.ts:vue官方把所有可能会写的文件后缀放在这里供ts识别
  • index.html:程序的默认页面,也是程序的入口
  • package.json:工程管理文件
  • tsconfig:ts语言配置文件
  • vite.config.ts:vite配置文件

项目启动

项目启动的顺序是:index.html -> main.js -> App.vue

以一盆花来举例说明main.js

import './assets/main.css' // 样式 不重要

import { createApp } from 'vue' // 盆
import App from './App.vue' // 根

createApp(App).mount('#app') // 把根插在盆里,并把花摆在id为app的盒子中

在这里,如果只看一层结构的话,vue其实仅仅接管了id为app的div容器,其内容是通过组件来实现的


.vue

<template>
    <div class="app">
        <h1>你好呀</h1>
    </div>
</template>

<script lang="ts">
    export default{
        name:'App'
    }
</script>

<style>
.app {
    background-color: #ddd;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
</style>

Vue风格

  • Vue2的API设计是Options(配置)风格的
  • Vue3的API设计是Composition(组合)风格的

Options(配置)风格的弊端

Options类型的API,数据、方法、计算属性等,是分布在data、methods、computed中的,若想新增或者修改需求,及需要分别修改这些,不便于维护和复用


Setup

在Vue2中,选项式的配置在methods中的方法,在Vue3中都变成setup中的函数了

在Vue2中,选项式配置在data中的数据,在Vue3中的setup中简单的配置是无法做到响应式数据的

返回值

setup的返回值可以直接指定渲染的内容(渲染函数)

setup(){
    return () => "想要直接返回的内容"
}
语法

Vue3可以和Vue2的语法共存,且Vue2可以直接使用this获取setup中的数据,但Vue3不可以调用this

语法糖

在这里就相当于使用了一个setup函数,并且自动返回了style标签对中定义的内容

<style lang="ts" setup>
</style>

响应式

在Vue3中,setup中默认的数据不再是响应式数据,需要通过vue框架中的ref和reactive方法修饰

reactive修饰的对象不能直接赋值其他对象,但可以通过Object.assign()方法将新的对象赋值给响应式对象

let person = reactive({name:'xiaobai',age:'18'})

person = {name:"xiaoming", age:'19'} //这种方法是错误的

Object.assign(person,{name:"xiaohong", age:"20"}) //这种方法是正确的
toRefs

使用toRefs结构reactive的对象,其name和age和person对象进行深绑定

也就是说,操作name和age属性,就是直接操作person中的name和age

可以理解为 解构出来的name和age为person属性的代理对象

let person = reactive({name:'xiaobai',age:'18'})

let {name,age}  = toRefs(person)

计算属性

计算属性(computed properties)用于声明式地描述依赖于其他数据属性的值。计算属性会根据其依赖的数据自动更新,并且是基于它们的依赖进行缓存的,只有当依赖的数据发生变化时才会重新计算

在Vue2中,计算属性是一个选项式配置的属性,类似于data和methods的配置方式,属性名为Computed

在Vue3中,计算属性通过导入vue对象中的computed实现

需要注意的是,在vue中,计算属性默认是只读属性,可以通过单独配置getter和setter的方式将其变为可读可写


Watch

同计算属性一样,在vue2中,也是选项式配置的属性,在vue3中,使用组合式方式导入vue对象的watch使用

vue3中,watch能够监视四种数据

  • ref定义的数据
  • reactive定义的数据
  • 函数返回一个值(getter函数)
  • 一个包含上述内容的数组

ref定义的对象 ,如果想监视对象中属性的变化,需要开启深度监视

reactive定义的对象,默认开启了深度监视

如果想要监视对象中的某一个具体值,就需要用到函数返回一个值来监视(推荐使用箭头函数)

如果想要监视对象中的属性(对象类型的属性),就可以直接写,不需要使用getter函数的方式,但仍然推荐写成getter方式,再开启深度监视


组件的隔离

在vue中,一个页面是由多个组件构成的:例如组件A,组件B

那么组件A中存在css样式,组件B中也有相同的样式,他们可能都作用于统一元素上,这可能不是本意

我们想让样式隔离,组件A的样式及仅应用于组件A,组件B的样式仅应用于组件B,就需要在style标签上加一个scope属性即可

那么针对js而言,如果采用id来操作元素的方式,组件A和组件B可能会出现id冲突的情况

这时,我们可以通过ref属性,为html元素添加标识,在js中创建该容器并且使用即可

ref

对于ref而言,我们不仅仅可以将此属性加载html原生的标签元素上,还可以直接加在组件标签元素上,

这里的逻辑是子组件向父组件暴露数据

但默认会有组件保护机制,无法直接拿到组件中内容(拿到的是组件的对象,没有实际意义)

可以在被调用组件中引入defineExpose(),将指定数据暴露,再通过ref就可以拿到数据了

版本差距

在vue2中的选项式API中,标记ref的元素会被加入到vue对象中,this.$refs.属性; 通过这种方式可以直接找到该元素

在vue3中的组合式API中,标记ref的元素推荐使用ref创建一下该元素即可


Ts

使用Ts来写Vue会更加的优雅,并且贴近后端OOP思维

例如 ,在创建响应式数据时,我们可以通过泛型来定义响应式数据的类型

let personList = reactive<Persons>({
    
})
defineProps

这里的逻辑是从父组件向子组件传递数据

从vue对象中导入此属性,这条属性用于从父组件中接收传递过来的参数(通过在父组件中给子组件标签元素加入属性的方式传递)

在Ts中,可以通过泛型来约束父组件传递过来的参数类型,并判断可空性

// 传过来的属性list必须为Persons类型,且可空
defineProps<{list?:Persons}>()
withDefaults

从vue对象中导入此属性,这条属性用于指定默认值

withDefaults(defineProps<{list?:Persons}>(),{
  List:() => [{id:'1'},{name:'xiaobai'},{age:18}]  
})

注:define开头的函数为宏函数,在vue3中无需引入即可使用


生命周期

生命周期、生命周期函数、生命周期钩子,都指的是vue项目中在特定的时刻执行特定的函数

在Vue2中,生命周期有四个阶段,八个生命周期钩子

在Vue3中,生命周期有四个阶段,六个生命周期钩子

在创建阶段,Vue3中使用setup,所以去掉创建阶段一共六个


自定义hook

由vue2走向vue3的组合式,hooks可以真正的将组合式API进行逻辑分离的处理

相关的逻辑提取到单独的函数中,这些函数通常被称为“组合函数”或“自定义组合函数”

在这里,组合函数真正意义上的实现了封装这一OOP重要特性

hook文件一般以use开头

export default function(){
	// 将相关的逻辑提取到这里
    
    
    // 将数据和方法暴露给调用者
    return {}
}

TypeScript(TS)为组合函数提供了更好的支持,尤其是在确保数据类型一致性和减少运行时错误方面。

JavaScript(JS)虽然也可以使用组合函数,但由于缺乏静态类型检查,可能会导致一些潜在的问题,特别是在大型项目或跨文件使用时


路由

  1. 导航区和展示区的确定
  2. 请来路由器
  3. 指定路由的具体规则(路径-> 组件对应)
# 安装路由
npm i vue-router

路由组件一般放在pages或views文件夹,其他组件一般放在components文件夹内

  • 路由组件:是通过路由规则渲染出来的
  • 一般组件:是通过自己亲手写标签写出来的

在vue3中,路由的完成就是将一个组件卸载 -> 将一个组件挂载的一个过程


路由模式

history模式:更加美观,不带有#,更接近传统网站URL。缺点是后期项目上线时,需要服务端配合处理路径问题,否则会出现404错误

hash模式:兼容性更好,因为不需要服务器端处理路径。缺点是url中带有#不美观,且在SEO优化方面相对较差

需要在后端配置路由回退机制,在后端返回未找到资源后,由vue重新接管该请求,解析到指定路由下


to的写法

RouterLink的跳转按钮存在多种配置to属性的写法

<RouterLink to="/home" active-class="active">首页</RouterLink>
<RouterLink :to="{path : '/home'}" active-class="active">首页</RouterLink>
<RouterLink :to="{name : 'home'}" active-class="active">首页</RouterLink>

路由传参

路由传参有param和query两种方式

其中,都可以通过RouterLink的to属性,配置对象中的query属性和param属性来实现

需要注意的是,param属性传递时需要在path中配置占位,在RouteLink跳转时推荐使用name属性跳转

利用props

可以配置路由时增加一个属性:props:true

这个属性默认会将param参数转换为props,直接使用defineProps接受即可,但不会转化query参数

可以配置路由时重写props(){}方法,他会将返回值转换为defineProps,这样就可以显式的手动将query转化换

props(route){
    route.query
}

通过props方法转换参数后,其实就是将其组件传递参数的方式从路由传参转换为普通的组件传参

defineProps(['id', 'title', 'content'])

// 接受为一个对象
const props = defineProps(['id', 'title', 'content'])
replace和push

vue默认开启了push模式,即每次跳转后会形成历史记录,可以通过浏览器的后退来返回上一个路由

在RouterLink上加上replace,则路由成为replace模式,即无法通过浏览器的后悔来返回上一个路由


编程式路由

vue2中,编程式路由重复跳转会报错,但vue3修复了此问题

从vue-router对象中拿到属性useRouter,调用方法实现跳转,这里push和replace方法的参数与RouteLink中的to属性的值是一样的

import {userRouter} from 'vue-router'

const router = useRouter()

router.push() // 通过调用push的方式实现路由跳转
router.replace() // 通过调用replace的方式实现路由跳转

集中式状态管理

vue2中,使用臃肿的vuex来进行状态管理

vue3中,使用更好用的pinia来进行状态管理

在vuex中,直接拿到数据之后是无法进行修改的,但pinia能拿到数据就可以修改

在pinia中存储的对象如果想要解构出来使用,不推荐使用toRefs方法,而是使用Pinia提供的storeToRefs方法


subscribe

此属性是pinia提供的一个类似于watch的监视属性,他能监视到pinia的变化,并回调用户自定义的函数

通常可以用于将pinia的数据持久化处理


组合式API

Pinia也可以通过组合式API来达成实践,在组合式API中,getters和actions不再强制要求作为独立的部分进行定义

组合式API将内容放入组合函数中,再根据需求将内容暴露出来调用即可