目录
3、第三种修改方式:借助action修改(action中可以编写一些业务逻辑)
7.1.【shallowRef 与 shallowReactive 】
7.2.【readonly 与 shallowReadonly】
1. 介绍
在本篇文章中,我们将详细讲解如何使用Vue3,从基本概念到高级技巧,最终通过一个项目实战,让大家全面掌握Vue3开发技能。
Vue基于标准HTML,CSS,JavaScript构建,并提供了一套声明式,组件化的编程模型,帮助你高效地开发用户页面。无论是简单还是复杂页面,Vue都可以胜任
1.1 Vue是什么
渐进式JavaScript框架,易学易用,性能出色,适用场景丰富的Web前端框架
1.2 为什么学习Vue
- Vue是目前前端最火的框架之一
- Vue是目前企业技术栈中要求的知识点
- Vue可以提升开发体验
- ....
1.3 渐进式框架
Vue是一个框架,也是一个生态。其功能覆盖了大部分前端开发常见的需求。但web世界是十分多样化的,不同的开发者在web上构建的东西可能在形式和规模上会有很大的不同。考虑到这一点,Vue的设计非常注重灵活性和“可以被逐步集成”这个特点。
1.4 Vue版本
目前,在开发中,Vue有两大版本vue2和vue3,老项目一般都是vue2,但是因为vue2已经停止维护了,新的项目一般都是会选择vue3开发(vue3涵盖了vue2的知识体系,当然vue3也增加了许多新的特性)
2. 环境准备
2.1 Node.js 安装
Windows 安装
-
访问官方网站下载: 访问Node.js官方网站 Node.js — Run JavaScript Everywhere ,选择"Downloads"页面,找到适合你系统的安装包(推荐使用LTS版本,即长期支持版,更稳定)。
-
运行安装程序: 下载完成后,双击安装包开始安装。在安装界面,你可以选择是否加入PATH环境变量(建议勾选),这样安装完成后就可以直接在命令行中使用
node
和npm
命令。 -
验证安装: 安装完成后,打开命令提示符(cmd)或PowerShell,输入以下命令检查安装是否成功:
node -v
npm -v
分别会显示Node.js和npm(Node包管理器)的版本号。
2.2 基于vite创建
vite 是新一代前端构建工具
优势
- 轻量快速的热重载,能实现极速的服务启动。
- 对 ts、jsx、css等支持开箱即用。
- 真正的按需求编辑,不再等待整个应用编辑完成。
- webpack构建与vite构建对比图如下:
- 具体操作如下:
## 1.创建命令
npm create vue@latest
## 2.具体配置
## 配置项目名称
√ Project name: vue3_test
## 是否添加TypeScript支持
√ Add TypeScript? Yes
## 是否添加JSX支持
√ Add JSX Support? No
## 是否添加路由环境
√ Add Vue Router for Single Page Application development? No
## 是否添加pinia环境
√ Add Pinia for state management? No
## 是否添加单元测试
√ Add Vitest for Unit Testing? No
## 是否添加端到端测试方案
√ Add an End-to-End Testing Solution? » No
## 是否添加ESLint语法检查
√ Add ESLint for code quality? Yes
## 是否添加Prettiert代码格式化
√ Add Prettier for code formatting? No
总结:
-
Vite
项目中,index.html
是项目的入口文件,在项目最外层。 -
加载
index.html
后,Vite
解析<script type="module" src="xxx">
指向的JavaScript
。 -
Vue3
中是通过createApp
函数创建一个应用实例。
2.3 简单介绍
.vscode --- VSCode工具的配置文件夹
node_modules --- Vue项目的运行依赖文件夹
public --- 资源文件夹(浏览器图标)
src --- 源码文件夹
.gitignore --- git忽略文件
index.html --- 如果HTML文件
package.json --- 信息描述文件
README.md --- 注释文件
vite.config.js --- Vue配置文件
2.4 模版语法
main.ts
// 引入createApp用于创建应用
import { createApp } from "vue";
// 引入App根组件
import App from "./App.vue";
createApp(App).mount("#app");
App.vue
<template>
<!-- html -->
</template>
<script lang="ts">
// JS 或 TS
</script>
<style>
/* css样式 */
</style>
文本插值
最基本的数据绑定形式是文本插值,它使用的是"Mustache"语法(即双大括号):
<template>
<div class="text">
<h3>模版语法</h3>
<p>{
{ msg }}</p>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const msg = ref('神奇的语法')
</script>
<style scoped>
.text{
background-color: #f10808;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
使用 JavaScript 表达式
每个绑定仅支持单一表达式,也就是一段能够被求值的JavaScript代码。一个简单的判断方法是是否合法地写在 return 后面
<template>
<div class="text">
<h3>模版语法</h3>
<p>{
{ count+1 }}</p>
<p>{
{ ok? 'YES':'NO' }}</p>
</div>
</template>
<script setup lang="ts">
import { ref,onMounted } from 'vue'
const count = ref(0)
const msg = ref('神奇的语法')
const ok = true
</script>
<style scoped>
.text{
background-color: #f10808;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
无效
<!-- 这是一个语句,而非表达式 -->
{
{ var a = 1 }}
<!-- 条件控制也不支持,请使用三元表达式 -->
{
{ if(ok) { return message } }}
3. Vue3基础知识
3.1 什么是Vue3
- Vue2 的API设计是Option(配置)风格的。
- Vue3 的API设计是Composition(组合)风格的。
Option API的弊端
Options类型的 API ,数据、方法、计算属性等、是分散在:data,methods,computed 中的,若想新增或者修改一个需求,就需要分别修改:data,methods,computed,不便于维护和复用。
Composition API的优势
可以用函数的方式,更加优雅的组织代码,让相关功能的代码更加有序的组织在一起。
3.2 Vue3的起点setup
setup 概述
setup 是 Vue3 中一个新的配置项,值是一个函数,它是 composition API "表演的舞台",组件中所用到的:数据,方法,计算属性,监视....等等,均配置在 setup 中。
特点如下:
- setup 函数返回的对象中的内容,可直接在模版中使用。
- setup 中访问 this 是 undefined
- setup 函数会在 beforeCreate 之前调用,它是"领先"所有钩子执行的。
<template>
<!-- html -->
<div class="person">
<h2>姓名:{
{ name }}</h2>
<h2>年龄:{
{ age }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">查看联系方式</button>
</div>
</template>
<script lang="ts">
// JS 或 TS
export default {
name: 'Person', // 组件名称
setup(){
// 数据
let name = '张三' // 注意这样写name不是响应式数据
let age = 12 // 注意这样写age不是响应式数据
let tel = '138888888'
// 方法
function changeName(){
name = '李四'
}
function changeAge(){
age += 1
}
function showTel(){
alert(tel)
}
// 将数据,方法交出去,模版中才可以使用
return {name,age,tel,changeName,changeAge,showTel}
}
}
</script>
<style>
/* css样式 */
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
setup 语法糖
setup 函数有一个语法糖,这个语法糖,可以让我们把 setup 独立出去,代码如下:
<template>
<!-- html -->
<div class="person">
<h2>姓名:{
{ name }}</h2>
<h2>年龄:{
{ age }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">查看联系方式</button>
</div>
</template>
<script setup lang="ts" name="Person234">
// 数据
let name = '张三' // 注意这样写name不是响应式数据
let age = 12 // 注意这样写age不是响应式数据
let tel = '138888888'
// 方法
function changeName(){
name = '李四'
}
function changeAge(){
age += 1
}
function showTel(){
alert(tel)
}
</script>
<style>
/* css样式 */
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
扩展:上述代码,还需要编写一个不写 setup 的 script 标签,去指定组件名字,比较麻烦,我们可以借助 vite 中的插件简化
- 第一步: npm i vite-plugin-vue-setup-extend -D
- 第二步:vite.config.ts
import { fileURLToPath, URL } from 'node:url'
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 ref 基本类型的响应式数据
作用:定义响应式变量。
语法: let xxx = ref(初始值) .
返回值:一个 RefImpl 的实例对象,简称 ref 对象 或 ref , ref 对象的 value 属性是响应式的。
注意点:
- JS 中操作数据需要: xxx.value ,但模版中不需要 .value , 直接使用即可。
- 对于 let name = ref('张三') 来说, name 不是响应式的, name.value 是响应式的。
<template>
<!-- html -->
<div class="person">
<h2>姓名:{
{ name }}</h2>
<h2>年龄:{
{ age }}</h2>
<h2>地址:{
{ address }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">查看联系方式</button>
</div>
</template>
<script setup lang="ts" name="Person234">
import { ref,onMounted } from 'vue'
// 数据
let name = ref('张三') // 注意这样写name不是响应式数据
let age = ref(12) // 注意这样写age不是响应式数据
let tel = '138888888'
let address = '北京'
// 方法
function changeName(){
name.value = '李四'
}
function changeAge(){
age.value += 1
}
function showTel(){
alert(tel)
}
</script>
<style>
/* css样式 */
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
3,4 reactive 对象类型的响应式数据
作用:定义一个响应式对象(基本类型不要用它,要用ref
,否则报错)
语法:
let 响应式对象= reactive(源对象)
返回值:一个Proxy
的实例对象,简称:响应式对象。
注意点:reactive
定义的响应式数据是“深层次”的。
<template>
<div class="text">
<h1>汽车信息:</h1>
<h2>一辆{
{ car.brand }}车</h2>
<h2>价值:{
{ car.price }}万</h2>
<button @click="changePrice">修改汽车的价格</button>
<hr>
<h1>游戏列表:</h1>
<ul>
<li v-for="(game,index) in games" :key="index">{
{ game.name }}</li>
</ul>
<button @click="changeFirstGame">修改第一个游戏的名字</button>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
// 数据
let car = reactive({
brand: '奔驰',
price: 100
})
let games = reactive([
{id:'aysdytfastr01',name:'王者荣耀'},
{id:'aysdytfastr02',name:'原神'},
{id:'aysdytfastr03',name:'火影忍者'},
])
// 方法
function changePrice() {
car.price += 10
}
function changeFirstGame(){
games[0].name = '绝地求生'
}
</script>
<style scoped>
.text {
background-color: #f10808;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
margin: 20px 0px;
}
li {
font-size: 20px;
}
</style>
3.5 ref 对象类型的响应式数据
其实
ref
接收的数据可以是:基本类型(详细可以看3.3)、对象类型。
1、定义与初始化:
使用ref
函数可以将一个初始值(不论是基本类型还是对象/数组)封装成一个响应式引用。例如,定义一个对象类型的响应式数据:
import { ref } from 'vue';
const user = ref({ name: '张三', age: 25 });
在这个例子中,user
是一个响应式引用,其.value
属性包含实际的对象数据。
2、访问与更新:
访问ref
包裹的值时,需要通过.value
来读取或修改其内部的值。在JavaScript代码中:
console.log(user.value.name); // 输出: 张三
user.value.name = '李四'; // 更新用户名
而在Vue模板中,可以直接使用user
,Vue会自动解包.value
给你:
<template>
<div>{
{ user.name }}</div>
</template>
3、 内部机制:
- 对于基本类型,
ref
通过Object.defineProperty
来实现响应式。 - 对于对象或数组这类复杂类型,虽然你直接使用
ref
,但其内部实际上会使用reactive
来创建一个深层次的响应式代理对象,然后将其包装在一个简单的包装器中,暴露.value
属性。
4、响应性:
当ref
包裹的对象内部属性发生变化时,Vue的响应系统会自动追踪并触发依赖更新,确保UI能够相应地更新。
5、与reactive的区别
ref ===> 基本 对象
reactive => 对象
区别
ref 创建的变量必须使用 .value (可以使用volar插件自动添加.value).
reactive 重新分配一个新对象,会失去响应式。(可以使用 去整体替换)。
reactive 更改对象
// car = {brand:'保时捷',price:100} 这样写页面是不刷新的
// car = reactive({brand:'宝马',price:200}) 这样写页面是不刷新的
Object.assign(car, {brand:'宝马',price:200})
ref 更改对象
car.value = {brand:'保时捷',price:100}
使用原则
1、若需要一个基本类型的响应式数据,必须使用 ref 。
2、若需要一个响应式对象,层级不深、ref、reactive 都可以。
3、若需要一个响应式对象,且层级较深,推荐使用 reactive 。
3.6 toRefs 与 toRef
作用:将一个响应式对象中的每一个属性,转换为ref
对象。
备注:toRefs
与toRef
功能一致,但toRefs
可以批量转换。
总结
toRef
用于将响应式对象的一个属性转换为一个独立的ref
对象,便于单独操作和传递。toRefs
则是将整个响应式对象转换为一个各属性均为独立ref
对象的普通对象,适合需要分解响应式对象以便于外部使用的情况。
<template>
<div class="person">
<h3>姓名: {
{ name }}</h3>
<h3>年龄:{
{ person.age }},{
{n1}}</h3>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
</div>
</template>
<script setup lang="ts">
import { reactive,toRefs,toRef } from 'vue';
// 用户属性
let person = reactive({
name: '张三',
age: 18
})
let {name, age} = toRefs(person)
let n1 = toRef(person, 'age')
console.log(n1.value);
// 方法
function changeName() {
name.value += '~';
console.log(name.value);
}
function changeAge() {
age.value += 1;
console.log(age.value);
}
</script>
<style scoped>
.person{
background-color: yellow;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
h3{
text-align: center;
}
</style>
3.7 computed 计算属性
作用:根据已有数据计算出新数据(和Vue2
中的computed
作用一致)。
基础用法
在Vue 3的Composition API中,你不再直接在组件的options
对象里定义computed
属性,而是使用setup
函数,通过import { computed } from 'vue'
导入computed
函数来定义计算属性。
import { ref,computed } from 'vue';
let firstName = ref('zhang');
let lastName = ref('san');
let fullName = computed(() => {
return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + '_' + lastName.value
})
在这个例子中,fullName
就是一个计算属性,它依赖于firstName和lastName
的值,并且只有当firstName或lastName
的值变化时,fullName
才会重新计算。
Getter & Setter
Vue 3的计算属性同样支持定义getter和setter,允许你不仅读取而且修改计算属性的值,并触发相应的副作用。
const fullName = computed({
get() {
return this.firstName + ' ' + this.lastName;
},
set(val) {
const [str1,str2] = val.split("_")
firstName.value = str1
lastName.value = str2
}
});
特性总结
- 响应式依赖:计算属性自动追踪依赖,当依赖的数据变化时自动重新计算。
- 缓存机制:计算属性的结果会被缓存,直到依赖项变化,这提高了应用的性能。
- 组合API集成:在
setup
函数中使用,与Vue 3的其他 Composition API 特性无缝集成。 - getter/setter:可以定义setter来改变计算属性所依赖的数据,从而提供了更灵活的数据处理能力。
与其他API的关系
在Vue 3中,computed
常与ref
和reactive
一起使用,前者用于创建基本类型的响应式引用,后者用于创建复杂对象或数组的响应式代理。computed
结合这些API可以构建复杂的响应式逻辑,同时保持代码的清晰和高效。
3.8 watch 监视
作用:watch
是一个用于观察和响应Vue实例上的数据变化的重要特性。它主要用于在某些数据变化时执行异步或开销较大的操作,或者执行那些不应该在每个组件渲染周期内运行的代码。
特点: Vue3 中的 watch 只能监视以下四种数据:
- ref 定义的数据。
- reactive 定义的数据。
- 函数返回的一个值。
- 一个包含上述内容的数组。
情况一 较多使用
监视 ref 定义的【基本类型】数据:直接写数据名即可,监视的是其 value 值的改变。
语法
watch(谁?, 回调函数)
import { ref,watch } from 'vue';
// 数据
let sum = ref(0)
// 方法
function changeSum(){
sum.value += 1
}
// 监视
watch(sum, (newValue, oldValue)=>{
console.log('sum变了',newValue, oldValue);
})
使用watch
函数监视sum
的变化。当sum.value
的值发生变化时,传入的回调函数会被调用,其中newValue
是变化后的新值,oldValue
是变化前的旧值。这段代码会打印出sum变化的前后值。