【Vue3】保姆级毫无废话的进阶到实战教程 - 01
ztj100 2025-06-29 22:04 2 浏览 0 评论
作为一个 React、Vue 双修选手,在 Vue 3 逐渐稳定下来之后,是时候摸摸 Vue 3 了。Vue3 的变化不可谓不大,所以,本系列主要通过对 Vue3 中的一些 Big Changes 做详细的介绍,然后封装一个比较通用的业务脚手架,里面会增加很多非常有用的小技巧,让你在 Vue 3 的世界里纵享丝滑 ~
第一篇将着重介绍一些 Vue3 中重要的变化和概念 ~
1、新建项目
找个可以开机的电脑,在终端输入:
打开链接 http://127.0.0.1:5173,你的眼睛就会看到:
代表项目初始化成功,你真棒!
你的目录会长这个样子:
注意:记笔记,小技巧学起来,在 vscode 终端中使用 tree 指令打印当前项目的文件树:
tree -I "node_modules|.vscode|cypress" > tree.txt
这个命令会做两件事:
- 使用 tree 命令输出目录树结构,同时排除 node_modules、.vscode 和 cypress 文件夹
- tree 命令可以输出目录的树形结构
- -I 参数用于排除某些文件夹不显示
- 在排除参数中用 | 分隔多个要排除的文件夹名
- 使用 '>' 符号将标准输出重定向到 tree.txt 文件(没有就会自动生成一个)
这样 tree 命令的输出就会被写入到 tree.txt 文件中,而不是打印到终端屏幕上。在项目中执行,然后你就会在项目根目录中看到一个 tree.txt 文件:
.
├── README.md
├── cypress.config.ts
├── dist
│ ├── assets
│ │ ├── AboutView-4d995ba2.css
│ │ ├── AboutView-675ecf4b.js
│ │ ├── index-9f680dd7.css
│ │ ├── index-d5df9149.js
│ │ └── logo-277e0e97.svg
│ ├── favicon.ico
│ └── index.html
├── env.d.ts
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
│ └── favicon.ico
├── src
│ ├── App.vue
│ ├── assets
│ │ ├── base.css
│ │ ├── logo.svg
│ │ └── main.css
│ ├── components
│ │ ├── HelloWorld.vue
│ │ ├── TheWelcome.vue
│ │ ├── WelcomeItem.vue
│ │ ├── __tests__
│ │ │ └── HelloWorld.spec.ts
│ │ └── icons
│ │ ├── IconCommunity.vue
│ │ ├── IconDocumentation.vue
│ │ ├── IconEcosystem.vue
│ │ ├── IconSupport.vue
│ │ └── IconTooling.vue
│ ├── main.ts
│ ├── router
│ │ └── index.ts
│ ├── stores
│ │ └── counter.ts
│ └── views
│ ├── AboutView.vue
│ └── HomeView.vue
├── tree.txt
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
├── tsconfig.vitest.json
├── vite.config.ts
└── vitest.config.ts
简单介绍一下重要的文件/文件夹:
public
里面的东西不会经过编译和打包,所以放在 public 内的东西 ”不要引用“;
通常会放置( 不被JavaScript ) 引用的静态资源,例如:网页标题栏 icon,即 favicon.ico;
打包的时候,里面的东西会直接被复制一份,放在根目录内,所以要引用 public 内的资源时,要使用根目录绝对路径,比如:要取 public/favicon.ico ,你应写成 /favicon.ico;
assets:放静态资源,如:图片、CSS
components:放公用组件
stores:与 Pinia 状态管理器有关
router:与 Vue Router 路由管理有关
views:放路由组件
2、深入认识 npm xxx
在 package.json 的 scripts 中常用的有三个指令:
npm run dev|npx vite:启动项目本地服务,并提供 Hot Module Replacement (HMR),可以在更新代码后即时更新页面;
是的,在项目根目录下 npx vite 也可以启动项目!
- npm run build|npx vite build:项目打包
- npm run preview|npx vite preview --port 4173:启动一个本地服务,预览打包后的 dist 内容,可以在正式布署前检查打包后的内容是否有问题
3、为什么要打包?
Vue3项目打包的主要目:
- 必要的语法编译
- 浏览器不认识 vue 文件,需要编译成浏览器能读懂的 js 和 css
- 浏览器不认识的新 ES 语法,需要 polyfill。
- Minify 代码:去除无用代码,节省浏览器解析的时间
- 在不影响程序运行的前提下,去除不必要的空白字元、注解,将变量名称、函数名称、参数名称缩短等等,减少部署后的代码体积。
- 整合第三方模块:打包可以将引入的各种第三方模块打包合并到一起,作为一个整体进行部署。通过 npm 或yarn 安装所需的第三方库,实际都放在 node_modules 内,却可以透过 import from "xxx" 直接使用,不需要写出该库的完整路径,这是打包工具的功劳。
- 性能优化:通过打包合并文件,减少页面 HTTP 请求数量,加快加载速度。
- 代码保护:源码经过打包后会进行压缩和混淆,可以起到一定的代码保护作用。
- 兼容性优化:打包可以将代码转换为主流浏览器都能识别的语法,优化不同浏览器的兼容性。
- 部署方便:打包后生成的静态资源文件可以很方便地部署到各种环境。
- 开启gzip压缩:打包过程可以进行gzip压缩,优化静态资源文件的体积。
- 分析代码:通过分析打包后的文件,可以清晰看到项目中不同文件的组成和大小。
打包主要是为了优化性能、安全性、扩展性、部署便利性等等,实际项目部署中也是必要的步骤。
4、Option API 和Composition API 区别
Vue 3 提供 Option API 和 Composition API 两种写法,Option API 是延续自 Vue 2 的写法,Composition API 则是跟着 Vue 3 一起推出的新写法。
Option API 和 Composition API 主要差别有两个:
- 管理逻辑代码的方式,也就是<script>的部分,模板 template 和 style 的用法是一样的。
- Composables (Vue 官网翻译成 组合式函数)
这里引用 FU 大神在 Vueconf 上的一个解释:
4.1 Option API
所谓的 Option (选项),就是 Vue 将代码根据特性不同,分类成 data、method、计算属性(computed)、生命周期......不同选项,让开发者通过选项 (Option) 的方式,来定义组件内的逻辑。
代码一般会根据选项式 API 被分成几个区块,比如这样:
4.2 Composition API
在 Composition API 搭配 <script setup> 的情况下,可以将所有逻辑代码直接写在<script>内,就跟写原生 Javascript 的感觉很像,几乎没有什么特殊规则,交由开发者自行管理。
使用 Composition API 时,通常会根据「功能」来管理逻辑代码,一个功能使用到的 data、method,声明位置可以比较靠近,对于大的、复杂的组件来说,会提升可读性。
Composition API 的代码一般是这样:
4.3 两者区别
- Option API:有既定规则,代码按照选项分区管理
- Composition API:较为弹性、自由,代码通常按照功能逻辑分区管理,(或随开发者偏好)
两种方式都有人喜欢,没有绝对的好坏。 其实 「自由/ 弹性」 在程式码管理上是把双刃剑,更考验开发者管理代码的能力;也有开发者偏好在订好的规则下进行开发,两者并没有优劣,而是风格差异。
- Composition API 形式下,需要由开发者自己利用 reactive() 和 ref() 定义 data 是否有响应性,在其他地方取 data 时,也就要根据 reactive() 和 ref() 的规则进行取值和操作。
- Option API 形式下,Vue 已经帮开发者做好了响应式,自动为 data 中的数据加上响应性,其他选项要取用 data 内的数据时,用 this.变量名 取得即可。
但整个两者背后的响应式机制是一样的,核心概念不变,而是根据Vue 定义的写法不同,有不同的使用方式,所以 Vue 官网将教学指南分成两种 API 形式。
复杂组件的情况下,Composition API 可读性更好
- 在开发比较小的组件时,两者的可读性其实没有太大的差异。
- 但随着组件越大、越复杂,功能用到几个不同的 Option,逻辑就会被分散在不同 Option 的区块,随着组件长大,可读性会变差,要管理一个功能时,需要在不同的 Option 区块之间切换。
官网也给了这两者的直观上的区别:
建议是都能熟悉使用,不然你怎么看懂别人的 shishan 代码呢?
5、使用 Composition API 封装自定义 Hooks
在 Vue 3 中,可以使用 Composition API 来封装可重用的逻辑,类似于 React 中的 Hooks。
通过自定义 Hooks,我们可以将可重用的逻辑封装起来,并在多个组件中共享使用。这样可以提高代码的可维护性、重用性和可读性,避免了代码重复,并且使组件更加关注自身的业务逻辑。并且 hook 具有良好的命名空间和类型推导,易于测试等特性。
5.1 useWindowSize
下面封装一个 useWindowSize 的自定义 Hooks,用于获取当前窗口的宽度和高度:
将窗口大小的逻辑封装成一个可重用的函数,并且与具体的组件解耦。其他组件只需要导入并调用 useWindowSize,就可以获取窗口大小,而不需要重复编写监听器和逻辑。
比如,你就可以在组件中这样使用 useWindowSize:
5.2 useFetch 和 usePagination
下面再来封装两个非常常用的自定义 Hooks:usePagination 和 useFetch。
import { ref, computed, onMounted, isRef, watch } from "vue";
export function usePagination(endpoint) {
const currentPage = ref(1);
const paginatedEndpoint = computed(() => {
return `${endpoint}?page=${currentPage.value}`;
});
function nextPage() {
currentPage.value++;
}
function prevPage() {
if (currentPage.value <= 1) {
return;
}
currentPage.value--;
}
return {
endpoint: paginatedEndpoint,
nextPage,
prevPage
};
}
export function useFetch(endpoint) {
const data = ref(null);
const loading = ref(true);
const error = ref(null);
function fetchData() {
loading.value = true;
// 也可以使用 axios
return fetch(isRef(endpoint) ? endpoint.value : endpoint, {
method: "get",
headers: {
"content-type": "application/json"
}
})
.then(res => {
// 非 200 响应码
if (!res.ok) {
const error = new Error(res.statusText);
error.json = res.json();
throw error;
}
return res.json();
})
.then(json => {
data.value = json;
})
.catch(err => {
error.value = err;
if (err.json) {
return err.json.then(json => {
error.value.message = json.message;
});
}
})
.finally(() => {
loading.value = false;
});
}
onMounted(() => {
fetchData();
});
if (isRef(endpoint)) {
watch(endpoint, () => {
// 重新请求数据
fetchData();
});
}
return {
data,
loading,
error
};
}
下面逐个分析这两个 Hooks 的封装思路:
1. usePagination:
这个自定义 Hook 用于处理分页逻辑。它接收一个 endpoint 参数,表示分页请求的接口。
- currentPage 是一个响应式引用(ref),用于存储当前页码,默认为 1。
- paginatedEndpoint 是一个计算属性(computed),根据当前页码和 endpoint 拼接出分页请求的完整接口。
- nextPage 函数用于增加当前页码,即跳转到下一页。
- prevPage 函数用于减少当前页码,即回到上一页。
最后,返回了一个对象,包含了 paginatedEndpoint、nextPage 和 prevPage。这样,在多个组件中可以方便地使用分页功能,而不需要重复编写逻辑。通过修改 currentPage 的值,可以轻松地切换页码,并且 paginatedEndpoint 会自动更新,以便发起正确的分页请求。
2. useFetch:
这个自定义 Hook 用于发送异步请求并处理响应数据。它接收一个 endpoint 参数,表示请求的接口。
- data、loading 和 error 都是响应式引用(ref),分别用于存储请求的响应数据、加载状态和错误信息。
- fetchData 函数用于发送请求。在函数内部,首先将 loading 置为 true,表示请求正在进行中。然后使用 Fetch API 发起请求,并根据请求的状态进行相应的处理:
- 如果响应状态码不是 200,抛出一个带有状态文本的错误。
- 如果响应状态码为 200,将响应数据解析为 JSON,并将其赋值给 data。
- 如果发生错误,将错误信息存储在 error 中,并尝试提取自定义的 JSON 错误响应。
- onMounted 钩子在组件挂载后调用 fetchData 函数,即在组件加载时发送请求。
- 如果 endpoint 是响应式引用,则使用 watch 监听 endpoint 的变化,并在变化时重新调用 fetchData,以重新获取数据。
最后,返回一个对象,包含了 data、loading 和 error。这样,在组件中发送请求变得更加简单。通过调用 fetchData 函数,可以发起请求并获取响应数据,同时也可以监控请求的加载状态和错误信息。这样,组件可以更专注于业务逻辑,而不需要过多关注请求的细节。
怎么使用呢?
<script setup>
import { usePagination, useFetch } from './hooks'
const endpoint = 'https://example.com/api'
const {
endpoint: paginatedEndpoint,
nextPage,
prevPage
} = usePagination(endpoint)
const {
data,
loading,
error
} = useFetch(paginatedEndpoint)
function handleNextPage() {
nextPage()
}
function handlePrevPage() {
prevPage()
}
</script>
<template>
<div>
<button @click="handlePrevPage">Prev</button>
<button @click="handleNextPage">Next</button>
<div v-if="loading">Loading...</div>
<div v-if="data">
<!-- display data -->
</div>
<div v-if="error">
Error: {{ error }}
</div>
</div>
</template>
6、几个重要的东西
6.1 setup() 和 <script setup>
在最新的 Composition API 中引入 <script setup>,其设计理念是去除不必要的包装器和其他旧的组件选项,这样就能更简单、更集中地编写组件。你可以认为 <script setup> 是 setup() 的语法糖,比如:
使用 <script setup> 语法糖,我们可以更简洁地编写组件逻辑。不再需要写多余的 return 语句:
对比一下:
6.2 Props 和 Events
要声明 props 和 emits 等选项,我们必须使用 <script setup> 中自动提供的所谓编译器宏:
这两个函数不需要导入,在预处理 <script setup> 时会自动编译。
如果你使用了 TypeScript,那么最好也声明一下 props 和 emits 的类型:
6.3 多个 script
在某些情况下,我们有可能希望在组件中声明一些自定义选项,比如自定义组件名称,<script setup> 实现不了的,可以用另外一种传统的写法,在编译 *.vue 文件时,这两个区块会自动合并。
6.4 defineExpose
在 Vue 3 的 Composition API 中,defineExpose 用于将组件的一部分内容公开给父组件。你可以指定哪些属性、方法或其他内容可以被父组件访问和使用。比如:
定义了一些。
使用 defineExpose 函数将内部的属性 exposedValue 和一个方法 exposedMethod 暴露出去。在模板中,我们可以像使用普通的属性和方法一样使用这些暴露的内容。在点击按钮时,调用了 exposedMethod 方法。
父组件可以像下面这样访问和使用子组件暴露的内容:
在父组件中,需要使用 ref 创建了一个对子组件的引用 childComponent。然后,我们可以通过 childComponent.value 来访问子组件实例,并调用其公开的方法 exposedMethod。
6.5 Suspense
在组件中,我们通常需要异步请求数据,比如在 <script setup> 的顶层使用了 await。以这种方式定义的组件必须与 Suspense 组件一起使用(React 有的我也要有?),这样 Vue 才能解决异步问题并正确加载组件。
<Suspense> 是一个内置组件,用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。
<script setup>
const user = await fetch(`/users/1`).then((d) => d.json())
</script>
<template>
<Suspense>
<AsyncComponent />
</Suspense>
</template>
不过需要注意:<Suspense> 还是一项实验性功能。它不一定会最终成为稳定功能,并且在稳定之前相关 API 也可能会发生变化。
7、SFC
在 Vue 3 中,SFC(Single File Component,单文件组件)是一种将模板、脚本和样式封装在一个单独的文件中的开发模式。SFC 提供了一种组织和编写 Vue 组件的便捷方式,并提供了更好的可读性和可维护性。
一个典型的 Vue 3 SFC 包含三个部分:
- 模板(template):每个 .vue 文件最多只能有一个<template>,内容会被 @vue/compiler-dom 预编译成 JavaScript 的渲染函数。
- 脚本(script):每个.vue最多只能有一个<script>(不包含<script setup>)
- 样式(style):每个.vue可以有多个<style>,样式可以是普通的 CSS,也可以使用预处理器(如 Sass、Less)或 CSS-in-JS 库(如 CSS Modules)来编写。
以下是一个示例 SFC 文件的结构:
<template>
<!-- 模板内容 -->
</template>
<script>
// 脚本内容
</script>
<style>
/* 样式内容 */
</style>
因为浏览器并不认识.vue档,所以在开发的时候,我们不能像以前一样直接通过 live server 在浏览器上预览项目,这也是为什么我们需要用到 Vite 或 Vue Cli 等建构工具,建构工具会根据 Vue 提供的 loader -@vue/compiler-sfc 来编译 .vue 文件。
Vue 3 的编译器会解析 SFC 的模板、脚本和样式部分,并将它们转换为可执行的渲染函数、JavaScript 代码和样式。这样,开发人员可以通过单个文件来组织组件的结构和逻辑,提高代码的可维护性和可读性,并且在构建过程中,Vue 3 的编译器会将 SFC 转换为可执行的 Vue 组件,使其能够在浏览器中运行。
打开浏览器的控制台,你就会发现,虽然它还有.vue,但你再仔细看看它,它已经是js了:
原文链接:
https://juejin.cn/post/7277089907973603388
相关推荐
- 使用Python编写Ping监测程序(python 测验)
-
Ping是一种常用的网络诊断工具,它可以测试两台计算机之间的连通性;如果您需要监测某个IP地址的连通情况,可以使用Python编写一个Ping监测程序;本文将介绍如何使用Python编写Ping监测程...
- 批量ping!有了这个小工具,python再也香不了一点
-
号主:老杨丨11年资深网络工程师,更多网工提升干货,请关注公众号:网络工程师俱乐部下午好,我的网工朋友。在咱们网工的日常工作中,经常需要检测多个IP地址的连通性。不知道你是否也有这样的经历:对着电脑屏...
- python之ping主机(python获取ping结果)
-
#coding=utf-8frompythonpingimportpingforiinrange(100,255):ip='192.168.1.'+...
- 网站安全提速秘籍!Nginx配置HTTPS+反向代理实战指南
-
太好了,你直接问到重点场景了:Nginx+HTTPS+反向代理,这个组合是现代Web架构中最常见的一种部署方式。咱们就从理论原理→实操配置→常见问题排查→高级玩法一层层剖开说,...
- Vue开发中使用iframe(vue 使用iframe)
-
内容:iframe全屏显示...
- Vue3项目实践-第五篇(改造登录页-Axios模拟请求数据)
-
本文将介绍以下内容:项目中的public目录和访问静态资源文件的方法使用json文件代替http模拟请求使用Axios直接访问json文件改造登录页,配合Axios进行登录请求,并...
- Vue基础四——Vue-router配置子路由
-
我们上节课初步了解Vue-router的初步知识,也学会了基本的跳转,那我们这节课学习一下子菜单的路由方式,也叫子路由。子路由的情况一般用在一个页面有他的基础模版,然后它下面的页面都隶属于这个模版,只...
- Vue3.0权限管理实现流程【实践】(vue权限管理系统教程)
-
作者:lxcan转发链接:https://segmentfault.com/a/1190000022431839一、整体思路...
- swiper在vue中正确的使用方法(vue中如何使用swiper)
-
swiper是网页中非常强大的一款轮播插件,说是轮播插件都不恰当,因为它能做的事情太多了,swiper在vue下也是能用的,需要依赖专门的vue-swiper插件,因为vue是没有操作dom的逻辑的,...
- Vue怎么实现权限管理?控制到按钮级别的权限怎么做?
-
在Vue项目中实现权限管理,尤其是控制到按钮级别的权限控制,通常包括以下几个方面:一、权限管理的层级划分...
- 【Vue3】保姆级毫无废话的进阶到实战教程 - 01
-
作为一个React、Vue双修选手,在Vue3逐渐稳定下来之后,是时候摸摸Vue3了。Vue3的变化不可谓不大,所以,本系列主要通过对Vue3中的一些BigChanges做...
- Vue3开发极简入门(13):编程式导航路由
-
前面几节文章,写的都是配置路由。但是在实际项目中,下面这种路由导航的写法才是最常用的:比如登录页面,服务端校验成功后,跳转至系统功能页面;通过浏览器输入URL直接进入系统功能页面后,读取本地存储的To...
- vue路由同页面重定向(vue路由重定向到外部url)
-
在Vue中,可以使用路由的重定向功能来实现同页面的重定向。首先,在路由配置文件(通常是`router/index.js`)中,定义一个新的路由,用于重定向到同一个页面。例如,我们可以定义一个名为`Re...
- 那个 Vue 的路由,路由是干什么用的?
-
在Vue里,路由就像“页面导航的指挥官”,专门负责管理页面(组件)的切换和显示逻辑。简单来说,它能让单页应用(SPA)像多页应用一样实现“不同URL对应不同页面”的效果,但整个过程不会刷新网页。一、路...
- Vue3项目投屏功能开发!(vue投票功能)
-
最近接了个大屏项目,产品想在不同的显示器上展示大屏项目不同的页面,做出来的效果图大概长这样...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)