---
name: vue3-mobile-starter
description: 快速搭建 Vue3 移动端应用(TS、Router、Pinia、SCSS、Vant、Vite、Axios、px-to-viewport)。当用户创建新的 Vue3 移动端项目时调用。
---
# 技能详细说明
用于快速初始化 Vue3 移动端项目骨架,内置 TypeScript、Vue Router、Pinia、SCSS、Vant、Vite、Axios、postcss-px-to-viewport-8-plugin。遵循本项目规范输出文件模板与执行步骤,确保以 pnpm 安装与运行。
## 1. 核心规范
- 技术栈:Vue 3 + TypeScript + Vite + Pinia + Vue Router + Axios + SCSS + Vant
- 构建工具:Vite(包含 PostCSS 配置,使用 postcss-px-to-viewport-8-plugin)
- 包管理器:pnpm(必须使用 pnpm 安装与运行脚本)
- 移动端适配:vw 转换(viewportWidth 推荐 375),附加完整可调参数
- 目录结构:清晰分层(router、store、styles、utils、views、components)
- 代码要求:函数需具备 JSDoc 注释,包含参数、返回值、异常;变量需添加用途注释
## 2. 代码结构模板
以下模板可直接复制到新工程中使用。按需调整命名与路径。
### 2.1 package.json(片段)
说明:确保使用 pnpm 脚本与常用命令。
```json
{
"name": "vue3-mobile-starter",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview --port 5173"
},
"dependencies": {
"axios": "^1.6.8",
"pinia": "^2.1.7",
"vant": "^4.8.0",
"vue": "^3.4.0",
"vue-router": "^4.3.0"
},
"devDependencies": {
"autoprefixer": "^10.4.18",
"postcss": "^8.4.35",
"postcss-px-to-viewport-8-plugin": "^1.2.0",
"sass": "^1.71.1",
"typescript": "^5.3.3",
"vite": "^5.1.0",
"@types/node": "^20.11.25"
}
}
```
### 2.2 tsconfig.json(基础)
```json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"jsx": "preserve",
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}
```
### 2.3 vite.config.ts(含 PostCSS 与别名)
```ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "node:path";
import pxToViewport from "postcss-px-to-viewport-8-plugin";
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
},
},
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/variables.scss" as *;`,
},
},
postcss: {
plugins: [
pxToViewport({
unitToConvert: "px",
viewportWidth: 375,
unitPrecision: 6,
propList: ["*"],
viewportUnit: "vw",
fontViewportUnit: "vw",
selectorBlackList: [".ignore", ".hairlines"],
minPixelValue: 1,
mediaQuery: false,
replace: true,
exclude: [],
landscape: false,
}),
],
},
},
server: {
port: 5173,
open: true,
},
});
```
### 2.4 postcss.config.js(可选,若不在 Vite 中内联)
```js
/* eslint-disable @typescript-eslint/no-var-requires */
const pxToViewport = require("postcss-px-to-viewport-8-plugin");
module.exports = {
plugins: [
pxToViewport({
unitToConvert: "px",
viewportWidth: 375,
unitPrecision: 6,
propList: ["*"],
viewportUnit: "vw",
fontViewportUnit: "vw",
selectorBlackList: [".ignore", ".hairlines"],
minPixelValue: 1,
mediaQuery: false,
replace: true,
exclude: [],
landscape: false,
}),
],
};
```
### 2.5 index.html(视口)
```html
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
/>
<link rel="icon" href="/favicon.ico" />
<title>Vue3 Mobile</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
```
### 2.6 src/main.ts(应用入口)
```ts
import { createApp } from "vue";
import { createPinia } from "pinia";
import { router } from "@/router";
import App from "./App.vue";
import "vant/lib/index.css";
import "@/styles/index.scss";
import { Button } from "vant";
// app: 应用实例
const app = createApp(App);
// store: 全局状态管理
const store = createPinia();
/**
* 初始化应用
* @throws Error 初始化过程中抛出的未捕获异常
* @returns void 无返回值
*/
function bootstrap(): void {
// 注册 Pinia
app.use(store);
// 注册路由
app.use(router);
// 注册基础 Vant 组件(示例)
app.use(Button);
// 挂载应用
app.mount("#app");
}
bootstrap();
```
### 2.7 src/router/index.ts(路由)
```ts
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
// routes: 路由表
const routes: RouteRecordRaw[] = [
{
path: "/",
name: "home",
component: () => import("@/views/Home.vue"),
},
];
/**
* 创建并导出路由实例
* @returns 路由实例
* @throws Error 当路由初始化失败时抛出
*/
export const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
});
```
### 2.8 src/store/index.ts(Pinia)
```ts
import { createPinia } from "pinia";
/**
* 创建 Pinia 实例(在 main.ts 中使用)
* @returns Pinia 实例
*/
export function setupStore() {
// pinia: 全局状态实例
const pinia = createPinia();
return pinia;
}
```
### 2.9 src/store/modules/app.ts(示例 Store)
```ts
import { defineStore } from "pinia";
// AppState: 应用状态类型
interface AppState {
// title: 应用标题
title: string;
}
/**
* 应用级 Store
* @param 无
* @returns Store 实例
* @throws Error 无特别异常
*/
export const useAppStore = defineStore("app", {
state: (): AppState => ({
title: "Vue3 Mobile",
}),
actions: {
/**
* 设置标题
* @param newTitle 新标题
* @returns void 无返回值
* @throws Error 当 newTitle 非法时可能抛出
*/
setTitle(newTitle: string): void {
this.title = newTitle;
},
},
});
```
### 2.10 src/utils/request.ts(Axios 封装)
```ts
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
// BASE_TIMEOUT: 基础超时时间(毫秒)
const BASE_TIMEOUT = 15000;
/**
* 创建 Axios 实例
* @returns Axios 实例
* @throws Error 创建实例失败
*/
function createService(): AxiosInstance {
// service: Axios 实例
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || "/",
timeout: BASE_TIMEOUT,
});
// 请求拦截
service.interceptors.request.use(
(config: AxiosRequestConfig) => {
// token: 鉴权令牌
const token = "";
if (token) {
config.headers = config.headers || {};
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
},
);
// 响应拦截
service.interceptors.response.use(
(response: AxiosResponse) => {
return response.data;
},
(error) => {
return Promise.reject(error);
},
);
return service;
}
// http: 全局复用的 Axios 实例
export const http = createService();
/**
* 通用请求方法
* @template T 返回数据类型
* @param config Axios 请求配置
* @returns Promise<T> 响应数据
* @throws Error 网络错误或业务异常
*/
export function request<T = unknown>(config: AxiosRequestConfig): Promise<T> {
return http.request<any, T>(config);
}
```
### 2.11 src/styles/variables.scss(变量示例)
```scss
// $primary-color: 主题色
$primary-color: #1989fa;
```
### 2.12 src/styles/index.scss(全局样式)
```scss
/* 基础重置与通用样式 */
html,
body,
#app {
height: 100%;
}
body {
margin: 0;
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
Arial, "Noto Sans", "Apple Color Emoji", "Segoe UI Emoji";
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #fff;
}
.text-primary {
color: $primary-color;
}
```
### 2.13 src/views/Home.vue(示例页面)
```vue
<template>
<section class="home">
<van-button type="primary" @click="handleClick">{{ title }}</van-button>
</section>
</template>
<script setup lang="ts">
import { computed } from "vue";
import { useAppStore } from "@/store/modules/app";
// store: 应用 Store
const store = useAppStore();
// title: 计算后的标题
const title = computed(() => store.title);
/**
* 点击事件处理
* @returns void 无返回值
* @throws Error 无特别异常
*/
function handleClick(): void {
store.setTitle("Hello Mobile");
}
</script>
<style lang="scss" scoped>
.home {
padding: 16px;
}
</style>
```
### 2.14 src/App.vue(应用根组件)
```vue
<template>
<router-view />
<!-- 可在此放置全局层级组件,例如全局提示 -->
<div class="app-footer">Vue3 Mobile Starter</div>
<router-link to="/" style="display: none">home</router-link>
<!-- router-link 仅为确保路由依赖在构建期被保留,可移除 -->
<!-- 上述注释说明仅为模板指引,可按需删除 -->
</template>
<script setup lang="ts">
// 无特别逻辑
</script>
<style lang="scss">
.app-footer {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 12px 0;
text-align: center;
color: #666;
font-size: 12px;
}
</style>
```
### 2.15 环境变量(.env.development 示例)
```env
VITE_API_BASE_URL=/api
```
## 3. 注意事项
1. 统一使用 pnpm:安装与运行脚本均使用 pnpm(避免 npm/yarn)。
2. Vant 引入:示例仅展示按钮组件按需注册,实际项目请按需引入其他组件。
3. px-to-viewport:推荐 viewportWidth=375;若视觉稿为 750,可设置 750,并据此调整设计规范。
4. 字体与 1px 细线:如需对特定选择器禁用转换,使用 `.ignore` 前缀或设置 selectorBlackList。
5. Axios 封装:根据后端返回结构调整响应拦截与错误处理逻辑;谨慎处理 token。
6. 样式组织:建议使用 SCSS 模块与变量管理主题;按需覆盖 Vant 样式变量。
## 4. 执行步骤
1. 创建模板工程(Vue + TS):
- pnpm create vite my-app --template vue-ts
2. 进入目录并安装依赖:
- cd my-app
- pnpm add vue-router pinia axios vant
- pnpm add -D sass postcss autoprefixer postcss-px-to-viewport-8-plugin
3. 配置 Vite 与 PostCSS:
- 复制 2.3 的 vite.config.ts(或使用 2.4 的 postcss.config.js)
4. 建立目录与文件:
- src/router、src/store、src/utils、src/styles、src/views
- 复制 2.6~2.15 示例文件
5. 运行与预览:
- pnpm dev
- pnpm build && pnpm preview
6. 可选优化:
- 引入按需自动导入(unplugin-auto-import/unplugin-vue-components)进一步简化 Vant 使用
- 接入 ESLint/Prettier/Husky 保障代码质量
当用户需要从零创建新的 Vue3 移动端项目且要求集成 TypeScript、Vue Router、Pinia、SCSS、Vant、Vite、Axios 与 postcss-px-to-viewport-8-plugin 时,调用本技能以生成模板与步骤清单。