vue 开发规范
myzbx 2025-01-09 14:47 17 浏览
- 项目运行指南(#项目运行指南)
- 开发本地环境(#开发本地环境)
- 开发相关插件/工具(#开发相关插件工具)
- 开发规范(#开发规范)vue(#vue)【数据流向】(#数据流向)【慎用全局注册】(#慎用全局注册)【组件名称】(#组件名称)【组件中的 CSS】(#组件中的-css)【统一标签顺序】(#统一标签顺序)【其它注意事项】(#其它注意事项)【 !!!其它则严格遵守 vue 官方风格指南】(#a-target_blank-hrefhttpscnvuejsorgv2style-guide其它则严格遵守-vue-官方风格指南a)vue-router(#vue-router)vuex(#vuex)模块复用(#模块复用)其它杂项(#其它杂项)代码注释(#代码注释)工程目录结构(#工程目录结构)前端部署(#前端部署)给 UI 的建议(#给-ui-的建议)
项目运行指南
- 安装/更新依赖包:npm install说明:进入正式开发前需要提交 package-lock.json,正式开发后慎用 npm update
- 运行:启动为 dev 环境:npm run serve 或 npm start打包为 stage 环境:npm run build:stage打包为 prod 环境:npm run build检查并修复源码:npm run lint运行单元测试:npm run test:unit启用静态资源服务:npm run dist版本号操作:npm version major|minor|patch版本号格式说明:major(主版本号).minor(次版本号).patch(修订号)
开发本地环境
- 在 VSCode 中给予独立的工作区,而非文件夹,以获得最佳的智能感知
- 新建 .env.development.local 来重写部分环境变量,如:模拟数据:VUE_APP_MOCK = true接口服务:DEV_PROXY_TARGET_API = http://10.25.73.159:8081...
开发相关插件/工具
- VSCode 相关插件必要插件ESLintVeturPrettier - Code formatterpath Autocomplete推荐插件stylelintvscode-element-helper (element-ui 专用)Debugger for ChromeGitLens -- Git supercharged
- Chrome 相关插件必要插件vue-devtools推荐插件json-formatter
- 其它工具推荐:Postman 或 Postwoman
开发规范
vue
【数据流向】
- 单个组件的数据流
props、data/$store/$route、computed (由前面派生)
↓
template/render
↓
用户交互事件、初始化的异步回调
↓
data/$store/$route
- 组件间的数据流
- 父向子传递用 props
- 子向父传递用 vue 内置的自定义事件,即 this.$emit
- 父子双向传递用 <a target="_blank" href="https://cn.vuejs.org/v2/guide/components-custom-events.html">v-model</a> 或 <a target="_blank" href="https://cn.vuejs.org/v2/guide/components-custom-events.html">.sync</a>
- 跨越传递用 vuex(慎用 EventBus)
- 紧密耦合的祖孙间传递也可以考虑用父组件作为中间运输层
- 紧密耦合的兄弟间传递也可以考虑用父组件作为中转运输层
【慎用全局注册】
- 组件、混入 ... 应使用局部注册
- 局部注册可保持清晰的依赖关系,并且 IDE 智能感知更为友好
【组件名称】
- 名称大小写
<script>
import MyComponent from '@/components/MyComponent.vue' // 文件名使用 PascalCase 命名法
export default {
name: 'ComponentName', // 必须有 name
components: { MyComponent },
}
</script>
<template>
<div>
<!-- 在 template 中一律使用 kebab-case 方式调用 -->
<my-component />
<el-input />
</div>
</template>
- 使用前缀
- 非业务通用组件使用 Base 前缀
- <a href="#hash_Ex">扩展/包装第三方开源组件或内部公共库组件 (不建议使用高阶组件)</a> 使用 Ex 前缀
- 单例组件使用 The 前缀
【组件中的 CSS】
- 使用 <a target="_blank" href="https://vue-loader.vuejs.org/zh/guide/css-modules.html">CSS Modules</a>,基于如下考虑:
- 不让外部进行样式重写,避免强耦合 (可通过 props 来处理内部样式的变化)
- 放心使用简短且语义强的 class 名,无需多余的命名空间
- 使用方式
- 语法
/* 默认为局部 */
.xxx {
}
/* 从局部转到全局 */
:global(.yyy) {
}
// or
:global {
}
/* 从全局转到局部 */
:local(.zzz) {
}
// or
:local {
}
- 单个组件专属
<style lang="less" module></style>
- 多个组件共用 (*.module.less)
import style from './style.module.less'
【统一标签顺序】
- script --> template --> style,并使用空行分隔
【其它注意事项】
- 慎用 this.$refs、this.$parent、this.$root、provide/injectthis.$refs 一般用在第三方开源组件或内部公共库组件或非常稳定的组件,以调用显式声明的方法在万不得已的情况下需要暴露方法给外部调用时需要加 pub 前缀,如:this.$refs.pubFocus()
- 尽量不要在 watch 中直接变更数据,易造成死循环。数据变更应该交给用户交互事件或初始化的异步回调
- 组件中的 data 及 vuex 中的 state 应该可序列化,即不要存 undefined、function 等
【 <a target="_blank" href="https://cn.vuejs.org/v2/style-guide/">!!!其它则严格遵守 vue 官方风格指南</a>】
vue-router
- url 定义准则
- path 对应视图变化,query 对应数据变化,hash 对应滚动条位置
- path 使用 kebab-case 命名法,并且尽量与组件名相匹配(即一眼看到 path 就能迅速找到对应的组件)
路由 path:/project-list
↓
路由组件:@/views/ProjectList.vue | @/views/ProjectList/index.vue
- 命名路由的 name 值使用 kebab-case 命名法,并且嵌套时要带命名空间(使用简写)
export const routes = {
path: '/user-center',
name: 'user-center',
// ...
children: [
{
path: 'base-info',
name: 'uc-base-info', // 带命名空间 uc-
// ...
},
],
}
- 当组件依赖 $route 作为核心数据时,要使用<a target="_blank" href="https://router.vuejs.org/zh/guide/essentials/passing-props.html">路由组件传参</a>,与 $route 解耦,也使得依赖更为显式清晰
export const routes = {
path: '/project-detail',
props: ({ query: { id } }) => ({ id }),
// ...
}
- 视图跳转尽量使用声明式(特别是 PC 端)
<router-link :to="path | { name, ... }">使用声明式</router-link>
<a @click="$router.push(...)">使用命令式</a>
vuex
- 需要由 vuex 管理的数据
- 组件间共享的响应式数据
- 组件间需要跨越传递的数据
- getter、mutation、action、module 使用驼峰命名法
- module 应避免嵌套,尽量扁平化
- module 应该启用命名空间 namespaced: true
模块复用
- 避免重复造轮子,多使用成熟的现成工具/类库/组件,如:lodash、qs、url-parse、date-fns/format 等
- 模块设计原则:
- 高内聚低耦合、可扩展
- 不要去改变模块输入的数据 (引用类型),如:函数参数、组件 prop
- 模块的入参为可选 Boolean 时,默认值应设计为 false如:hasToolbar?=false 或 noToolbar?=false
- …
- 方法接口的设计
// 参数类型与个数要保持稳定
// 建议参数不要超过3个,且预留一个 options 对象,以提高扩展性
// 方法尽量纯净 (纯函数思想)
export function myMethod1(a, options) {} // 当必选参数只有一个时
export function myMethod2(a, b, options) {} // 当必选参数只有两个时
export function myMethod3(options) {} // 当必选参数有两个以上时
export function myMethod4(options) {} // 当所有参数都是可选时
// 有时为了提高灵活性,参数类型可以是两重,一重是期望值,另一重是返回期望值的函数 (可带参)
export function myMethod5(a) {
a = typeof a === 'function' ? a() : a
}
- <span id="hash_Ex">扩展/包装第三方开源组件或内部公共库组件 (不建议使用高阶组件)</span>
- 使用 extends 混入 (相关命名需要加 ex 前缀,防止覆盖)
- 使用<a target="_blank" href="https://cn.vuejs.org/v2/guide/render-function.html">函数式组件</a>包装
其它杂项
- IDE 统一使用 VSCode,并统一使用相关插件及配置
- js 变量声明尽量使用 const
- js 变量或对象属性使用驼峰命名法
- js 私有变量或对象私有属性使用 _ 前缀 (注意: <a target="_blank" href="https://cn.vuejs.org/v2/style-guide">vue 组件属性不要使用 _ 前缀</a>)
// 表明该变量仅在 createId 方法中使用 (与 createId 方法紧挨着)
let _count = 0
const createId = () => `${Date.now()}_${++_count}`
// 适时使用立即执行函数可以简洁作用域及保护私有变量
const createId = (() => {
let count = 0
return () => `${Date.now()}_${++count}`
})()
- 导入模块时不要省略后缀(js 除外),利于 IDE 感知
- 导入当前目录以外的模块时,建议使用'@'别名
// js
import XxxXxx from '@/components/XxxXxx.vue'
<!-- template -->
<img src="@/assets/logo.png" />
/* style */
@import '~@/styles/vars.less';
.xxx {
background: url('~@/assets/logo.png');
}
- 严格遵守 ESLint 语法校验,警告级别的也要处理 (暂时用不到的代码可以先注释掉)
- css
- 全局 class 使用 g- 前缀
- CSS 选择器应避免深嵌套,尽量的扁平化
- 关键选择器 (最右边) 避免使用通配符 *
代码注释
- 文件头部注释
- 脚本文件、样式文件
/**
* 说明
* @author 作者
*/
- vue 文件
<!-- 说明 -->
<!-- @author 作者 -->
- js 注释 (结合 <a target="_blank" href="https://jsdoc.app/">JSDoc 注释标准</a>,帮助 IDE 智能感知)
- 注释格式
/**
* 文件头部、大的区块、JSDoc
*/
/* 一般的区块 */
// 小的区块、行
- <a target="_blank" href="https://jsdoc.app/howto-es2015-modules.html">ES 2015 Modules</a>
/**
* 使用 param 表示函数形参
* 使用 returns 表示函数返回值
* @param {类型} data
* @param {object} [options] 可选参数
* @param {类型} options.xxx
* @param {类型 =} options.yyy 可选属性
* @returns {类型}
*/
export function myMethod(data, options) {}
/**
* 使用 type 进行类型断言
* @type {import('vue-router').RouteConfig[]}
*/
const routes = []
/**
* 使用 typedef 定义类型,方便多处使用(命名时需要首字母大写)
* @typedef {routes[0]} RouteConfig
* @param {(meta: object, route: RouteConfig) => boolean} filterCallback
* @returns {RouteConfig[]}
*/
export const filterMapRoutes = function(filterCallback) {}
/**
* 类型参考:https://www.tslang.cn/docs/handbook/basic-types.html
*
* 基本
* @type {boolean}
* @type {number}
* @type {string}
* @type {1 | 2 | 3}
* @type {'a' | 'b' | 'c'}
*
* 数组
* @type {Array}
* @type {string[]}
*
* 函数
* @type {Function}
* @type {(data) => void}
* @type {(data: Array) => void | boolean}
*
* 对象
* @type {object}
*
* 联合
* @type {number | string}
* @type {boolean | (() => boolean)}
*
* 导入 ts 类型
* @type {import('xxx').yyy}
*
* 从现有的 js 变量或 ts 类型进行推导
* @type {Parameters<fn>} 取函数形参的类型
* @type {Parameters<fn>[0]} 取函数第一个形参的类型
* @type {ReturnType<fn>} 取函数返回值的类型
* @type {obj['xxx']} 取指定属性值的类型(不能使用点语法)
* ...
*/
- <a target="_blank" href="https://jsdoc.app/howto-es2015-classes.html">ES 2015 Classes</a>
- 待完成或待优化的地方
/* TODO: 说明 */
- css 注释
- 全局样式需要写注释
/* 说明 */
.g-class1 {
}
/* 说明 */
.g-class2 {
}
- vue template 注释
- 适当使用注释与空行
<!-- 说明 -->
<div>block1</div>
<!-- 说明 -->
<div>block2</div>
工程目录结构
|-- .env.development ------------ dev 环境变量
|-- .env.development.local ------ dev 本地环境变量 (被 git 忽略,需手动新建,用来重写部分环境变量)
|-- .env.production-stage ------- stage 环境变量
|-- .env.production ------------- prod 环境变量
|-- .env.test
|-- .vscode --------------------- 统一 VSCode 插件及配置
|-- static-server.js ------------ 静态资源服务 (node 运行),通常用于预览/检查打包结果,或者临时给其他人员启用前端服务
|-- docs ------------------------ 开发文档
| |-- README.html ------------- 由 ../README.md 手动生成 (使用 VSCode 插件 Markdown Preview Enhanced)
| |-- xxx.md
| |-- xxx.html
|-- public
| |-- favicon.ico
| |-- index.html
| |-- libs -------------------- 不支持模块化加载的第三方 ES5 类库/模块 (只能通过全局变量引用)
|-- src
|-- main.js
|-- App.vue
|-- libs -------------------- 支持模块化加载但是无法通过 npm 安装的第三方 ES5 类库/模块
|-- assets
|-- styles
| |-- global.less
| |-- reset.less
| |-- vars.less ----------- less 全局变量/函数 (webpack 自动注入)
| |-- xxx.less
|-- scripts
| |-- utils --------------- 通用方法
| |-- constants ----------- 常量 (多使用 Object.freeze)
| |-- xxx.js
| |-- http ---------------- axios 实例
| |-- index.js
| |-- http.js
| |-- createAxios.js
| |-- xxx.js
|-- injects ----------------- vue 全局注册 (慎用)
| |-- index.js
| |-- $xxx.js
| |-- v-xxx.js
| |-- mixin_xxx.js
| |-- xxx.js
|-- element-ui
| |-- index.js
| |-- rewrite ------------- 主题样式复写
| |-- index.less
| |-- xxx.less
|-- vant
| |-- index.js
| |-- vars.less ----------- 内置变量复写
| |-- rewrite ------------- 主题样式复写
| |-- index.less
| |-- xxx.less
|-- router
| |-- index.js
| |-- routes.js
| |-- registerInterceptor.js
|-- store
| |-- index.js
| |-- root.js
| |-- xxx.js
|-- api
| |-- xxx.js
| |-- mock ---------------- 模拟数据
| |-- index.js
| |-- createMock.js
| |-- xxx.js
|-- components
| |-- BaseXxx.vue --------- 非业务通用组件
| |-- TheXxx.vue ---------- 单例组件
| |-- ExXxx.vue ----------- 扩展/包装第三方开源组件或内部公共库组件
| |-- XxxXxx.vue
| |-- ComponentExamples --- 非单例公共组件需要在这里写示例
| | |-- index.vue
| | |-- XxxXxx.vue
| |-- SvgIcon ------------- svg-sprite 图标组件
| | |-- index.vue
| | |-- icons
| |-- directives ---------- 可复用的自定义指令(局部注册)
| | |-- xxx.js
| |-- mixins -------------- 可复用的混入(局部注册)
| |-- xxx.js
|-- views
|-- Xxx.vue
|-- Xxx ----------------- 除了 api 和 vuex,其它的专属模块要内聚在同一目录下
|-- index.vue
|-- Xxx.vue --------- 相关页面/子页面/子路由
|-- xxx.js
|-- xxx.module.less
|-- components ------ 存放私有组件
前端部署
- 跨域处理
- 使用代理或 <a target="_blank" href="https://www.baidu.com/s?wd=cors跨域">CORS</a>
- history 模式<a target="_blank" href="https://router.vuejs.org/zh/guide/essentials/history-mode.html">路由处理</a>
- 如果 url 匹配的不是静态资源 (不带后缀的),则返回 /index.html 页面
- 客户端缓存处理 (配置响应头)
- 静态资源
- 不缓存 /index.html
Cache-Control: no-store
强缓存 /static-hash/**/*
Cache-Control: public,max-age=31536000
<a target="_blank" href="https://www.baidu.com/s?wd=http协商缓存">协商缓存</a> (默认)
Cache-Control: no-cache
Etag: xxx
Last-Modified: xxx
XHR (解决 IE 缓存问题)
Cache-Control: no-cache
- gzip 压缩
- 静态资源:启用 gzip 压缩 (除了像素型图片)
- XHR:发给客户端的响应数据超过指定阀值时应启用 gzip 压缩
给 UI 的建议
- 对于中后台项目,在画 UI 界面时,建议参考前端已选型的开源组件库,并推荐使用开源组件库提供的制图元件/模板,如:<a target="_blank" href="http://element-cn.eleme.io/#/zh-CN/resource">element-ui</a>
- 对于 H5 项目,如:<a target="_blank" href="https://youzan.github.io/vant/#/zh-CN/design">vant</a>
相关推荐
- 攀升战境S5电竞主机评测:NVIDIA RTX 3060实力助阵,光追游戏走起
-
此次笔者将为玩家们推荐一款游戏主机——攀升战境S5。该主机是攀升电脑今年力推的游戏装备,主机采用一线品牌配件,特别是在显卡选用上严苛把关,精选GeForceRTX30系列显卡,玩家们大可以放心选购...
- 慎买-神牛闪光灯兼容性问题:神牛V350&松下S5M2
-
神牛V350和松下S5M2的兼容性问题。大家好,我是向往闪光灯人像的Fish。国庆期间,我购买了神牛V350闪光灯和神牛X2T引闪器,但这成为了我的噩梦。我原以为客服和松友们说这款闪光灯在松下S5M2...
- Acer蜂鸟持续办公一整天(acer 蜂鸟s5)
-
移动办公在工作节奏日益加快的今天越来越普遍,目前大部分工作无法在手持设备上完成,笔记本依然是移动办公最明智的选择。为了实现移动办公,很多笔记本越做越轻薄,性能也越来越强,而续航却一直没有很大提升。笔者...
- 职业车手明年会骑什么?2021赛季各大世巡赛车队使用器材一览
-
新年的钟声即将敲响,意味着充满魔幻色彩的2020年即将过去。受新冠肺炎的影响,2020年的赛季非常不同寻常。因这一原因不得不延迟举行的各种比赛导致许多车队的赞助商无法得到足够曝光,这也间接导致了许多车...
- 三星部分手机系统升级路线图流出(三星系统在哪升级)
-
三星包括Note3和S5在内的手机在升级到4.4.2系统之后一直没有什么系统升级的消息,而最近流出的一张三星的系统升级路线图中出现了一共13台手机升级KTU84P(也就是Android4.4.4)...
- 索尼Xperia Z3配置大曝光:升级并不大
-
IT之家(www.ithome.com):索尼XperiaZ3配置大曝光:升级并不大索尼明天就会在IFA2014大会上发布其下代旗舰XperiaZ3智能手机,目前网上曝光了其原型机,并且机身背后...
- 不进反退 三星Exynos 5433只能运行32位模式?
-
三星GalaxyNote4将带有两个版本,除了国行使用的骁龙805以外,还有三星自家的Exynos5433版本。而这颗SoC的详细信息三星并没有公布,据外媒Anandtech称,他们从源码中确认...
- 尼康Z6III测评:对比EOS R6 II、A7M4、S5IIX
-
摄影器材测评网站DPReview刚刚发布了尼康Z6III的完整图文测评,该机获得金奖评级,得分达到91%。以下是该文章的摘录——尼康Z6III核心规格:2400万像素“部分堆栈式”传感器RAW连拍:机...
- 赛默飞Ion S5首批数据公布,玩爆前任PGMTM系列
-
北美时间9月1日,赛默飞发布了两款最新的NGS系统IonS5和IonS5XL,旨在提供更加简捷的靶向测序流程。10月29日IonS5测序仪的首批实验数据产生于阜外医院。阜外医院研究人员选用了主...
- Excel技巧:快速制作批量文件夹,省时省力,加强工作效率
-
大家好,如果公司领导要求按人员姓名制作文件夹,以一人一档的形式呈现人员档案,办公人员一个一个制作费时费力,而且效力低下,今天为大家介绍快捷制作批量文件夹的方法下面我们用图片来进行演示操作打开表格,选...
- 国行、港版、美版Apple watch各版本售价一览
-
今天凌晨,苹果牌手表正式发布,苹果开始正式进入可穿戴设备领域,除了功能和外观,我相信大家更关心的是价格问题了,小编就将国行、港版、美版的Applewatch售价做一总结,以供参考。国行:美版:港版:...
- 松下全画幅微单S5和S1到底哪里不一样?
-
Hello,我是ET,欢迎大家来到我的“相机笔记”。————9月2日晚,松下正式发布了第4款全画幅微单LUMIXS5。这一篇,我们主要来说松下LUMIXS5和LUMIXS1到底有哪些区别...
- 融会贯通之典范 神舟S7-2021S5评测
-
便携、性能、续航,这简简单单的六个字道出了这么些年来笔记本电脑的设计方向,可是由于底层技术、模具设计等等原因,这三点并不能很好的融合在一起。虽说闻道有先后,术业有专攻,但能够有一台融会贯通的产品,不是...
- 三国志战略版:S5赛季装X指南,开荒不是一成不变,需要因地制宜
-
大家好我是零氪玩家花席,S5赛季已经开始,因为S5赛季的野地阵容和S4赛季没有区别,所以S5赛季开荒相对不难。你在S4有经验,并且多了很多武将和战法,还能用150赛季功勋兑换7500战法点。S5赛季新...
- 聊聊松下S5M2和S5M2X的区别(松下s5k和s5c有什么区别)
-
先简单说下哪里不同:12bitRAWHDMI外录支持直接将视频录制到USB-SSD上多了All-Intra和ProRes编码支持有线/无线IP推流,USB网络连接黑化的机身不过要特别强调一下,S5...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 基础教程 (29)
- HTML 简介 (30)
- HTML 响应式设计 (31)
- HTML URL 编码 (32)
- HTML Web 服务器 (31)
- HTML 表单属性 (32)
- HTML 音频 (31)
- HTML5 支持 (33)
- HTML API (36)
- HTML 总结 (32)
- HTML 全局属性 (32)
- HTML 事件 (31)
- HTML 画布 (32)
- HTTP 方法 (30)
- 键盘快捷键 (30)
- CSS 语法 (35)
- CSS 选择器 (30)
- CSS 轮廓 (30)
- CSS 轮廓宽度 (31)
- CSS 谷歌字体 (33)
- CSS 链接 (31)
- CSS 中级教程 (30)
- CSS 定位 (31)
- CSS 图片库 (32)
- CSS 图像精灵 (31)