https://github.com/vbenjs/vite-plugin-svg-icons/
创建一个空的 vue 项目
pnpm create vue
┌ Vue.js - The Progressive JavaScript Framework
◇ 请输入项目名称:
│ vueSvg
│
◇ 请输入包名称:
│ vuesvg
│
◇ 请选择要包含的功能: (↑/↓ 切换,空格选择,a 全选,回车确认)
│ TypeScript, ESLint(错误预防), Prettier(代码格式化)
│
◇ 选择要包含的试验特性: (↑/↓ 切换,空格选择,a 全选,回车确认)
│ none
│
正在初始化项目 C:\Users\Windows\Desktop\study\vue\primevue\vueSvg...
│
└ 项目初始化完成,可执行以下命令:
cd vueSvg
pnpm install
pnpm format
pnpm dev
| 可选:使用以下命令在项目目录中初始化 Git:
git init && git add -A && git commit -m "initial commit"
空的 vue 项目创建好后,开始安装 vite-plugin-svg-icons
项目体积比较大,或使用的插件体积比较大,小程序分包就很有必要。
https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages/basic.html
配置方法
假设支持分包的小程序目录结构如下:
├── app.js
├── app.json
├── app.wxss
├── packageA
│ └── pages
│ ├── cat
│ └── dog
├── packageB
│ └── pages
│ ├── apple
│ └── banana
├── pages
│ ├── index
│ └── logs
└── utils
开发者通过在 app.json subPackages 字段声明项目分包结构:
{
"pages":[
"pages/index",
"pages/logs"
],
"subPackages": [
{
"root": "packageA",
"pages": [
"pages/cat",
"pages/dog"
],
"entry": "index.js"
}, {
"root": "packageB",
"name": "pack2",
"pages": [
"pages/apple",
"pages/banana"
]
}
]
}
当然,分包文件也可以在根的 pages
目录下,记得定义好 root 就好。root 下的所有页面都是属于分包的。 还有,插件的配置。如果想插件也在分包内使用,必须也配置进去,否则插件会打包在主包里。
如:
{
……,
"subPackages": [
{
"root": "packageA",
"pages": [
"pages/cat",
"pages/dog"
],
"plugins": {
"kivicube": {
"version": "2.16.19",
"provider": "wx3bbab3920eabccb2"
}
}
}
]
}
以下是一个基于 Nuxt 4 架构、面向复杂企业级后台系统的完整项目目录结构示例,结合了官方推荐、社区实践与真实项目经验,具备高度可扩展性和清晰的职责划分:
my-nuxt4-project/
├── app/ # 所有客户端代码集中目录(Nuxt 4 新结构)
│ ├── assets/ # 需构建的静态资源(scss、字体、图片等)
│ │ ├── css/
│ │ │ └── main.scss
│ │ └── fonts/
│ ├── components/ # 自动导入的 Vue 组件
│ │ ├── ui/ # 基础 UI 组件(按钮、表单、弹窗)
│ │ ├── layout/ # 布局相关组件(Sidebar、Header、Footer)
│ │ └── charts/ # 图表组件(ECharts、D3)
│ ├── composables/ # 自动导入的 Composition API 逻辑
│ │ ├── useAuth.ts # 权限处理
│ │ ├── useApi.ts # 统一 API 调用封装
│ │ └── useTable.ts # 列表页通用逻辑
│ ├── layouts/ # 页面级布局
│ │ ├── default.vue # 默认布局(含侧边栏、顶部栏)
│ │ ├── auth.vue # 登录/注册页布局
│ │ └── blank.vue # 空白布局(弹窗、预览页)
│ ├── middleware/ # 路由中间件
│ │ ├── auth.global.ts # 全局鉴权
│ │ ├── role.ts # 路由级角色控制
│ │ └── log.ts # 路由访问日志
│ ├── pages/ # 文件系统路由
│ │ ├── index.vue # 首页(重定向到 /dashboard)
│ │ ├── login.vue
│ │ ├── dashboard.vue
│ │ ├── system/
│ │ │ ├── user.vue
│ │ │ ├── role.vue
│ │ │ └── dept.vue
│ │ └── […slug].vue # 404 或其他通配路由
│ ├── plugins/ # 客户端插件
│ │ ├── vuetify.client.ts # UI 框架初始化
│ │ ├── dayjs.client.ts # 日期库
│ │ └── pinia.ts # 状态管理
│ ├── stores/ # Pinia 全局状态
│ │ ├── auth.ts
│ │ ├── app.ts # 全局设置、主题
│ │ └── menu.ts # 动态菜单
│ ├── utils/ # 通用工具函数
│ │ ├── request.ts # axios 二次封装
│ │ ├── validate.ts # 表单校验规则
│ │ └── constants.ts # 常量枚举
│ ├── app.vue # 应用根组件(全局入口)
│ ├── app.config.ts # 运行时配置(主题、i18n)
│ └── error.vue # 错误页(500/404)
├── shared/ # 前后端共享代码(类型、DTO、工具)
│ ├── types/
│ │ ├── api.d.ts
│ │ └── user.d.ts
│ └── utils/
│ └── date.ts
├── server/ # 服务端代码(Nitro)
│ ├── api/ # RESTful API
│ │ ├── auth/
│ │ │ ├── login.post.ts
│ │ │ └── logout.post.ts
│ │ ├── system/
│ │ │ ├── user.get.ts
│ │ │ └── user.post.ts
│ ├── middleware/ # 服务端中间件(日志、鉴权)
│ │ └── logger.ts
│ ├── plugins/ # 服务端插件(数据库连接)
│ │ └── db.ts
│ ├── utils/ # 服务端工具(加密、权限)
│ │ └── jwt.ts
│ └── routes/ # 非 /api 前缀的自定义路由
│ └── healthz.ts # /healthz
├── public/ # 纯静态资源(favicon、robots.txt)
│ ├── favicon.ico
│ └── images/
│ └── logo.png
├── modules/ # 本地开发的 Nuxt 模块
│ └── nuxt-module-i18n/
├── layers/ # 多应用共享层(微前端、主题系统)
│ └── admin-layer/
├── tests/ # 单元 & e2e 测试
│ ├── unit/
│ └── e2e/
├── .env # 环境变量
├── .env.example
├── .gitignore
├── nuxt.config.ts # 主配置文件
├── package.json
├── tsconfig.json # 一个 tsconfig 即可(Nuxt 4 特性)
└── README.md
✅ 目录亮点说明
目录/文件 | 作用与最佳实践 |
---|---|
app/ |
Nuxt 4 强制的新结构,所有客户端代码集中,IDE 感知更清晰,监听更快 |
shared/ |
前后端共享类型、DTO、工具,避免重复定义 |
server/ |
基于 Nitro 的服务端逻辑,支持热更新、无服务器部署 |
modules/ |
本地私有模块,便于拆分业务、发布内部包 |
layers/ |
多应用/主题继承,适合微前端或 SaaS 白标系统 |
✅ 迁移建议
- 旧项目想升级?
运行npx nuxt upgrade --dedupe
即可平滑升级;目录结构不强制迁移,旧结构也能跑 。 - 新项目建议直接采用上述结构,提前享受更快的 HMR、类型推断和 IDE 体验 。
如需进一步模板,可直接使用官方 nuxt-ui-pro/dashboard 作为起点,再按此结构扩展。
nuxt 的一些搞法。
- 路由别名。比如你想访问 www.xxx.com 默认对应代码的 ./app/pages/index.vue 和 ./app.vue 文件。如果想对应 ./app/pages/home/index.vue,路由别名就很有用处了。
只需要在 ./app/pages/home/index.vue 中使用路由别名就好。如:
<template>
<h2>home</h2>
</template>
<script setup lang="ts">
definePageMeta({
alias: '/'
})
</script>
这种方法,访问地址依然是 www.xxx.com。 初了使用路由别名,还可以使用中间件和redirect 的方式来实现。其实,这两种方式都是 redirect 。但是这个时候地址变成了 www.xxx.com/home 。方法如下。
方法一: ./app/pages/index.vue 依然存在,通过 definePageMeta 来做跳转。
// pages/index.vue
<script setup lang="ts">
definePageMeta({
redirect: '/home'
})
</script>
方法二: 新建中间件 ./app/middleware/redirectRoot.ts 文件。加入以下代码
export default defineNuxtRouteMiddleware(() => {
if (useRoute().path === '/') {
return navigateTo('/home')
}
})
然后在 nuxt.config.ts 中加入以下代码
export default defineNuxtConfig({
…,
nitro: {
routeRules: {
'/': { redirect: '/home' }
}
}
})
看个人喜好,个人还是喜欢用路由别名,然后是中间件。确实有强迫症,不喜欢多一个 ./app/index.vue 文件。
以整个视口为单位,使用滑轮滚动或导航触发来达到展示效果的网站是一种需求。一种是自己手写 js + css 来达到这种效果。还有一种使用 fullpage.js 来达到这个效果。当然,使用 swiperjs 来实现这效果也是妥妥的赞,还很丝滑。
https://github.com/alvarotrigo/fullPage.js
https://swiperjs.com/get-started
主要是 fullpage.js 是需要花钱购买服务,而 swiperjs 是开源使用的。并且 swiperjs 不仅仅可以做这种视口滚动效果。
所以,这里选择使用 swiperjs 来完成目标。
DEMO 展示效果如下图所示(gif 使用 https://www.mnggiflab.com/ 录制和压缩):

基础环境
初始化一个 vue 项目。
pnpm create vue
cd swiperFullpage
pnpm install
pnpm format
pnpm dev
创建选项如下图所示。

然后,创建一个版本管理。
git init
git add .
git commit -m 'initialize'
先去掉 components 里的页面和默认样式。只留 App.vue 文件
rm -rf ./src/components
rm -rf ./src/assets
然后,修改 App.vue 文件。
<template>
<h2>Home</h2>
</template>
删除 main.ts 中的样式引入。运行起来看看。没问题,添加 git 版本控制。
git add . && git commit -m '删除默认页面和样式'
使用
先安装 swiper。
pnpm add swiper
开始在 App.vue 中编写相关的代码
<template>
<swiper
direction="vertical"
:modules="[FreeMode, Mousewheel]"
:space-between="0"
:slides-per-view="'auto'"
:allow-touch-move="false"
:pagination="{ clickable: true }"
:mousewheel="{ forceToAxis: true, sensitivity: 10, releaseOnEdges: true }"
style="height: 100vh"
class="swiper-pointer-events"
@swiper="onSwiper"
@slideChange="onSlideChange"
ref="swiperRef"
>
<swiper-slide class="slide" style="background: #444">
<div class="slide-content">
<h2>点绛唇·屏却相思</h2>
<p>屏却相思,近来知道都无益</p>
<p>不成抛掷,梦里终相觅</p>
<p>醒后楼台,与梦俱明灭</p>
<p>西窗白,纷纷凉月,一院丁香雪</p>
</div>
</swiper-slide>
<swiper-slide class="slide" style="background: #333">
<div class="slide-content">
<h2>《望江南》</h2>
<p>多少恨,昨夜梦魂中</p>
<p>还似旧时游上苑</p>
<p>车如流水马如龙</p>
<p>花月正春风</p>
</div>
</swiper-slide>
<swiper-slide class="slide" style="background: #222">
<div class="slide-content">
<h2>《蟾宫曲·春情》</h2>
<p>平生不会相思</p>
<p>才会相思,便害相思</p>
<p>身似浮萍,心如飞絮,气若游丝,</p>
<p>空一缕余香在此</p>
</div>
</swiper-slide>
<swiper-slide class="slide slide-footer" style="height: 240px; background: #111">
<p>© 2025 Vini123.Com All rights reserved.</p>
</swiper-slide>
</swiper>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Swiper, SwiperSlide } from 'swiper/vue'
import { FreeMode, Mousewheel } from 'swiper/modules'
import 'swiper/css'
const swiperRef = ref()
const activeIndex = ref(0)
const onSwiper = (swiper: any) => {
swiperRef.value = swiper
activeIndex.value = swiper.activeIndex
}
const onSlideChange = () => {
if (swiperRef.value) {
activeIndex.value = swiperRef.value.activeIndex
}
}
</script>
<style>
html,
body {
margin: 0;
padding: 0;
}
</style>
<style scoped>
.slide {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.slide-footer {
color: #fff;
align-items: flex-end;
padding-bottom: 20px;
}
.slide-content {
color: #fff;
text-align: center;
background: rgba(0, 0, 0, 0.4);
padding: 30px 100px;
border-radius: 24px;
}
</style>
这里要注意一点。并不是所有的页面都是整个视口的高度。比如底部的信息。这个时候需要设置 slides-per-view:auto
和 FreeMode
。其他的根据实际情况操作。这里页面高度是整个视口的高度 100vh,有的时候,swiper 是某个页面的一部分,高度自然不一样。
运行起来看看,提交版本控制。
git add .
git commit -m '安装 swiper,编写 demo'