1. 单文件组件:Vue开发的工程化基石
在Vue项目实战中,单文件组件(Single File Components,简称SFC)是构建现代前端应用的标配方案。一个典型的.vue文件包含以下结构:
vue复制<template>
<!-- HTML模板 -->
<div class="example">{{ msg }}</div>
</template>
<script>
// JavaScript逻辑
export default {
data() {
return {
msg: 'Hello Vue!'
}
}
}
</script>
<style>
/* CSS样式 */
.example {
color: red;
}
</style>
这种将模板、逻辑和样式封装在单一文件中的设计,解决了传统开发方式的三大痛点:
- 全局命名冲突:每个组件都是独立的作用域
- 关注点分离:相关代码高内聚低耦合
- 开发体验:支持语法高亮、热重载等现代特性
提示:使用VSCode开发时,推荐安装Volar插件替代Vetur,以获得更好的TypeScript支持和模板类型检查
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. SFC核心工作机制解析
2.1 编译过程揭秘
当运行npm run dev时,Vue CLI内部的工作流程:
- 依赖分析:通过
@vue/compiler-sfc解析.vue文件 - 模板编译:将template转换为render函数
- 样式处理:通过PostCSS应用autoprefixer等插件
- 代码生成:输出浏览器可执行的JavaScript模块
关键编译产物示例:
javascript复制// 编译后的render函数
function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", {
class: "example"
}, _toDisplayString(_ctx.msg), 1 /* TEXT */))
}
2.2 作用域样式原理
使用scoped属性时,Vue会通过PostCSS插件自动添加属性选择器:
css复制.example[data-v-f3f3eg9] {
color: red;
}
对应的DOM会被编译为:
html复制<div class="example" data-v-f3f3eg9>Hello Vue!</div>
3. 高级SFC开发技巧
3.1 动态组件与代码分割
结合defineAsyncComponent实现按需加载:
javascript复制const AsyncComponent = defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
最佳实践:
- 配合webpack魔法注释命名chunk
- 添加加载状态和错误处理组件
3.2 自定义块扩展
除了标准的template/script/style,还可以定义:
vue复制<docs>
## 组件文档
这是一个示例组件
</docs>
<unit-test>
// 单元测试代码
</unit-test>
配置vue.config.js处理自定义块:
javascript复制module.exports = {
chainWebpack: config => {
config.module
.rule('docs')
.resourceQuery(/blockType=docs/)
.use('docs-loader')
.loader('./loaders/docs-loader.js')
}
}
4. 工程化实践与性能优化
4.1 组件设计原则
| 原则 | 实现方式 | 示例 |
|---|---|---|
| 单一职责 | 每个组件只做一件事 | Button.vue只处理点击交互 |
| 受控接口 | 明确props/emit定义 | 使用TypeScript接口 |
| 组合优先 | 使用slot而非prop传内容 | 基础布局组件设计 |
4.2 静态资源处理
不同位置引用的资源路径解析规则:
| 引用位置 | 示例 | 处理方式 |
|---|---|---|
| template | <img src="./assets/logo.png"> |
被webpack处理 |
| style | background: url(../assets/bg.jpg) |
被css-loader处理 |
| script | import img from '@/assets/icon.png' |
需要显式导入 |
注意:public目录下的文件应使用绝对路径引用,且不会经过webpack处理
4.3 性能优化方案
-
编译时优化:
- 开启模板预编译(
compilerOptions: { whitespace: 'condense' }) - 使用
@vue/compiler-sfc的cache配置
- 开启模板预编译(
-
运行时优化:
- 组件级代码分割(动态import)
- 使用
v-once和v-memo指令
-
构建优化:
javascript复制// vue.config.js module.exports = { chainWebpack: config => { config.optimization.splitChunks({ chunks: 'all', maxSize: 244 * 1024 // 拆分为244KB以下的chunk }) } }
5. 常见问题排查指南
5.1 样式污染问题
现象:组件样式影响全局
解决方案:
- 检查是否遗漏
scoped属性 - 深度选择器使用规范:
css复制/* 错误用法 */
::v-deep .child { color: red; }
/* 正确用法 */
:deep(.child) { color: red; }
5.2 热更新失效
典型排查步骤:
- 检查文件名大小写(Linux系统区分大小写)
- 确认组件命名无重复
- 检查webpack配置:
javascript复制devServer: {
hot: true,
hotOnly: true // Vue CLI默认配置
}
5.3 TypeScript支持问题
确保shims-vue.d.ts包含:
typescript复制declare module '*.vue' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
推荐配置:
json复制// tsconfig.json
{
"compilerOptions": {
"jsx": "preserve",
"strict": true,
"paths": {
"@/*": ["src/*"]
}
}
}
6. 生态工具链集成
6.1 状态管理方案对比
| 方案 | SFC集成方式 | 适用场景 |
|---|---|---|
| Pinia | import { useStore } from '@/stores' |
新项目首选 |
| Vuex | this.$store |
遗留项目维护 |
| Provide/Inject | provide('key', value) |
小型组件树 |
6.2 测试工具配置
Jest测试配置示例:
javascript复制// jest.config.js
module.exports = {
moduleFileExtensions: ['js', 'json', 'vue'],
transform: {
'^.+\\.vue$': '@vue/vue3-jest',
'^.+\\.js$': 'babel-jest'
},
testEnvironment: 'jsdom'
}
测试用例结构:
javascript复制import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('renders message', () => {
const wrapper = mount(Component, {
props: { msg: 'Hello' }
})
expect(wrapper.text()).toContain('Hello')
})
6.3 自定义指令开发
典型指令实现:
javascript复制// src/directives/highlight.js
export default {
mounted(el, binding) {
el.style.backgroundColor = binding.value || 'yellow'
}
}
// 在SFC中使用
<template>
<div v-highlight="'#ff0'">重点内容</div>
</template>
7. 从Vue 2到Vue 3的迁移策略
7.1 破坏性变更处理
| Vue 2特性 | Vue 3替代方案 | 修改建议 |
|---|---|---|
Filters |
计算方法/工具函数 | 全局替换为methods |
EventBus |
mitt库 |
引入事件中心模块 |
$listeners |
v-bind="$attrs" |
合并到attrs处理 |
7.2 组合式API改造
改造前(Options API):
javascript复制export default {
data() {
return { count: 0 }
},
methods: {
increment() {
this.count++
}
}
}
改造后(Composition API):
javascript复制import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
const increment = () => count.value++
return { count, increment }
}
}
7.3 构建工具升级
推荐迁移路径:
- 使用
vue-cli创建新项目 - 逐步迁移组件(保持两个版本共存)
- 最终移除
@vue/compat兼容层
迁移检查清单:
- [ ] 全局API调用改为
import { ref } from 'vue' - [ ] 替换
Vue.extend为defineComponent - [ ] 更新Vue Router到4.x版本
- [ ] 测试所有生命周期钩子的兼容性
8. 企业级项目实践
8.1 组件库开发规范
目录结构示例:
code复制components/
├─ Button/
│ ├─ Button.vue // 组件实现
│ ├─ index.ts // 组件注册
│ ├─ README.md // 使用文档
│ └─ __tests__/ // 单元测试
├─ theme/ // 样式主题
└─ index.ts // 全局导出
按需加载配置:
javascript复制// babel.config.js
module.exports = {
plugins: [
['import', {
libraryName: 'your-lib',
customName: name => `your-lib/es/${name.slice(3)}`
}]
]
}
8.2 微前端集成方案
基于qiankun的集成示例:
javascript复制// 主应用配置
import { registerMicroApps, start } from 'qiankun'
registerMicroApps([
{
name: 'vue-app',
entry: '//localhost:7101',
container: '#subapp',
activeRule: '/vue'
}
])
start()
子应用适配:
javascript复制// src/public-path.js
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
// main.js
let instance = null
function render(props = {}) {
instance = createApp(App)
instance.mount(props.container || '#app')
}
export async function bootstrap() {}
export async function mount(props) { render(props) }
export async function unmount() { instance.unmount() }
8.3 服务端渲染优化
Nuxt.js关键配置:
javascript复制// nuxt.config.js
export default {
target: 'server',
render: {
compressor: { threshold: 1024 } // 启用响应压缩
},
build: {
extractCSS: true, // 提取CSS
optimizeCSS: true // 优化CSS
}
}
性能优化指标:
- 首屏加载时间 < 1s
- 可交互时间 < 2s
- 最大内容绘制 < 1.5s
9. 调试与性能分析
9.1 Vue DevTools高级用法
性能分析步骤:
- 打开"Performance"选项卡
- 记录组件渲染时间线
- 分析:
- 不必要的重新渲染(黄色标记)
- 长任务(红色标记)
- 内存泄漏(堆大小持续增长)
9.2 Chrome性能分析
关键指标采集:
javascript复制// 在组件中埋点
export default {
mounted() {
performance.mark('componentMountedStart')
// 初始化逻辑...
performance.mark('componentMountedEnd')
performance.measure(
'componentMountDuration',
'componentMountedStart',
'componentMountedEnd'
)
}
}
9.3 内存泄漏排查
典型泄漏场景:
- 全局事件监听未移除
- 定时器未清理
- 大对象缓存未释放
检查工具:
javascript复制// 在控制台执行
function printLeaks() {
const list = []
for (const comp of window.__VUE_DEVTOOLS_CONTEXT__.apps[0]._instance
.ctx.$children) {
list.push(comp)
}
console.log('Active components:', list.length)
}
10. 前沿技术探索
10.1 Vite加速原理
与传统打包工具对比:
| 指标 | webpack | Vite |
|---|---|---|
| 启动时间 | 20-30s | <1s |
| HMR更新 | 1-3s | 50-300ms |
| 构建输出 | bundle | 原生ESM |
配置示例:
javascript复制// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
optimizeDeps: {
include: ['lodash-es'] // 预构建依赖
}
})
10.2 响应式编译器优化
Vue 3.2+的reactivityTransform:
javascript复制// 启用前
const count = ref(0)
const double = computed(() => count.value * 2)
// 启用后
let count = $ref(0)
const double = $computed(() => count * 2)
配置方式:
javascript复制// vite.config.js
export default defineConfig({
plugins: [
vue({
reactivityTransform: true
})
]
})
10.3 Web Components集成
封装Vue组件为自定义元素:
javascript复制// main.js
import { defineCustomElement } from 'vue'
import MyComponent from './MyComponent.ce.vue'
customElements.define(
'my-component',
defineCustomElement(MyComponent)
)
使用限制:
- 需要
@vitejs/plugin-vue@^2.4.0 - 不支持Scoped样式
- 插槽内容需手动分发
11. 安全最佳实践
11.1 XSS防护措施
安全编码规范:
vue复制<template>
<!-- 危险用法 -->
<div v-html="userProvidedContent"></div>
<!-- 安全用法 -->
<div>{{ sanitizedContent }}</div>
</template>
<script>
import DOMPurify from 'dompurify'
export default {
computed: {
sanitizedContent() {
return DOMPurify.sanitize(this.userProvidedContent)
}
}
}
</script>
11.2 CSP合规配置
Content-Security-Policy示例:
code复制Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline' https://unpkg.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
connect-src 'self' https://api.example.com;
11.3 敏感数据处理
加密存储方案:
javascript复制// src/utils/crypto.js
import CryptoJS from 'crypto-js'
const SECRET_KEY = import.meta.env.VITE_CRYPTO_KEY
export function encrypt(data) {
return CryptoJS.AES.encrypt(
JSON.stringify(data),
SECRET_KEY
).toString()
}
export function decrypt(ciphertext) {
const bytes = CryptoJS.AES.decrypt(ciphertext, SECRET_KEY)
return JSON.parse(bytes.toString(CryptoJS.enc.Utf8))
}
12. 移动端适配方案
12.1 响应式布局实现
Viewport配置:
html复制<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
CSS适配方案:
css复制/* rem基准值 */
html {
font-size: calc(100vw / 7.5); /* 设计稿宽度750px */
}
/* 媒体查询断点 */
@media screen and (max-width: 480px) {
.container {
padding: 0 10px;
}
}
12.2 手势事件处理
使用@touch指令:
vue复制<template>
<div
@touchstart="handleStart"
@touchmove="handleMove"
@touchend="handleEnd"
>滑动区域</div>
</template>
<script>
export default {
methods: {
handleStart(e) {
this.startX = e.touches[0].clientX
},
handleMove(e) {
this.deltaX = e.touches[0].clientX - this.startX
}
}
}
</script>
12.3 性能优化技巧
- 减少DOM节点:虚拟滚动优化
- 避免重绘:使用transform替代top/left
- 图片懒加载:
vue复制<template>
<img v-lazy="imageSrc" alt="">
</template>
<script>
import { Lazyload } from 'vant'
app.use(Lazyload, {
loading: require('@/assets/loading.gif'),
error: require('@/assets/error.png')
})
</script>
13. 国际化解决方案
13.1 Vue I18n集成
基础配置:
javascript复制// src/i18n.js
import { createI18n } from 'vue-i18n'
const messages = {
en: {
greeting: 'Hello!'
},
zh: {
greeting: '你好!'
}
}
export default createI18n({
locale: 'en',
messages
})
组件内使用:
vue复制<template>
<p>{{ $t('greeting') }}</p>
</template>
<script>
import { useI18n } from 'vue-i18n'
export default {
setup() {
const { t } = useI18n()
return { t }
}
}
</script>
13.2 动态语言切换
实现方案:
javascript复制// store/locale.js
import { ref, watch } from 'vue'
import { loadLocaleMessages } from '@/i18n'
export const currentLocale = ref('en')
export async function setLocale(locale) {
if (!loadedLocales.has(locale)) {
const messages = await import(`@/locales/${locale}.json`)
i18n.global.setLocaleMessage(locale, messages)
loadedLocales.add(locale)
}
currentLocale.value = locale
}
13.3 文案管理平台
推荐工具:
- Lokalise:企业级翻译管理
- Crowdin:开源友好型平台
- Phrase:开发者优先设计
集成流程:
javascript复制// 自动化同步脚本
import Phrase from '@phrase/phrase'
const phrase = new Phrase({
projectId: 'your-project-id',
secret: 'api-secret'
})
async function syncTranslations() {
await phrase.download({
fileFormat: 'i18next',
output: 'src/locales'
})
}
14. 可视化开发实践
14.1 ECharts集成
封装示例:
vue复制<template>
<div ref="chart" style="width: 600px; height: 400px;"></div>
</template>
<script>
import * as echarts from 'echarts'
export default {
mounted() {
this.initChart()
},
methods: {
initChart() {
const chart = echarts.init(this.$refs.chart)
chart.setOption({
xAxis: { type: 'category' },
yAxis: { type: 'value' },
series: [{ data: [120, 200, 150], type: 'line' }]
})
window.addEventListener('resize', () => chart.resize())
}
}
}
</script>
14.2 D3.js高级应用
与Vue的响应式结合:
vue复制<script>
import * as d3 from 'd3'
export default {
data() {
return { dataset: [5, 10, 15, 20, 25] }
},
watch: {
dataset: {
handler(newVal) {
this.updateChart(newVal)
},
deep: true
}
},
methods: {
updateChart(data) {
d3.select(this.$refs.svg)
.selectAll('circle')
.data(data)
.join('circle')
.attr('r', d => d)
.attr('cx', (d, i) => i * 50 + 30)
.attr('cy', 50)
}
}
}
</script>
14.3 WebGL集成
使用Three.js示例:
vue复制<script>
import * as THREE from 'three'
export default {
mounted() {
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75,
this.$refs.renderer.clientWidth / this.$refs.renderer.clientHeight,
0.1, 1000
)
const renderer = new THREE.WebGLRenderer()
renderer.setSize(this.$refs.renderer.clientWidth, this.$refs.renderer.clientHeight)
this.$refs.renderer.appendChild(renderer.domElement)
function animate() {
requestAnimationFrame(animate)
renderer.render(scene, camera)
}
animate()
}
}
</script>
15. 项目脚手架深度定制
15.1 自定义生成器
基于plop的组件生成:
javascript复制// plopfile.js
module.exports = function(plop) {
plop.setGenerator('component', {
description: 'Create a new component',
prompts: [{
type: 'input',
name: 'name',
message: 'Component name (PascalCase):'
}],
actions: [{
type: 'add',
path: 'src/components/{{name}}/{{name}}.vue',
templateFile: 'plop-templates/component.hbs'
}]
})
}
模板文件示例:
handlebars复制<template>
<div class="{{lowerCase name}}-container">
<!-- Component content -->
</div>
</template>
<script>
export default {
name: '{{name}}'
}
</script>
<style scoped>
.{{lowerCase name}}-container {
/* Styles */
}
</style>
15.2 自动化代码检查
Husky + lint-staged配置:
json复制// package.json
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,vue}": ["eslint --fix", "prettier --write"],
"*.{css,scss}": ["stylelint --fix", "prettier --write"]
}
}
15.3 智能代码提示
jsconfig.json配置:
json复制{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"components/*": ["src/components/*"]
}
},
"exclude": ["node_modules"]
}
配合VSCode的volar插件,可实现:
- 组件自动导入
- props类型提示
- 模板表达式校验
16. 微交互设计实现
16.1 动画性能优化
CSS动画最佳实践:
css复制/* 优先使用transform和opacity */
.box {
will-change: transform; /* 提前告知浏览器 */
transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
}
.box:hover {
transform: scale(1.05);
}
16.2 手势反馈设计
滑动删除实现:
vue复制<template>
<div
class="swipe-item"
@touchstart="startDrag"
@touchmove="onDrag"
@touchend="endDrag"
:style="{ transform: `translateX(${offsetX}px)` }"
>
<div class="content">可滑动内容</div>
<div class="actions">
<button @click="handleDelete">删除</button>
</div>
</div>
</template>
<script>
export default {
data() {
return { offsetX: 0, startX: 0 }
},
methods: {
startDrag(e) {
this.startX = e.touches[0].clientX
},
onDrag(e) {
this.offsetX = e.touches[0].clientX - this.startX
},
endDrag() {
if (this.offsetX < -100) {
this.offsetX = -80 // 显示操作按钮
} else {
this.offsetX = 0 // 恢复原位
}
}
}
}
</script>
16.3 加载状态设计
骨架屏实现方案:
vue复制<template>
<div v-if="loading" class="skeleton">
<div class="skeleton-header"></div>
<div class="skeleton-content"></div>
</div>
<div v-else class="actual-content">
<!-- 实际内容 -->
</div>
</template>
<style>
.skeleton {
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 0.6; }
50% { opacity: 1; }
}
</style>
17. 无障碍访问(A11Y)
17.1 ARIA属性应用
vue复制<template>
<button
aria-label="关闭弹窗"
@click="closeModal"
>
×
</button>
<div
role="alert"
aria-live="assertive"
v-if="errorMessage"
>
{{ errorMessage }}
</div>
</template>
17.2 键盘导航支持
实现可聚焦组件:
vue复制<script>
export default {
mounted() {
this.$el.setAttribute('tabindex', '0')
},
methods: {
handleKeydown(e) {
if (e.key === 'Enter') {
this.$emit('activate')
}
}
}
}
</script>
17.3 颜色对比度检测
使用postcss-a11y自动检查:
javascript复制// postcss.config.js
module.exports = {
plugins: [
require('postcss-a11y')({
colors: {
enabled: true,
level: 'AA',
lightness: {
enabled: true,
threshold: 4.5
}
}
})
]
}
18. 测试策略全覆盖
18.1 单元测试实践
测试工具链:
- Jest:测试运行器
- @vue/test-utils:组件挂载
- Testing Library:用户行为模拟
示例测试:
javascript复制import { render, fireEvent } from '@testing-library/vue'
import Counter from './Counter.vue'
test('increments count on click', async () => {
const { getByText } = render(Counter)
const button = getByText('Count is: 0')
await fireEvent.click(button)
expect(button.textContent).toBe('Count is: 1')
})
18.2 E2E测试方案
Cypress配置:
javascript复制// cypress/integration/component.spec.js
describe('Component Test', () => {
it('should navigate to about page', () => {
cy.visit('/')
cy.contains('About').click()
cy.url().should('include', '/about')
})
})
18.3 视觉回归测试
使用cypress-image-snapshot:
javascript复制// cypress/plugins/index.js
const { initPlugin } = require('cypress-image-snapshot/plugin')
module.exports = (on, config) => {
initPlugin(on, config)
return config
}
// 测试用例
it('should match screenshot', () => {
cy.visit('/')
cy.matchImageSnapshot('homepage')
})
19. 部署与CI/CD
19.1 静态资源部署
Nginx配置示例:
nginx复制server {
listen 80;
server_name yourdomain.com;
location / {
root /var/www/your-project/dist;
try_files $uri $uri/ /index.html;
gzip on;
gzip_types text/plain text/css application/json application/javascript;
}
}
19.2 自动化部署流程
GitHub Actions配置:
yaml复制name: Deploy
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v2
with:
name: dist
path: dist
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v2
with:
name: dist
- uses: appleboy/scp-action@master
with:
host: ${{ secrets.SSH_HOST }}
key: ${{ secrets.SSH_KEY }}
source: "dist/*"
target: "/var/www/your-project"
19.3 灰度发布策略
基于Cookie的分流方案:
javascript复制// router.js
router.beforeEach((to, from, next) => {
if (to.meta.experimental && !isInExperimentalGroup()) {
next('/old-version')
} else {
next()
}
})
function isInExperimentalGroup() {
const cookie = document.cookie.match(/experimental=([^;]+)/)
return cookie ? cookie[1] === 'true' : Math.random() < 0.1
}
20. 架构设计进阶
20.1 插件系统设计
典型插件结构:
javascript复制// plugins/analytics.js
export default {
install(app, options = {}) {
app.config.globalProperties.$track = (event) => {
console.log(`Track: ${event}`, options)
}
app.provide('analytics', {
pageView: () => $track('pageview')
})
}
}
// main.js
import analytics from './plugins/analytics'
app.use(analytics, { id: 'UA-XXXXX' })
20.2 依赖注入模式
组合式API中的provide/inject:
javascript复制// 祖先组件
import { provide } from 'vue'
export default {
setup() {
provide('theme', 'dark')
}
}
// 后代组件
import { inject } from 'vue'
export default {
setup() {
const theme = inject('theme', 'light') // 默认值
return { theme }
}
}
20.3 状态机管理
使用XState示例:
javascript复制import { createMachine, interpret } from 'xstate'
const toggleMachine = createMachine({
id: 'toggle',
initial: 'inactive',
states: {
inactive: { on: { TOGGLE: 'active' } },
active: { on: { TOGGLE: 'inactive' } }
}
})
const toggleService = interpret(toggleMachine)
.onTransition(state => console.log(state.value))
.start()
21. 调试技巧大全
21.1 自定义DevTools面板
实现步骤:
- 创建
src/devtools.js:
javascript复制export function installDevtools(app) {
app.config.globalProperties.$logState = () => {
console.log(store.state)
}
if (process.env.NODE_ENV === 'development') {
window.__MY_APP_DEVTOOLS__ = {
version: app.version,
utils: { inspectState: $logState }
}
}
}
- 在main.js中调用:
javascript复制import { installDevtools } from './devtools'
installDevtools(app)
21.2 错误追踪方案
Sentry集成:
javascript复制// src/utils/errorTracking.js
import * as Sentry from '@sentry/vue'
export function initSentry(app) {
Sentry.init({
app,
dsn: 'your-dsn',
integrations: [
new Sentry.BrowserTracing({
routingInstrumentation: Sentry.vueRouterInstrumentation(router)
})
],
tracesSampleRate: 0.2
})
}
21.3 性能监控实现
自定义指标采集:
javascript复制// src/utils/perf.js
export function trackPerf() {
const perfData = {
fcp: 0,
tti: 0
}
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.name === 'first-contentful-paint') {
perfData.fcp = entry.startTime
}
}
})
po.observe({ type: 'paint', buffered: true })
return perfData
}
22. 代码分割策略
22.1 路由级分割
动态导入路由组件:
javascript复制const routes = [
{
path: '/dashboard',
component: () => import('./views/Dashboard.vue'),
meta: { preload: true } // 标记为需要预加载
}
]
22.2 组件级分割
使用defineAsyncComponent:
javascript复制const HeavyComponent = defineAsyncComponent({
loader: () => import('./HeavyComponent.vue'),
loadingComponent: LoadingSpinner,
delay: 200 // 延迟显示loading的时间
})
22.3 预加载策略
路由守卫中预加载:
javascript复制router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.preload)) {
const matched = to.matched.flatMap(record =>
Object.values(record.components).map(component => component())
)
Promise.all(matched).then(next)
} else {
next()
}
})
23. 类型安全实践
23.1 组件Props验证
高级类型定义:
typescript复制interface Props {
size: 'small' | 'medium' | 'large'
disabled?: boolean
onChange?: (value: number) => void
}
defineProps<Props>()
23.2 全局类型扩展
增强Vue类型:
typescript复制// src/types/vue.d.ts
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$filters: {
currency(value: number): string
}
}
}
23.3 组合式API类型
类型化composables:
typescript复制interface UseCounterOptions {
initial?: number
min?: number
max?: number
}
export function useCounter(options: UseCounterOptions = {}) {
const count = ref(options.initial ?? 0)
function increment() {
if (options.max !== undefined && count.value >= options.max) return
count.value++
}
return { count, increment }
}
24. 设计系统集成
24.1 主题切换实现
CSS变量方案:
css复制:root {
--primary-color: #42b983;
--text-color: #2c3
