# 1 vue3简介
- 2020年9月18日,`Vue.js`发布版`3.0`版本,代号:`One Piece`
- 经历了:[4800+次提交](https://github.com/vuejs/core/commits/main)、[40+个RFC](https://github.com/vuejs/rfcs/tree/master/active-rfcs)、[600+次PR](https://github.com/vuejs/vue-next/pulls?q=is%3Apr+is%3Amerged+-author%3Aapp%2Fdependabot-preview+)、[300+贡献者](https://github.com/vuejs/core/graphs/contributors)
- 官方发版地址:[Release v3.0.0 One Piece · vuejs/core](https://github.com/vuejs/core/releases/tag/v3.0.0)
- 截止2023年10月,最新的公开版本为:`3.3.4`
## 1.1 性能的提升
- 打包大小减少`41%`。
- 初次渲染快`55%`, 更新渲染快`133%`。
- 内存减少`54%`。
## 1.2 源码的升级
- 使用`Proxy`代替`defineProperty`实现响应式。
- 重写虚拟`DOM`的实现和`Tree-Shaking`。
## 1.3 拥抱TypeScript
- `Vue3`可以更好的支持`TypeScript`。
## 1.4. 新的特性
1. `Composition API`(组合`API`):
- `setup`
- `ref`与`reactive`
- `computed`与`watch`
......
2. 新的内置组件:
- `Fragment`
- `Teleport`
- `Suspense`
......
3. 其他改变:
- 新的生命周期钩子
- `data` 选项应始终被声明为一个函数
- vue2在非组件中,data可以是对象,也可以是函数;组件中必须为函数
- 移除`keyCode`支持作为` v-on` 的修饰符
- 例如:v-on:key-up.13 这种形式已被移除
......
# 2 创建Vue3工程
## 基于vue-cli创建
- 官方:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
- 目前`vue-cli`已处于维护模式,官方推荐基于 `Vite` 创建项目
```shell
## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version
## 安装或者升级你的@vue/cli
npm install -g @vue/cli
## 执行创建命令
vue create vue_test
## 随后选择3.x
## Choose a version of Vue.js that you want to start the project with (Use arrow keys)
## > 3.x
## 2.x
## 启动
cd vue_test
npm run serve
```
## 基于vite创建
- 官网:https://vitejs.cn
- 轻量快速的热重载(`HMR`),能实现极速的服务启动。
- 对 `TypeScript`、`JSX`、`CSS` 等支持开箱即用。
- 真正的按需编译,不再等待整个应用编译完成。
- `webpack`构建 与 `vite`构建对比图如下:
使用Vite构建Vue3项目参考:https://cn.vuejs.org/guide/quick-start.html#creating-a-vue-application
总结
- `vite`项目中,`index.html`是项目的入口文件,在项目最外层
- 加载`index.html`后,`vite`解析``指向的js
- vue3中是通过`createApp`函数创建一个应用实例
# 3 vue3核心语法
## 3.1 OptionsAPI 与 CompositionAPI
- vue2的API设计是`Options`(配置)风格的
- vue3的API设计是`Composition`(组合)风格的
### vue2选项式风格
```js
data() {
return {
name: '张三',
age: 19,
tel: '13888888888'
}
},
methods: {
showTel() {
alert(this.tel)
},
changeName() {
this.name = 'zhangsan'
},
changeAge() {
this.age += 1
}
},
```
### vue3组合式风格
> 注意:
> 组合式 API 通常会与 `
```
上诉代码中,还需要编写一个不写`setup`的`script`标签,去指定组件名称,比较麻烦,可以借助vite中的一个插件去简化
- 1:npm install vite-plugin-vue-setup-extend -D
- 2:vue.config.ts 做出如下配置
```ts
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
VueSetupExtend()
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
```
## 3.3 响应式数据
### 3.4.1 ref定义基本类型响应式数据
- **作用:**定义响应式变量。
- **语法:**`let xxx = ref(初始值)`。
- **返回值:**一个`RefImpl`的实例对象,简称`ref对象`或`ref`,`ref`对象的`value`**属性是响应式的**。
- **注意点:**
- `JS`中操作数据需要:`xxx.value`,但模板中不需要`.value`,直接使用即可。
- 对于`let name = ref('张三')`来说,`name`不是响应式的,`name.value`是响应式的。
在vue2的年代,把数据放在data中,数据默认就是响应式了
```ts
data:{
return {
a: 19
}
}
```
vue3中定义响应式数据
```ts
let name = ref('张三')
```
### 3.4.2 reactive定义对象类型响应式数据
- **作用:**定义一个**响应式对象**(基本类型不要用它,要用`ref`,否则报错)
- **语法:**`let 响应式对象= reactive(源对象)`。
- **返回值:**一个`Proxy`的实例对象,简称:响应式对象。
- **注意点:**`reactive`定义的响应式数据是“深层次”的。
```ts
let car = reactive({brand: '奔驰', price: 100})
let games = reactive([
{id: "g1", name: '王者荣耀'},
{id: "g2", name: '原神'},
{id: "g3", name: '创越火线'}
])
let obj = reactive({
a: {
b: {
c: 666
}
}
})
```
### 3.4.3 ref定义对象类型响应式数据
- 其实`ref`接收的数据可以是:**基本类型**、**对象类型**。
- 若`ref`接收的是对象类型,内部其实也是调用了`reactive`函数。
### 3.4.4 ref 与 reactive 的对比
宏观角度看:
> `ref`用来定义:基本类型数据、对象类型数据
> `reactive`用来定义:对象类型数据
区别:
> `ref`创建的变量必须使用`.value`(在template中不用),(可以用`volar`插件自动添加`.value`)
> `reactive`重新分配一个新对象,会**失去**响应式(可以使用`Object.assgin`去整体替换)
使用规则(推荐,并不是规范):
> 若需要一个基本类型的响应式数据,必须使用`ref`
> 若需要一个响应式对象,层级不深,`ref`、`reactive`都可以
> 若需要一个响应式对象,且层级较深,推荐使用`reactive`
## 3.5 toRefs 与 toRef
- 作用:将一个响应式对象中的每一个属性,转换为`ref`对象。
- 备注:`toRefs`与`toRef`功能一致,但`toRefs`可以批量转换。
```ts
let person = reactive({name: '张三', age: 18})
let {name, age} = toRefs(person)
let n = toRef(person, 'name')
```
## 3.6 computed 计算属性
- 作用:根据已有数据计算出新数据(和`Vue2`中的`computed`作用一致)
总结:
计算属性是有缓存的
官方描述:一个计算属性仅会在其响应式依赖更新时才重新计算
vue2中定义计算属性的方式
```js
```
## 3.7 watch
- 作用:监视数据的变化(和vue2中的watch的作用一致)
- 特点:`vue3`中的`watch`只能监视以下**四种数据**:
> - `ref`定义的数据
> - `reactive`定义的数据
> - 函数返回的一个值(getter函数)
> - 一个包含上述内容的数组
我们在vue3中使用`watch`的时候,通常会遇到如下情况:
### 情况一
监视`ref`定义的【基本类型】数据:直接写数据名即可,监视的是其`value`值的变化。
```vue
要实现路由说人话就是大致有以下步骤:
1. 要有导航区、展示区
2. 指定路由的具体规则(什么路径,对应着什么组件)
3. 形成一个个 【Xxx.vue】,根据路由路由规则展示不同的组件【Xxx.vue】
## 4.2 基本切换效果
- `Vue3`中要使用`vue-router`的最新版本,目前是`4`版本
```shell
npm install vue-router
```
- 路由配置文件代码如下:
```ts
// 创建一个路由器,并暴露出去
// 第一步:引入createRouter
import {createRouter, createWebHistory} from 'vue-router'
// 引入一个个可能要呈现的组件
import Home from '@/components/Home.vue'
import News from '@/components/News.vue'
import About from '@/components/About.vue'
// 第二步:创建路由器
const router = createRouter({
history: createWebHistory(), // 路由器的工作模式
// 定义一个个的路由规则
routes: [
{
path: '/home',
component: Home
},
{
path: '/news',
component: News
},
{
path: '/about',
component: About
},
]
})
// 第三步:暴露出去router 导出路由
export default router
```
- `main.ts`代码如下:
```ts
// 引入路由器
import router from './router/index'
// 创建一个应用
const app = createApp(App)
// 使用路由器
app.use(router)
// 挂载整个应用到app容器
app.mount('#app')
```
- `App.vue`代码如下
```vue
## 5.2 搭建 pinia 环境
第一步:`npm install pinia`
第二步:操作`src/main.ts`
```ts
import { createApp } from 'vue'
import App from './App.vue'
/* 引入createPinia,用于创建pinia */
import { createPinia } from 'pinia'
const app = createApp(App)
/* 创建pinia */
const pinia = createPinia()
/* 使用插件 */
app.use(pinia)
app.mount('#app')
```
此时开发者工具中已经有了`pinia`选项
## 5.3 存储+读取数据
1. `Store`是一个保存:**状态**、**业务逻辑** 的实体,每个组件都可以**读取**、**写入**它。
2. 它有三个概念:`state`、`getter`、`action`,相当于组件中的: `data`、 `computed` 和 `methods`。
1. 大多数时候,state 是 store 的核心部分
2. Getter 完全等同于 Store 状态的 [计算值](https://v3.vuejs.org/guide/reactivity-computed-watchers.html#computed-values)
3. Actions 相当于组件中的 [methods](https://v3.vuejs.org/guide/data-methods.html#methods)。
1. **actions 可以是异步的**,您可以在其中`await` 任何 API 调用甚至其他操作!
3. 具体编码:`src/store/count.ts`
```ts
// 引入defineStore用于创建store
import {defineStore} from 'pinia'
// 定义并暴露一个store
export const useCountStore = defineStore('count',{
// 动作
actions:{},
// 状态
state(){
return {
sum:6
}
},
// 计算
getters:{}
})
```
4. 具体编码:`src/store/talk.ts`
```js
// 引入defineStore用于创建store
import {defineStore} from 'pinia'
// 定义并暴露一个store
export const useTalkStore = defineStore('talk',{
// 动作
actions:{},
// 状态:真正存储数据的地方
state(){
return {
talkList:[
{id:'yuysada01',content:'你今天有点怪,哪里怪?怪好看的!'},
{id:'yuysada02',content:'草莓、蓝莓、蔓越莓,你想我了没?'},
{id:'yuysada03',content:'心里给你留了一块地,我的死心塌地'}
]
}
},
// 计算
getters:{}
})
```
5. 组件中使用`state`中的数据
```vue
## 6.1 props
概述:`props`是使用频率最高的一种通信方式,常用与 :**父 ↔ 子**。
- 若 **父传子**:属性值是**非函数**。
- 在父组件中给子组件绑定属性,子组件内部通过props选型接收数据
- 若 **子传父**:属性值是**函数**。
- 父先提供一个函数给子,子调用函数传数据给父
> 说明:
>
> 如果需要父传给孙,孙传给父,不建议使用props
父组件:
```vue
我是弹窗中的一些内容