前端设计规范总结

  • Post author:
  • Post category:其他


作者 内容 时间
jj 前端设计规范总结 2023年1月31日




第一章 架构设计原则



1.1 技术选型


  • 【强制】

    在做前端技术选型前需先确定客户类型、项目终端、分辨率、浏览器、响应要求。
  • 【推荐】 移动端采用

    H5+happ



    小程序

    采用

    uni-app

    ; 桌面端采用

    electron+vue



1.2 前端资源


  • 【强制】


    生产环境

    所有静态资源应该

    压缩

    ,减少请求资源大小,css、 js应该

    合并

    , 减少请求资源次数, 并为文件增加

    md5标识

    ,避免出现缓存失效不更新的情况。
  • 【推荐】 图标尽量使用字体图标、把所有相对较小的资源图片,合并成雪碧图,svg转字体图标工具可以使用

    icomoon

  • 【推荐】 单个页面大小不应超过

    2M

  • 【推荐】 加载的外部CSS和JS文件的总数不应超过

    10个

  • 【推荐】 所有请求的资源(CSS、JS、图片、Flash等)数量不应超过

    50个



1.3 前端存储

  • 【推荐】 html 开启ETag,其他静态资源,开启

    Expires



    Cache-control

  • 【推荐】 所有静态资源和动态资源开启

    gzip

  • 【推荐】 避免cookie中存储过多信息。
  • 【推荐】 页面数据可使用

    localStorage



    sessionStorage

    缓存,推荐优先使用

    sessionStorage


  • 【强制】

    禁止在

    localStorage



    sessionStorage

    中存储敏感信息。



1.4 前后端协作


  • 【强制】

    接口设计遵循 RESTful规范。

  • 【强制】

    使用

    YAPI

    进行接口管理和前后端联调。

  • 【强制】

    后端设计评审应该包含前后端接口设计,接口定义由前后端共同评审决定,由技术负责人决策。

  • 【强制】

    在前后端均可实现的情况下,业务处理优先放后端。接口定义优先考虑接口的业务内聚,其次是接口的灵活性和适应性。业务内聚能减少理解成本和维护成本,灵活性和适应性可让接口更便于扩展和接口复用。



1.5 其它

  • 【强制】

    XSS

    输入过滤,对输入数据进行有效验证,对敏感字符进行转义, 如: |<>, ” & # javascript expression 。

    常见的可能造成问题的字符的HTML编码
显示 实体名字 实体编号
< < <
> > >
& & &
  • 【推荐】 前后端数据交互时,请求体采用

    application/json

    格式, 文件上传采用

    multipart/form-data


  • 【强制】

    IDE需开启eslint、stylelint代码检测。

  • 【强制】

    服务器端开启sonar检测。
  • 【推荐】 页面首屏渲染在

    2秒

    以内,页面全部渲染完在

    5秒

    以内,报表统计数据在

    5秒

    以内。

  • 【强制】

    与用户交互相关的系统异常,应在前台页面给出友好提示,不应直接输出堆栈信息。
  • 【推荐】 页面应防止

    按钮



    链接

    重复点击。




第二章 前端通用规范



2.1 基本原则


  • 【强制】

    源代码文件统一使用

    无 BOM 的 UTF-8 编码

    ,避免在不同运行环境或者IDE下出现乱码情况。

  • 【强制】

    遵循内容(HTML)、显示(CSS)、行为(JavaScript)分离的代码组织模式,尽量确保文档和模板只包含

    HTML

    结构,样式都放到

    样式表

    里,行为都放到

    脚本

    里。

  • 【强制】

    html, css, js 必须格式化,缩进全部采用

    4个空格

    ,保持干净整洁。
  • 【推荐】 每行文本的长度不该超过

    80

    个字符。
  • 【推荐】为了方便维护,在每个源码文件的头部要有必要的注释时间戳和签名,应该包含且不限于以下几种:

    • 版本号;
    • 作者;
    • 生成日期;
    • 模块功能描述(如功能、内部各部分之间的关系、该文件与其它文件关系等);
    • 本文件历史修改记录;
  • 【参考】 注释要逻辑清晰易懂,边写代码边注释。
/* 以下是四种注释场景 */

/* 1.大型模块注释,如首页,详情页等等 */
/*********************************************\

				大型模块

\*********************************************/

/* 2.大型模块下的子模块注释,如首页下的主体,头部,侧栏等 */
/**
 * 大型模块=>子模块
\*********************************************/

/* 3.多行注释 */
/**
 * 组件: cl-ul-01
 * 描述: 列表组件1
 * 应用: 首页、详情
 */

/* 4.单行注释, less 注释使用 // */
/* 单行注释 */
// 单行注释
  • 【推荐】 IDE推荐使用

    webstorm



    vscode


  • 【强制】

    TAB键用四个空格代替。

    • 【说明】在不同系统的编辑工具对

      TAB

      解析不一样,windows下的

      tab

      键是占

      四个

      空格的位置,而在

      linux

      下会变成占

      八个

      空格的位置。



2.2 常用命名约定(HTML, CSS, JS, VUE, PNG, GIF, JPG, ICO)


  • 【强制】


    文件

    命名总是以

    字母

    开头。

  • 【强制】


    文件



    目录

    命名一律

    小写

    ,必须是英文单词或者汉语拼音,以英语单词优先,多个单词以连字符 (

    -

    ) 连接。 只能出现小写英文字母、数字和连字符。文件名中带有清晰含义的元数据,如

    .min.js



    .min.css



    .3fa89aaasdb.main.min.css

    ,使用

    点分隔符

    进行区分。
  • 【推荐】 业务单词推荐使用拼音简拼,非业务单词推荐使用英文单词命名如:cl-anyou-label (案由label)。
  • 【推荐】 name采取小驼峰命名法name = “helloWorld” 。
  • 【参考】 id 和 class 的命名基本原则: 内容优先,表现为辅。首先根据内容来命名,如cl-header、cl-footer、cl-main-nav 如根据内容无法找到合适的命名,可以再结合表现进行命名,如:cl-col-main、cl-col-sub、cl-col-extra、cl-box-01等。

  • 【强制】

    CSS的class 的名称一律小写,


    必须增加前缀cl-


    ,多个单词以连字符

    -

    连接,如 class: 连接符命名法 class=“cl-hello-world” , 状态名不需要添加前缀cl-

    , 且不能单独使用(

    disabled` 除外),必须和其他非状态的类名一起使用。示例:
<ul class="cl-main-nav">
    <li class="cl-item active">选中</li>
    <li class="cl-item">未选中<li>
</ul>
<style>
    .cl-main-nav .cl-item {
        color: #333;
    }
    .cl-main-nav .cl-item.active {  
        color: red;
  }
</style>
/* 可以嵌套用 */
.cl-nav .active {
    ...
}
/* 可以堆叠用 */
.cl-btn.active {
    ...
}
/* 绝不要单独用!!! */
.active {
    color: red;
}
  • 【参考】 常用状态名如下:

    状态名 含义
    hover 划过
    active 激活
    visited 访问过后
    pressed 按下后
    selected 单选选中
    checked 复选框选中
    disabled 禁用的
    focus 获得焦点
    blur 失去焦点
    success 成功
    fail 失败
    error 出错
    warning 警告
    default 默认
    current 当前的




第三章 HTML规范



3.1 基础语法


  • 【强制】

    嵌套元素应当缩进四个空格。

  • 【强制】

    属性的定义必须加双引号。

  • 【强制】

    禁止在自闭合(self-closing)元素的尾部添加斜线 。
  • 【推荐】 习惯性书写注释,方便日后维护。
  • 【推荐】 不要省略可选的结束标签(closing tag)(例如,< /li> 或 </body>)。

  • 【强制】

    对于作为js钩子的 id 和 class 命名规则为以

    js

    开头,后面加上原应有的命名,在使用class的时候需要放在最前面。如:class=“js-cl-tab-01 cl-tab-01”。(注意:js钩子,不允许在css中定义任何的样式效果)。

  • 【强制】


    结构层



    行为层



    表现层

    分离这是基本的原则,页面中不允许出现css内容(包括行内样式和style),如有必要,特殊情况特殊处理。
  • 【推荐】 为了最大程度的发挥浏览器自动排版的功能,在一段完整的文字中尽量不要使用

    <br>

    来人工干预分段。
  • 【推荐】

    <img>

    标签中不要带上

    width



    height

    两个属性,避免人为干预图片显示的尺寸,尽可能的发挥浏览器自身的功能。
  • 【推荐】 不同语种的文字之间应该有一个半角空格,但避头的符号之前和避尾的符号之后除外,汉字之间的标点要用全角标点,英文字母和数字周围的括号应该使用半角括号。

  • 【强制】

    禁止使用font标签定义字体大小,如:

    <font size="*">

  • 【参考】 使用

    W3C HTML Validator

    来验证你的HTML代码有效性。
  • 【参考】 在每个模块开始和结束的地方添加注释。
<!-- 新闻列表模块开始 -->
<div class="cl-module-news g-mod">
    ...
</div>
<!-- 新闻列表模块结束 -->

<!-- 排行榜模块  start -->
<div class="cl-module-topic g-mod">
    ...
</div>
<!-- 排行榜模块 end -->



3.2 HTML文档基础要求


  • 【强制】

    为每个 HTML 页面的第一行添加标准模式

    <!DOCTYPE html>

    (standard mode)的声明,这样能够确保在每个浏览器中拥有一致的展现。
<!DOCTYPE html>
<html lang="zh-CN">
    <!-- ... -->
</html>

  • 【强制】

    为 html 根元素指定 lang 属性。
<html lang="zh-CN">
    <!-- ... -->
</html>

  • 【强制】

    明确声明字符编码为UTF-8。
<head>
    <meta charset="UTF-8">
</head>

  • 【强制】

    明确声明

    X-UA-Compatible

    ,推荐设置为

    edge mode

<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">

  • 【强制】

    将 CSS 样式放在页面的上方 (head内)。

  • 【推荐】 将脚本移动到底部(body结束标签前),包括内联的,非必要,不要放在head标签里面

  • 【推荐】 引入CSS和JS时不需要指明 type,因为 text/css 和 text/javascript 分别是他们的默认值。

  • 【参考】 HTML基础模板示例

<!DOCTYPE HTML>
<html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
        <title>my page</title>
      	<link rel = "Shortcut Icon" href="favicon.ico">
        <link rel="stylesheet" href="css/reset.css">
    </head>
    <body>
        <div class="cl-page">
            <header class="cl-header">
                页头
            </header>
            <section class="cl-content">
                主体
            </section>
            <footer class="cl-footer">
                页尾
            </footer>
        </div >
        <script src="js/jquery.min.js"></script>
    </body>
</html>



3.3 HTML元素

  • 【推荐】 HTML属性应当按照以下给出的顺序依次排列,确保代码的易读性。

    • class
    • id、name
    • data-*
    • src、for、type、href、value、max-length、max、min、pattern
    • title、alt、placeholder
    • aria-*、role
    • required、readonly、disabled
<a class="..." id="..." data-modal="toggle" href="#">
    Example link
</a>
<input class="cl-form-control" type="text">
<img src="..." alt="...">

  • 【强制】

    不用给元素的布尔型属性赋值true或false,有此属性则为true,无则为false。
<input type="text" disabled>
<input type="checkbox" value="1" checked>
<select>
    <option value="1" selected >1</option>
</select>
  • 【推荐】 使用简洁的html,减少无用的父元素嵌套。
<!-- 反例 -->
<span class="cl-avatar">
    <img src="...">
</span>
<!-- 正例 -->
<img class="cl-avatar" src="...">
  • 【推荐】 优先使用

    语义化元素

    ,减少无语义标签(div、span)的使用。语义化标签如

    h1

    代表最高级别的标题,

    p

    代表文字段落,

    a

    代表链接锚点。

    • 结构性元素
    h1~h6 文章标题、内容区块标题,根据重要性由大到小区分,h1一个页面只出现一次;
    p 文本段落,只能包含内联元素,不能包含块级元素;
    table 数据网格,规则的分栏布局,尽可能显性的定宽和定高;
    div 本身无特殊含义,可用于布局。几乎可以包含任何元素;
    br 表示换行符;
    hr 表示水平分割线;
    blockquote 表示引用,可以包含多个段落。请勿纯粹为了缩进而使用 blockquote,大部分浏览器默认将 blockquote 渲染为带有左右缩进;
    pre 表示一段格式化好的文本;
    
    • 头部元素
    title 每个页面必须有且仅有一个 title 元素;
    base 可用场景:首页、频道等大部分链接都为新窗口打开的页面;
    Link 用于引入 css 资源;
    style 内嵌css资源;
    
    • 文本元素
    strong/em 强调文本;em表示句意强调,加与不加会引起语义变化,可用于表示不同的心情或语调; 
    strong 表示重要性强调,可用于局部或全局,strong强调的是重要性,不会改变句意;
    abbr 表示缩写;
    sub,sup 主要用于数学和化学公式,sup还可用于脚注;
    span 本身无特殊含义;
    ins,del 分别表示从文档中增加(插入)和删除;
    a 表示链接;
    
    • 媒体元素
    img 图像,必须加上alt属性,当图像无法显示时,可表示图像信息,背景和按钮使用css处理,不使用img元素;
    Object 可以用来插入Flash;
    video 视频,可以播放视频文件
    audio 音频,可以播放音频文件
    
    • 列表元素
    dl 定义列表,可包括标题和内容简介的列表;dd是对dt的解释; dt和dd的对应关系比较随意:一个dt对应多个dd、多个dt对应一个dd、多个dt对应多个dd,都合法; 可用于名词/单词解释、日程列表、站点目录;
    ul 无序列表;
    ol 有序列表,可用于排行榜等;
    li 表示列表项,必须是ul/ol的子元素;
    
    • 表单元素
    fieldset 元素包裹相同类别的字段;
    legend 元素表示字段类别名称;
    label 表示字段文本,添加必要的for属性,以在点击字段文本时,文本框能获得焦点;
    文本框不使用size属性定义宽度,而使用css的width属性
    
    • html5元素
    section 表示文档中的节、区段,可以和h1-h6一起来显示文档结构
    article 表示一块比较独立的内容或者主题内容,块级元素,比如blog的内容,报纸的文章
    aside 表示article以外的内容,而且应该和article有一定的关系,块级元素
    hgroup 表示一个文档、区段(section)的标题组合
    header 表示页眉,页头
    footer 表示页脚
    nav 表示导航内容
    figure 表示以相对独立的或外引的元素,如img video
    figcaption 表示 figure内容的标题
    
    
    • 示例
    <!-- hgroup 示例 -->
    <hgroup>
        <h1>文档主标题</h1>
        <h2>文档副标题</h2>
    </hgroup>
    
    <!-- figure 示例 -->
    <figure>
        <video src="ogg"></video>
        <figcaption>Example</figcaption>
    </figure>
    
    <figure>
        <img src="img" alt="Example image">
        <figcaption>Example image</figcaption>
    </figure>
    
    <!-- 反例 -->
    <div class="cl-top-navigation">
        <div class="cl-nav-item"><a href="#home">Home</a></div>
        <div class="cl-nav-item"><a href="#news">News</a></div>
        <div class="cl-nav-item"><a href="#about">About</a></div>
    </div>
    
    <!-- 正例 -->
    <nav class="cl-top-navigation">
        <ul>
            <li class="cl-nav-item"><a href="#home">Home</a></li>
            <li class="cl-nav-item"><a href="#news">News</a></li>
            <li class="cl-nav-item"><a href="#about">About</a></li>
        </ul>
    </nav>
    

  • 【强制】

    标签合理嵌套

  a、内联元素不能嵌套块级元素
  b、<li> 用于 <ul><ol> 下
  c、<dd><dt> 用于 <dl> 下
  d、<thead><tbody><tfoot><tr><td> 用于 <table> 下
  e、inline-Level 元素,仅可以包含文本或其它 inline-Level 元素;但是<a>里不可以嵌套交互式元素<a><button><select>等
  f、<p>、h1~h6里不可以嵌套块级元素<div><h1>~<h6><p><ul>/<ol>/<li><dl>/<dt>/<dd><form>



3.4 文档模板

  • 【参考】 文档模板如下
<!DOCTYPE HTML>
<html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
        <title>my page</title>
      	<link rel = "Shortcut Icon" href="favicon.ico">
        <link rel="stylesheet" href="css/reset.css">
    </head>
    <body>
        <div class="cl-page">
            <header class="cl-header">
                页头
            </header>
            <section class="cl-content">
                主体
            </section>
            <footer class="cl-footer">
                页尾
            </footer>
        </div >
        <script src="js/jquery.min.js"></script>
    </body>
</html>




第四章 CSS规范



4.1 基础语法


  • 【强制】

    为选择器分组时,将单独的选择器单独放在一行。

  • 【强制】

    在每个声明块的

    左花括号

    前添加一个空格,

    左花括号

    后进行换行。

  • 【强制】

    每条声明语句的

    :

    后应该插入一个空格。

  • 【强制】

    所有声明

    语句

    都应当以 “;”

    分号结尾

  • 【推荐】 值为0时须省略指定单位,例如,用 margin: 0; 代替 margin: 0px; 对于非0数值,必须明确定义单位。

  • 【强制】

    为了获得更准确的错误报告,声明块的

    右花括号

    应当单独成行,每条声明都应该独占一行,禁止将样式写为单行,这个应该是压缩工具做的事。

  • 【强制】

    对于以逗号分隔的属性值,每个逗号后面都应该插入一个空格(例如,box-shadow)。

  • 【强制】

    禁止使用行内(inline)样式, 除非是动态样式。
  • 【推荐】 优先使用类选择器。

  • 【强制】

    url() 函数中的路径增加双引号。

  • 【强制】


    >



    +



    ~

    选择器的两边各保留一个空格。

  • 【强制】

    属性选择器中的值必须用

    双引号


  • 【强制】

    十六进制值应该全部小写,并采用简写形式,例如,

    #fff


  • 【强制】

    禁止使用 Expression (css 表达式)。

  • 【强制】

    对于属性值或颜色参数,不省略小于 1 的小数前面的 0 (例如,不要把0.5 成.5;-.5px)。

  • 【强制】

    不要在多个页面通过<style lang=“less” src>重复引用相同的样式文件或者公用文件,用@import 要加 (reference) ,避免打包后生成多份重复代码
@import (reference) "reference1.css";
@import (reference) "reference2.css";
  • 【推荐】 不使用

    !important

    声明。
  • 【推荐】 小图片sprite 合并。
  • 【推荐】 rgb()、rgba()、hsl()、hsla() 或 rect() 值的内部的逗号后面应该插入空格。
/* 反例 */
.cl-selector, .cl-selector-secondary, .cl-selector[type=text]{
	padding:15px;
	margin:0px 0px 15px;
	background-color:rgba(0,0,0,.5);
	box-shadow:0px 1px 2px #CCC,inset 0 1px 0 #FFFFFF}

/* 正例 */
.cl-selector,
.cl-selector-secondary,
.cl-selector[type="text"] {
	margin-bottom: 15px;
	padding: 15px;
	background-color: rgba(0, 0, 0, 0.5);
	box-shadow: 0 1px 2px #ccc, inset 0 1px 0 #fff;
}



4.2 属性声明


  • 【强制】

    相关的属性声明应该归为一组,并按照下面的顺序排列:

    • Show or hide (显示属性)。
    • Position (位置属性 )。
    • Box model (盒子模型)。
    • Typographic (文本属性)。
    • Visual (视觉)。
    • other (其他)。
    • 显示属性决定元素是否可被视觉捕获,因此排在第一位, 常用属性如下:
    content、display、visibility 等。
    
    • 位置属性决定当前显示元素的位置,可以从正常的文档流中移除元素,并且还能覆盖盒模型(box model)相关的样式,因此排在第二位。常用属性如下:
    position、top、right、bottom、left、z-index、float、clear、flex
    
    • 盒子大小排在第三位,因为它决定了元素的尺寸和位置。常用属性如下:
    margin、padding、width、height、max-width、max-height、min-width、min-height、overflow
    
    • 文本属性决定容器内部的文本显示状态,因此摆放在盒模型之后,常用属性如下:
    color、font、line-height、text-align、text-indent、text-overflow、vertical-align、white-space、word-wrap、word-break
    
    • 视觉样式决定容器的外观,起到锦上添花的作用,因此排在第五位,常用属性如下:
    list-style、border-radius、border、outline、box-shadow、background、clip-path
    
    • 其他属性只是影响组件的内部(inside),因此排在后面。常用属性如下:
    opacity、filter、perspective、transform、transition、animation、cursor、user-select
    
    • 常用属性范例如下,其他遵循前端通用

      stylelint

      规范配置。
    .cl-declaration-order {
    	/* 显示、隐藏 */
    	content: "";
    	display: none;
    	visibility: hidden;
    
    	/* 定位 */
    	position: absolute;
    	top: 0;
    	right: 0;
    	bottom: 0;
    	left: 0;
    	z-index: 9;
    	float: left;
    	clear: both;
    	
    	/* 盒子模型 */
    	margin:	10px;
    	padding: 10px;
    	width: 100px;
    	height: 100px;
    	max-width: 200px;
    	max-height: 200px;
    	min-width: 50px;
    	min-height: 50px;
    	
    	/* 文本 */
    	color: #333;
    	font: normal 13px "Helvetica Neue", sans-serif;
    	line-height: 1.5;
    	text-align: center;
    	text-indent: -9999em;
    	text-overflow: ellipsis;
    	vertical-align: top;
    	white-space: nowrap;
    
    	/* 视觉 */
    	border-radius: 3px;
    	border: 1px solid #e5e5e5;
    	background-color: #f5f5f5;
    
    	/* 其它 */
    	opacity: 1;
    	transform: translate(-50%, -50%);
    	transition: opacity 0.5s 0s linear;
    	animation: fadeIn 0.5s 0s linear;
    	cursor: pointer;
    	user-select: none;
    }
    

  • 【强制】

    禁止使用

    @import

    。与

    <link>

    标签相比,

    @import

    指令要慢很多,不光增加了额外的请求次数,还会导致不可预料的问题。替代办法有以下几种:

    • 使用多个

      <link>

      元素。
    • 通过

      Sass



      Less

      类似的 CSS 预处理器将多个 CSS 文件编译为一个文件。
    • 通过

      Rails



      Jekyll

      或其他系统中提供过 CSS 文件合并功能。
  • 【推荐】

    媒体查询(MEDIA QUERY)

    尽可能放在相关规则的附近或者放在该文件的底部。不要将他们打包放在一个单一样式文件中。示例:

.cl-element { ... }
.cl-element-avatar { ... }
.cl-element-selected { ... }
@media (min-width: 480px) {
    .cl-element { ... }
    .cl-element-avatar { ... }
    .cl-element-selected { ... }
}
  • 【推荐】 当使用特定厂商的带有前缀的属性时,通过缩进的方式,让每个属性的值在垂直方向对齐,这样便于多行编辑。
/* 带前缀的属性 */
.cl-selector {
  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
          box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
  • 【推荐】 在需要显示地设置某些值的情况下,应当

    尽量避免使用简写形式的属性声明

    。常见的滥用简写属性声明的情况如下:
- margin
- padding
- font
- border-radius
- border
- background   
  • 【参考】 大部分情况下,我们不需要为简写形式的属性声明指定所有值。例如,HTML 的 heading 元素只需要设置上、下边距(margin)的值,因此,在必要的时候,只需覆盖这两个值就可以。过度使用简写形式的属性声明会导致代码混乱,并且会对属性值带来不必要的覆盖从而引起意外的副作用。
/* 反例 */
.cl-element {
    margin: 0 0 10px;
    border-radius: 3px 0 0 0;
    background: red;
    background: url("image.jpg");
}

/* 正例 */
.cl-element {
    margin-bottom: 10px;
    border-top-left-radius: 3px;
    background-color: red;
    background-image: url("image.jpg");
 }



4.3 命名规范


  • 【强制】



    cl

    为命名空间。

  • 【强制】

    class 名称中只能出现小写字符和分隔符(

    -

    )(不是下划线,也不是驼峰命名法)。分隔符应当用于相关 class 的命名(类似于命名空间)(例如,cl-btn 和 .cl-btn-danger)。
  • 【推荐】 命名使用全称,避免过度简写带来的理解成本。
  • 【推荐】 使用有意义的名称。使用有组织的或目的明确的名称,尽量使用抽象名称。

  • 【强制】

    使用 .js-* class 来标识行为(与样式相对),并且不要将这些 class 包含到 CSS 文件中【!important】

  • 【强制】

    命名基本原则:[前缀]-[类型|作用]-[名称]-[状态|位置]。

    • 如:

      .cl-ul-01



      cl-ul-01-top

    • 【推荐】 在为 Sass 和 Less 变量命名时也可以参考上面列出的各项规范。
  • 【推荐】 关注分离,将 HTML、CSS 解耦;模块化编码。
  • 【推荐】 语义化的模块名,通过模块名应该能一眼就看出模块的用途。
<dl class="cl-dl-01">
    <dt class="cl-dt-01">这是标题</dt>
    <dd class="cl-dd-01">这是内容</dd>
</dl>
  • 【推荐】 模块最外层使用

    {命名空间}-{模块名}

    的方式命名 Class。模块子元素以在此基础上进行命名。如果不继承父级的类名,很容易造成命名冲突(

    BEM

    命名规范)。
  • 【推荐】 优先使用

    语义化元素

    ,根据元素设计的目的来使用元素。段落用 < p> ;标题用< h1 > ~ < h6 > ;引用用< blockquote> , 而不是简单粗暴地使用< div> 、< span> 。语义化的目的,一方面是抽去

    css

    以后,页面还是一个结构良好、可读的页面。
  • 【推荐】 避免不必要的 CSS 选择符嵌套。class 已经模块化命名,从类名上已经可以清晰的分辨元素的从属,一般情况下也不会造成类名冲突,没有必要再进行选择器嵌套,保持 css 结构清晰,提高渲染效率。特殊情况可以嵌套(如提高权重、主题之间代码隔离,必须将样式限制在父元素内,也就是后代选择器),但应避免过多层级(应小于

    6

    级)。
/* 反例 */
.cl-dl-01 .cl-dl-01-dt {}
.cl-dl-01 .cl-dl-01-dd {}

/* 正例 */
.cl-dl-01 {
    border: 1px solid #333;
}
.cl-dl-01-dt  {
    margin: 0;
    padding: 5px 10px;
    border-bottom: 1px solid #333;
    background-color: #ccc;
}
.cl-dl-01-dd  {
    margin: 10px;
}
  • 【推荐】 与 JS 交互时,在模块 HTML 结构的最外一层添加状态,而非给模块每个子元素单独添加元素。给最外层添加状态类以后,整个模块的样式都能控制,减少操作,提高性能,示例:
<!-- 反例 -->
<dl class="cl-dl-01">
    <dt class="cl-dl-01-dt active"></dt>
    <dd class="cl-dl-01-dt active"></dd>
</dl>

<!-- 正例 -->
<dl class="cl-dl-01 active">
    <dt class="cl-dl-01-dt"></dt>
    <dd class="cl-dl-01-dd"></dd>
</dl>
  • 【推荐】 常用的CSS命名规则 。

    • 页面结构
    页面结构 命名
    页面 page
    容器 container
    页头 header
    内容 content
    页面主体 main
    页尾 footer
    导航 nav
    侧栏 aside
    栏目 column
    页面外围控制整体布局宽度 wrap
    • 导航
    导航结构 命名
    导航 nav
    主导航 mainnav
    子导航 subnav
    顶导航 topnav
    边导航 sidenav
    左导航 leftsidenav
    右导航 rightsidenav
    菜单 menu
    子菜单 submenu
    标题 title
    摘要 summary
    • 功能
    功能 命名
    登陆 login
    文章 article
    列表 list
    指南 guide
    标志 logo
    广告 banner
    登录条 loginbar
    注册 register
    搜索 search
    功能区 shop
    标题 title
    加入 joinus
    状态 status
    按钮 btn
    滚动 scroll
    标签页 tab
    提示信息 msg
    当前的 current
    小技巧 tips
    图标 icon
    注释 note
    服务 service
    热点 hot
    新闻 news
    下载 download
    投票 vote
    合作伙伴 partner
    友情链接 link
    版权 copyright



4.4 其它

  • 【推荐】 避免使用通配规则。

    • 除了传统意义的

      通配选择符

      之外, 还包括

      相邻兄弟选择符

      ,

      子选择符

      ,

      后代选择符



      属性选择符



      标签选择器

      。推荐

      class

      选择器。
  • 【推荐】 避免标签限制

    class

    选择器或

    id

    选择器。
  • 【推荐】 避免使用多层选择器 ;使用特殊的 class 选择器替换,减少css查找。
/* 反例 */
body div p span { ... }
.cl-page-container #stream .cl-stream-item .cl-tweet .cl-tweet-header .cl-username { ... }

/* 正例 */
.cl-text { ... }
.cl-stream-tweet-username { ... }
  • 【推荐】 避免使用后代选择符。

  • 【推荐】 避免使用标签

    子选择符

    • 如果有如: #header > li > a,这样基于子标签的

      子选择符

      ,那么应该使用一个class来关联每个元素如: .cl-header-anchor。尽量使用具体的类代替

      子选择符

    /* 反例 */
    #header > li > a {}
    
    /* 正例 */
    .cl-header-anchor {}
    
  • 【推荐】 以

    组件

    为单位组织代码段。

  • 【推荐】 使用一致的空白符将代码分隔成块,这样利于扫描较大的文档。

  • 【推荐】 如果使用了多个 CSS 文件,将其按照组件而非页面的形式分拆,因为页面会被重组,而组件只会被移动。

/* 组件标题 */
.cl-element { ... }

/**
 * 组件标题
 *
 * 有时您需要为整个组件包含可选的上下文。 如果它足够重要,就在这里做。
 ********************************************/
.cl-element { ... }

/* 上下文 子组件 或 修饰符 */
.cl-element-heading { ... }
  • 【推荐】 尽量减少对

    Hack

    的使用和依赖,如果非Hack不可,选择稳定且常用并易于理解的。
.cl-test {
    color: #000;       /* For all */
    color: #111\9;     /* For all IE */
    color: #222\0;     /* For IE8 and later, Opera without Webkit */
    color: #333\9\0;   /* For IE8 and later */
    color: #444\0/;    /* For IE8 and later */
    *color: #666;      /* For IE7 and earlier */
    _color: #777;      /* For IE6 and earlier */
}
  • 【推荐】 z-index的值不能超过

    100

    ; 页面中非弹出类的z-index不要超过10,需要按照内容定义1 2 3 4不允许直接使用如1000,9999;弹出类(popup/message/tips)的z-index, 需要按照内容使用 99以下,10以上的值(11,12, …),不允许直接使用1000,9999之类大值。

    z-index 使用者 类型

    <10
    page-content 非弹出类

    >10, <99
    page-popup 弹出类

    >10, <30
    message 消息

    >30, <50
    tips 提示

    >50, <100
    popup 弹出层
  • 【推荐】 慎重选择

    耗CPU

    的样式。

    • box-shadows (阴影)
    • border-radius (圆角)
    • transforms (transform相关属性值)
    • transparency (透明相关属性)
    • css filters(css滤镜,性能杀手)
  • 【推荐】 减少

    重排



    重绘

    ,提高页面渲染速度。

    • 常见的

      重排元素

      :
    	display
    	position
    	top
    	left
    	right
    	bottom
    	float
    	clear
    	margin
    	padding
    	width
    	height
    	min-height
    	overflow
    	overflow-y
    	font-size
    	font-family
    	line-height
    	text-align
    	font-weight
    	vertical-align
    	white-space
    	border-width
    
    • 常见的

      重绘元素

        visibility
        color
        text-decoration
        border-radius
        border-style
        outline-color
        box-shadow
        background
        background-image
        background-repeat
        background-size
    
  • 【推荐】 正确使用display的属性:

    • display 属性会影响页面的渲染,请合理使用。
    • display: inline后不应该再使用 width、height、margin、padding 以及 float;
    • display: inline-block 后不应该再使用 float;
    • display: block 后不应该再使用 vertical-align;
    • display: table-* 后不应该再使用 margin 或者 float;
  • 【推荐】 如果使用基于 javaScript 的动画,尽量使用

    requestAnimationFrame

    ,避免使用

    setTimeout

    ,

    setInterval

  • 【推荐】 避免通过类似 jQuery animate()-style 改变每帧的样式,使用

    CSS 声明动画

    会得到更好的浏览器优化。

  • 【推荐】 使用

    translate

    取代

    absolute 定位

    就会得到更好的

    fps

    ,动画会更顺滑。

    • 一般在 Chrome 中,3D或透视变换(perspective transform)CSS属性和对 opacity 进行 CSS 动画会创建新的图层,在硬件加速渲染通道的优化下,GPU 完成 3D 变形等操作后,将图层进行复合操作(Compesite Layers),从而避免触发浏览器大面积重绘和重排。注:3D 变形会消耗更多的

      内存和功耗

    /* 反例 */
    .cl-ball-2 {
    	left: 0;
    	transition: left 0.5s ease; 
    }
    .cl-ball-2.slidein {
    	left: 500px;
    }
    
    /* 正例 */
    .cl-ball-1 {
    	-webkit-transform: translate3d(0, 0, 0);
    	transition: -webkit-transform 0.5s ease;
    }
    .cl-ball-1.slidein {
    	-webkit-transform: translate3d(500px, 0, 0);
    }
    
  • 【推荐】 使用

    W3C CSS Validator

    来验证你的CSS代码有效性。




第五章 JavaScript规范



5.1 基础语法


  • 【强制】

    在自己单独的模块区域中使用

    严格模式

'use strict';
// 这里写代码
  • 【推荐】 避免使用全局变量,用模块化代替全局变量。

  • 【强制】

    语句的结尾总是使用分号。
// 这里写分号
var foo = bar;

var foo = function() { 
    return true;
};
// 这里没有分号的话,脚本解析器会报错!!!

function foo() {
    return true;
}
// 这里不写分号
  • 【推荐】 函数定义结束不允许添加分号。
//  正例
function funcName() {
}

// 反例 
function funcName() {
};

// 如果是函数表达式,分号是不允许省略的。
var funcName = function () {
};

  • 【强制】

    ES6语法中变量使用

    let



    const

    声明;非ES6语法变量使用

    var

    声明。

  • 【强制】

    不要在块内声明一个函数(严格模式会报语法错误)。如果确实需要在块中定义函数,可以使用函数表达式来声明函数。
/* 正例 */
if (x) {
    var foo = function() {};
}

/* 反例 */
if (x) {
    function foo() {}
}
  • 【推荐】 遇到异常可以将异常本身抛出,而不是抛出字符串。
  • 【推荐】 可以使用自定义错误信息,让代码更加清晰。
  • 【推荐】 优先使用原生的方法,而不是自行封装的非标准接口。

  • 【强制】

    不要封装基本类型,明确用于类型转换的场景除外。
/* 正例 */
var x = Boolean(0);
if (x) {
    // 这里不会弹出警告框
    alert('hi');  
}
typeof Boolean(0) === 'boolean'; // true
typeof new Boolean(0) === 'object'; // true

/* 反例 */
var x = new Boolean(false);
if (x) {
    // 弹出'hi'
    alert('hi');
}
  • 【推荐】 仅在

    构造函数



    方法



    闭包

    中使用

    this

    关键字,避免出现错误引用。

  • 【强制】

    禁止在

    Array

    上使用for-in循环,for-in仅用于循环对象。
/* 正例 */
var obj = {};
for (name in obj) {
    // 执行代码
}

/* 反例 */
var  arr = [];
for(index in arr) {
    // 执行代码
}
  • 【推荐】 需要键值对映射时直接使用

    Object

  • 【推荐】 用

    Array



    Object

    字面量代替

    Array



    Object

    构造函数。
/* 正例 */
var arr = [x1, x2, x3],
    obj = {
        a: 0,
        b: 1,
        c: 2
    };

/* 反例 */
var arr = new Array(x1, x2),
    obj = new Object();
  • 【参考】 类方法的定义示例:
/* 正例 */
var Foo = {
    // Foo对象
};

Foo.prototype.bar = function() {
    // bar方法
};

/* 反例 */
var Foo = function() {
    this.bar = function() {
        // bar方法
    };
};

  • 【强制】

    禁止修改内置对象的原型,如

    Object.prototype



    Array.prototype



    Function.prototype

    等。

  • 【参考】 谨慎使用

    闭包

    。闭包保留了一个指向它封闭作用域的指针,所以,在给

    DOM

    元素附加闭包时,很可能会产生循环引用, 进一步导致内存泄漏。比如下面的代码:


/* 反例 */
function foo(element, a, b) {
    element.onclick = function() { /* 使用a参数和b参数 */ };
}

  • 此处即使没有使用

    element

    ,闭包也保留了

    element



    a



    b

    的引用。由于

    element

    也保留了对闭包的引用,这就产生了循环引用,导致不能被

    GC

    回收。可将代码重构为:

/* 正例 */
function foo(element, a, b) {
	element.onclick = bar(a, b);
}

function bar(a, b) {
	return function() { /* 使用a参数和b参数 */ }
}


  • 【强制】

    禁止使用

    eval()

    ,应使用

    JSON.parse

    解析序列化字符串。

  • 【强制】

    禁止使用

    with() {}

    语句。

  • 【强制】

    禁止给

    setInterval

    /

    setTimeout

    传递字符串。
/* 正例 */
setTimeout(function () {
    alter(5);
    // 执行代码
}, 2000);

/* 反例 */
setTimeout("alter(5)", 2000);

  • 【强制】

    禁止使用多行字符串字面量。
  • 【推荐】 一般情况使用

    +

    操作符拼接字符串;如果存在大量的字符串拼接,推荐采用数组

    join()

    拼接字符串。ES6采用字符串模板。
/* 反例 */
var myString = '字符串1 \
                字符串2 \
                字符串3 \';

/* 正例 */
/* 短字符串使用+语法 */
var myString = '字符串1' + '字符串2' + '字符串3';

/* 大量字符串join语法 */ 
var myString = ['大量字符串1', '大量字符串2''大量字符串3'].join('');

/* ES6语法字符串模板 */
const str = '字符串2';
const myString = `字符串1 ${str} 字符串3`;

  • 【强制】

    在if判断中,使用

    ===

    作比较,避免掉入

    ==

    造成的陷阱



    • 条件判断时

      ,以下值表示

      false


      • null



        undefined



        空字符串

        、 数字

        0



        NaN
    • 而在

      ==

      时,则会有一些让人难以理解的陷阱,如:
    (function () {
        var undefined;
        undefined == null; // true
        1 == true; //true
        2 == true; // false
        0 == false; // true
        0 == ''; // true
        NaN == NaN; // false
        [] == false; // true
        [] == ![]; // true
    })();
    
  • 【推荐】 number to string的转换,建议使用

    1 + ""



    String(1)

    ,不使用

    new String(1)



    1.toString()

    的方式。

  • 【推荐】 string to number的转换,建议使用

    parseInt

    ,必须显式指定第二个参数的进制。下面的例子展示了不指定进制的风险:

// 反例
parseInt('08'); // 0

// 正例
parseInt('08', 10); // 8

  • 【强制】

    float to integer的转换,建议使用

    Math.floor

    /

    Math.round

    /

    Math.ceil

    方法,不使用

    parseInt



5.2 编码风格


  • 【强制】

    命名仅限于数字和字母字符,也可以用下划线,最好不用

    $



    \


  • 【强制】

    常量使用全大写字母,并用

    _下划线

    分隔单词,形如
// 特定含义的数字
var MAX_CONNT = 10;
// 常量字符串
var URL = "http://www.wuweigang.com";

  • 【强制】

    禁止使用

    关键字



    保留字


  • 【强制】

    变量名采用

    小驼峰格式

    命名,

    首字母小写

    ,不要用动词开头。
// 反例
// 字符串是一个名词,不能动词开头
var getBox="box";  

// 正例
function getName(name) {
    return name;
};
var myName = getName("jj");
  • 【推荐】 私有变量、私有属性、变量和方法以下划线

    _

    开头,形如

    _privateMethod


  • 【强制】

    函数命名采用

    小驼峰格式

    (构造函数使用

    大驼峰格式

    ),避免同变量混淆,函数名第一个应该是

    动词

  • 【推荐】 动词常见的约定:


    • can ,has,is

      返回一个布尔值。

    • get

      返回一个非布尔值。

    • set

      用来保存一个值。
    function doSomething() {
        // expression  普通函数
    }
    // 类名
    function DoSomething() {
        // expression  构造函数
    }
    var myFunction = new DoSomething();
    

  • 【强制】

    命名空间使用

    小驼峰

    命名法。

// 正例
equipments.heavyWeapons = {};

  • 【强制】

    由多个单词组成的缩写词,在命名中,根据当前命名法和出现的位置,所有字母的大小写与首字母的大小写保持一致。
// 正例
function XMLParser() {
}
function insertHTML(element, html) {
}
var httpRequest = new HTTPRequest();

  • 【强制】

    字符串应该始终使用单引号,只有 JSON 中的字符串属性值和HTML属性使用

    双引号

  • 【推荐】 避免使用null值,以下情况除外:

    • 用来初始化一个变量,这个变量可能被赋值为一个对象。
    • 用来和一个已经初始化的变量比较,这个变量可以是也可以不是一个对象。
    • 当函数的参数期望是一个对象时,被用做参数传入。
    • 当函数的返回值是一个对象时,被用作返回值传出。
  • 【推荐】 避免使用

    undefined

    值,除非要typeof操作符判断一个变量是否定义。
// 正例
if (typeof person === 'undefined') {
    // 执行代码
}

  • 【强制】

    要明确作用域。例如,不要依赖作用域链中的 window 对象。

  • 【强制】


    赋值运算符



    逻辑运算符

    前后必有使用一个空格,保持表达式的整洁。
// 正例
var  found = (values[i] === item);
if (found && (count > 8)) {
    // 执行代码
};
for (var i = 0; i < values.length; i++) {

};

  • 【强制】

    括号间距、当使用括号时,紧接左括号之后应该有空格,紧接右括号之后应该有空格,else前后都应该有个空格。
// 正例
if (found && (count > 10)) {
    // 执行代码
} else {

}

  • 【强制】


    if



    else

    等表达式后始终添加花括号。

  • 【强制】

    起始左花括号应当和表达式保持一行,结束的右括号应当独自占一行。

  • 【强制】

    每个属性的名值对,应当保持一个缩进,第一个属性应当在左括号后的另起一行。

  • 【强制】

    每个属性的名值对,应当适应不含引号的属性名,其后紧跟一个冒号(之前不含空格),而后是值。

  • 【强制】

    倘若属性值是一个函数类型,函数体应当在属性名之下另起一行,而且其前后均应保留一个空行。
  • 【推荐】 一组相关的属性前后可以插入空行,以提升代码的可读性。
var object = {
    key1: "value1",
    key2: function() {
        // 执行代码
    },
    key3: "value3"
};
  • 【推荐】 一个函数的参数不允许超过

    5

    个,超过5个请使用

    对象传参

    方式
  • 【推荐】 一个函数的单行长度超过

    80

    字符, 每个参数独占一行,并以 4个空格缩进,一行长度不超过

    80

    , 同一行上显示。 比如:
// 正例
// 一行不超过 80 , 同一行上
goog.foo = function(param1, param2, param3, param4) {
    // ...
};

// 一行超过 80 ,每个参数独占一行,并以 4个空格缩进
goog.foo.bar.doThingThatIsVeryDifficultToExplain = function(
    param1,
    param2,
    param3,
    param4) {
    // ...
};
  • 【推荐】 使用空行来划分一组逻辑上相关联的代码片段;文件末尾空一行。

  • 【强制】

    禁止在对象的最后一个属性值后面写

    逗号

    (某些浏览器会报错)。
/* 正例 */
var obj = {
    a: 1,
    b: 2,
    c: 3
};

/* 反例 */
var obj = {
    a: 1,
    b: 2,
    c: 3,
};



5.3 注释规范

  • 【推荐】 注释主要是进行说明,例如:

    • @todo:说明代码还未完成,应当包含下一步要做的事情。
    • @hack:为了兼容浏览器。
    • @fixme:尽快修复。
    • @bug:说明代码有问题,应当尽快修复。
    • @review:说明任何代码改动都需要评审。
    if (condition) {
        /**
        * 这里是注释
        * 这是注释2
        * param 这里是注释三
        */
     };
    
  • 【推荐】 文档注释应该包含以下信息,作者,版本,文件名,创建时间,更新时间,文件描述,更新描述。
/**
 * @version: 2016.01.01
 * @creatTime: 2016.10.10
 * @updateTime: 2016.10.12
 * @author: jj
 * @name: clDataTable
 * @decription 数据代码转换表
 * @updateDecription 2016.10.12  更新内容描述
 */
  • 【推荐】 函数或者类等都要添加头描述。
/**
 * 简述
 *
 * 功能详细描述
 *
 * @param {string} arg1 参数1
 * @param {number} arg2 参数2,默认为0
 * @returns {boolean} 看xxx是否成功
 */
 function fooFunction (arg1, arg2) {
 }

  • 【强制】

    类型定义都是以

    {


    开始, 以

    }

    结束。

    • 常用类型如:{string}, {number}, {boolean}, {Object}, {Function}, {RegExp}, {Array}, {Date}。

  • 【强制】

    对于基本类型 {string}, {number}, {boolean},首字母必须小写。


类型定义

语法示例

解释
单一类型集合 {Array.} string 类型的数组
多类型 {(number|boolean)} 可能是 number 类型, 也可能是 boolean 类型
允许为null {?number} 可能是 number, 也可能是 null
不允许为null {!Object} Object 类型, 但不是 null
Function类型 {function(number, boolean)} 函数, 形参类型
Function带返回值 {function(number, boolean):string} 函数, 形参, 返回值类型
Promise Promise.<resolveType, rejectType> Promise,成功返回的数据类型,失败返回的错误类型
参数可选 @param {string=} name 可选参数, =为类型后缀
可变参数 @param {…number} args 变长参数, …为类型前缀
任意类型 {*} 任意类型
可选任意类型 @param {*=} name 可选参数,类型不限
可变任意类型 @param {…*} args 变长参数,类型不限
  • 【参考】 注释标签参考

    • @addon 把一个函数标记为另一个函数的扩张,另一个函数的定义不在源文件中。 @argument 用大括号中的自变量类型描述一个自变量。
    • @author 函数/类作者的姓名。
    • @base 如果类是继承得来,定义提供的类名称。
    • @class 用来给一个类提供描述,不能用于构造器的文档中。
    • @constructor 描述一个类的构造器。
    • @deprecated 表示函数/类已被忽略。
    • @exception 描述函数/类产生的一个错误。
    • @exec @extends 表示派生出当前类的另一个类。
    • @fileoverview 表示文档块将用于描述当前文件。这个标签应该放在其它任何标签之前。
    • @final 指出函数/类。
    • @ignore 让jsdoc忽视随后的代码。
    • @link 类似于@link标签,用于连接许多其它页面。
    • @member 定义随后的函数为提供的类名称的一个成员。
    • @param 用大括号中的参数类型描述一个参数。
    • @private 表示函数/类为私有,不应包含在生成的文档中。
    • @requires 表示需要另一个函数/类。
    • @returns 描述一个函数的返回值。
    • @see 连接到另一个函数/类。
    • @throws 描述函数/类可能产生的错误。
    • @type 指定函数/成员的返回类型。
    • @version 函数/类的版本号。
    • @namespace 命名空间。



5.4 模块化

  • 【推荐】 非es6模块使用 AMD(requirejs) 作为模块定义。

    • AMD 作为由社区认可的模块定义形式,提供多种重载提供灵活的使用方式,并且绝大多数优秀的

      Library

      都支持 AMD,适合作为规范。



5.5 DOM

  • 【推荐】 操作 DOM 时,尽量减少页面

    reflow

    • 页面

      reflow

      是非常耗时的行为,非常容易导致性能瓶颈。下面一些场景会触发浏览器的

      reflow

      • DOM元素的

        添加



        修改



        删除

      • 应用

        新的样式

        或者修改任何影响元素

        布局的属性


      • Resize

        浏览器窗口、

        滚动

        页面。
      • 读取元素的某些属性(

        offsetLeft



        offsetTop



        offsetHeight



        offsetWidth



        scrollTop|Left|Width|Height



        clientTop|Left|Width|Height



        getComputedStyle()



        currentStyle(in IE)

        ) 。
  • 【推荐】 DOM 操作也是非常耗时的一种操作,减少 DOM 操作有助于提高性能。

    • 反例:在循环体中 createElement 并 append 到父元素中。
    • 正例:在循环体中拼接 HTML 字符串,循环结束后写父元素的

      innerHTML



5.6 其它


  • 【强制】

    Js操作的dom,无论是class还是id都必须以

    js

    开头,js开头的class 或者id禁止操作css,多词组合分隔,用分隔符

    -

<div class="js-test" id="js-test"></div>

【说明】以js开头的class或者id会告诉自己以及他人这块dom有js操作,请注意。


  • 【强制】

    url 编码用

    encodeURIComponent()

    ,解码

    decodeURIComponent()


  • 【强制】

    一个文件只允许出现一个vm对象,命名为

    VM

    , 一个模块有多个 VM请分文件,通过该模块的index.js,引入,务必保持文件的单一职责。以VUE举例:
var VM = new Vue({
    el: '#jsApp',
    data: {}
});

将文件保存为

module-xxx.js


  • 【强制】

    接口返回的文本数据必须是

    application/json

    格式,使用

    UTF-8

    编码。


  • 【强制】

    前端代码坚持

    模块化



    组件化


    • require


      amd

      模块划分,如:
    define('test', [], function() {
        // 内容
    })  
    // 保存为test.js
    

    • ES6

      模块
    export default () => {
        // 内容
    }
    

    • node 模块


      CommonJS
    module.exports = () => {
        // 内容
    }
    
    exports.xxx = {}
    
  • 【推荐】使用

    ArteryUI

    时,

    window.Artery

    对象中已经包含了常用的工具,不需要在项目里自己实现,如:

    deepCopy



    findComponentDownward



    qs



    on



    off

    等等




第六章 VUE规范



6.1 基础规范

  • 【推荐】 组件/实例的选项的顺序,统一按照以下结构摆放, 没有的属性可不写。
// 导出模块
export default {
	name: 'template',
	// components
	components: {},
	// directives
	directives: {},
	// filters
	filters: {},
	mixins: [],
	model:{},
	props: {
		property1:{
			type: String,
			default: '1'
		}
	},
	data() {
		return {
			user: '张三',
			age: 25
		};
	},
	computed: {
		// computed
		userInfo() {
			return `用户名:${this.user};年龄:${this.age}`;
		}
	},
	// watch
	watch: {},
	beforeCreate() {
		// beforeCreate
	},
	created() {
		// created
	},
	beforeMount() {
		// beforeMount
	},
	mounted() {
		// mounted
	},
	beforeUpdate() {
		// beforeUpdate
	},
	updated() {
		// updated
	},
	activated() {
		// activated
	},
	deactivated() {
		// deactivated
	},
	beforeDestroy() {
		// beforeDestroy
	},
	destroyed() {
		// destroyed
	},

	methods: {

		/**
		 * @function
		 * @description 一个实例方法,触发【getUserInfo】事件
		 * @return {undefined} 无返回值
		 */
		method1() {
			this.counter += 1;
			this.$emit('getUserInfo', this.userInfo);
		}
	},
	template: '<div></div>',
	// render
	render() {
		// render 方法
	}
};
  • 组件选项被划分为几大类,所以你也能知道从插件里添加的新 property 应该放到哪里。


    1. 副作用

      (触发组件外的影响)


      • el

    2. 全局感知

      (要求组件以外的知识)


      • name

      • parent

    3. 组件类型

      (更改组件的类型)


      • functional

    4. 模板修改器

      (改变模板的编译方式)


      • delimiters

      • comments

    5. 模板依赖

      (模板内使用的资源)


      • components

      • directives

      • filters

    6. 组合

      (向选项里合并 property)


      • extends

      • mixins

    7. 接口

      (组件的接口)


      • inheritAttrs

      • model

      • props

        /

        propsData

    8. 本地状态

      (本地的响应式 property)


      • data

      • computed

    9. 事件

      (通过响应式事件触发的回调)


      • watch

    10. 生命周期钩子

      (按照它们被调用的顺序)


      • beforeCreate

      • created

      • beforeMount

      • mounted

      • beforeUpdate

      • updated

      • activated

      • deactivated

      • beforeDestroy

      • destroyed

    11. 非响应式的 property

      (不依赖响应系统的实例 property)


      • methods

    12. 渲染

      (组件输出的声明式描述)


      • template

        /

        render

      • renderError
  • 【推荐】 元素 (包括组件) 的 attribute 应该有统一的顺序。


    1. 唯一的 attribute

      (需要唯一值的 attribute)


      • id

      • ref

    2. 定义

      (提供组件的选项)


      • is

    3. 列表渲染

      (创建多个变化的相同元素)


      • v-for

    4. key

      (与v-for配合使用的属性)


      • key

    5. 条件渲染

      (元素是否渲染/显示)


      • v-if

      • v-else-if

      • v-else

      • v-show

      • v-cloak

    6. 渲染方式

      (改变元素的渲染方式)


      • v-pre

      • v-once

    7. 双向绑定

      (把绑定和事件结合起来)


      • v-model

    8. 其它 attribute

      (所有普通的绑定或未绑定的 attribute)

    9. 事件

      (组件事件监听器)


      • v-on

    10. 内容

      (覆写元素的内容)


      • v-html

      • v-text


【强制】

组件名必须满足html的

自定义元素命名规范

;全部为小写,应该始终是多个单词的,并且使用分隔符

-

分割,不要使用

驼峰

或者其他形式 (根组件

App

以及 、 之类的 Vue 内置组件除外)。

  • 因为Html标签不区分大小写且元素名称都是单个单词的,这样做可以避免跟现有的以及未来的 HTML 元素相冲突。

/* 反例 */
Vue.component('todo', {
	// ...
})
export default {
	name: 'Todo',
	// ...
}

/* 正例 */
Vue.component('todo-item', {
	// ...
})
export default {
	name: 'todo-item',
	// ...
}
  • 【推荐】 命名约定,通用组件:

    cc

    +

    name

    、业务组件:

    ac

    +

    name



    name

    的可读性优于简洁性。

    • c 代表 common。
    • a 代表 app。
    • 第二个c代表 component。
    • name 代表组件名, 特定name用: 模块名+子模块名+后代模块名。
    • 项目组可以根据实际需要,在cc|ac前面再加自己的前缀, 如 dzjz-ac, dzjz-cc, dzjz代表电子卷宗项目。
/* 反例 */ 
// 学生设置组件
SdSettings
// 上传组件
ud
// 分页组件
fy
 
/* 好例子 */
//学生设置组件
ac-student-settings
// 业务上传组件
ac-upload  
// 分页组件
cc-pagination  

  • 【强制】

    Props 定义应该尽量详细,至少需要指定其类型。
/* 反例 */
// 这样做只有开发原型系统时可以接受
props: ['status']

/* 正例 */
props: {
	status: String
}

/* 正例 */
// 更好的做法!
props: {
	status: {
		type: String,
		required: true,
		validator: function (value) {
			return [
				'syncing',
				'synced',
				'version-conflict',
				'error'
			].indexOf(value) !== -1
		}
	}
}

  • 【强制】

    在声明 props 的时候,其命名应该始终使用 camelCase(驼峰),而在模板和 JSX 中应该始终使用 kebab-case(分隔符

    -

    分割)。

    • 我们单纯的遵循每个语言的约定。在 JavaScript 中更自然的是 camelCase。而在 HTML 中则是 kebab-case。
/* 反例 */ 
props: {
	'greeting-text': String
}

/* 正例 */ 
props: {
	greetingText: String
}

  • 【强制】

    当在组件中使用

    data

    property 的时候 (除了

    new Vue

    外的任何地方),它的值必须是

    返回一个对象的函数

    • 因为组件可能被用来创建多个实例 ,如果

      data

      仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象。通过提供

      data

      函数,每次创建一个新实例后,我们能够调用

      data

      函数,从而返回初始数据的一个全新副本数据对象。
/* 反例 */
Vue.component('some-comp', {
	data: {
		foo: 'bar'
	}
})

export default {
	data: {
		foo: 'bar'
	}
}

/* 正例 */
Vue.component('some-comp', {
	data: function () {
		return {
			foo: 'bar'
		}
	}
})

export default {
	data () {
		return {
			foo: 'bar'
		}
	}
}
// 在一个 Vue 的根实例上直接使用对象是可以的,
// 因为只存在一个这样的实例。
new Vue({
	data: {
		foo: 'bar'
	}
})
  • 【推荐】 计算属性尽量简单化 , 应该把

    复杂计算属性

    进行分割,拆分成多个更

    简单的 property

/* 反例 */ 
computed: {
	price: function () {
		var basePrice = this.manufactureCost / (1 - this.profitMargin);
		return (basePrice - basePrice * (this.discountPercent || 0));
	}
}

/* 正例 */ 
computed: {
	basePrice: function () {
		return this.manufactureCost / (1 - this.profitMargin);
	},
	discount: function () {
		return this.basePrice * (this.discountPercent || 0);
	},
	finalPrice: function () {
		return this.basePrice - this.discount;
	}
}

  • 【强制】

    在组件上必须用不重复的

    key

    配合

    v-for

    使用,详细解释可参考

    vue规范-key

<!-- 反例 -->
<ul>
	<li v-for="todo in todos">
		{{ todo.text }}
	</li>
</ul>

<!-- 正例 -->
<ul>
	<li
		v-for="todo in todos"
		:key="todo.id">
		{{ todo.text }}
	</li>
</ul>

  • 【强制】

    禁止把

    v-if



    v-for

    同时用在同一个元素上,必要情况下应该替换成computed属性。
<!-- 反例 -->
<ul>
	<li
		v-for="user in users"
		v-if="user.isActive"
		:key="user.id">
		{{ user.name }}
	</li>
</ul>

<ul>
	<li
		v-for="user in users"
		v-if="shouldShowUsers"
		:key="user.id" >
		{{ user.name }}
	</li>
</ul>

<!-- 正例 -->
<script>
computed: {
    activeUsers() {
        return this.users.filter((user) => {
            // 过滤出激活节点
            return user.isActive
        })
    }
}
</script>
<ul>
	<li
		v-for="user in activeUsers"
		:key="user.id">
		{{ user.name }}
	</li>
</ul>

<ul v-if="shouldShowUsers">
	<li
		v-for="user in users"
		:key="user.id">
		{{ user.name }}
	</li>
</ul>

  • 【强制】

    对于应用来说,顶级

    App 组件



    布局组件

    中的样式可以是

    全局

    的,但是其它所有组件都应该是有作用域的。

  • 【推荐】 使用

    CSS Modules

    ,那是一个基于 class 的类似

    BEM

    的策略,当然你也可以使用


    scoped

    attribute


  • 【强制】

    对于组件库,我们应该更倾向于选用基于

    class

    的策略而不是

    scoped attribute

    • 这让覆写内部样式更容易:使用了常人可理解的 class 名称且没有太高的选择器优先级,而且不太会导致冲突。
<!-- 反例 -->
<template>
	<button class="btn btn-close">X</button>
</template>

<style>
.btn-close {
	background-color: red;
}
</style>

<!-- 正例 -->
<template>
	<button class="button button-close">X</button>
</template>

<!-- 使用 `scoped` attribute -->
<style scoped>
.button-close {
	background-color: red;
}
</style>

<template>
	<button class="cl-button cl-button-close">X</button>
</template>

<!-- 使用 BEM 约定 -->
<style>
.cl-button-close {
	background-color: red;
}
</style>
  • 【推荐】 使用

    模块作用域

    保持不允许外部访问的函数的私有性。
/* 反例 */
var myGreatMixin = {
	// ...
	methods: {
		update: function () {
			// ...
		}
	}
}

/* 正例 */
var myGreatMixin = {
	// ...
	methods: {
		// 公用方法
		publicMethod() {
			// ...
			myPrivateFunction()
		}
	}
}
// 私有方法
function myPrivateFunction() {
	// ...
}

export default myGreatMixin
  • 【推荐】 每个组件单独拆分成文件。
// components.js
/* 反例 */ 
Vue.component('todo-list', {
	// ...
})

Vue.component('todo-item', {
	// ...
})

/* 正例 */
components/
|- todo-list.js
|- todo-item.js

components/
|- todo-list.vue
|- todo-item.vue

  • 【强制】

    元素

    attribute

    , 必须带双引号

    ""

    ,在 HTML 中不带空格的 attribute 值是可以没有引号的,但这会导致可读性变差。
  • 【推荐】 组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。

    • 复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的

      是什么

      ,而非

      如何

      计算那个值。而且计算属性和方法使得代码可以重用。
/* 反例 */ 
{{
  fullName.split(' ').map(function (word) {
	  return word[0].toUpperCase() + word.slice(1)
  }).join(' ')
}}

/* 正例 */ 
<!-- 在模板中 -->
{{ normalizedFullName }}

// js 复杂表达式已经移入一个计算属性
computed: {
	normalizedFullName: function () {
		return this.fullName.split(' ').map(function (word) {
			return word[0].toUpperCase() + word.slice(1)
		}).join(' ')
	}
}
  • 【推荐】 指令缩写 (用 : 表示 v-bind:、用 @ 表示 v-on: 和用 # 表示 v-slot:) 各个类型的指令使用尽量保持一致,应该要么都用缩写,要么都不用。
<!-- 反例 --> 
<input
	v-bind:value="newTodoText"
	:placeholder="newTodoInstructions">

<input
	v-on:input="onInput"
	@focus="onFocus">

<template v-slot:header>
	<h1>Here might be a page title</h1>
</template>

<template #footer>
	<p>Here's some contact info</p>
</template>

<!-- 正例 -->
<!-- 绑定数据 -->
<input
	:value="newTodoText"
	:placeholder="newTodoInstructions">

<!--  绑定事件-->
<input
	@input="onInput"
	@focus="onFocus">

<!--  插槽使用1 -->
<template v-slot:header>
	<h1>Here might be a page title</h1>
</template>

<template v-slot:footer>
	<p>Here's some contact info</p>
</template>

<!--  插槽使用2 -->
<template #header>
	<h1>Here might be a page title</h1>
</template>

<template #footer>
	<p>Here's some contact info</p>
</template>

  • 【强制】

    单文件组件应该总是让

    template



    script

    、和

    style

    标签的顺序保持一致。且

    style

    要放在最后,因为另外两个标签至少要有一个。
<!-- 反例 -->
<style>/* ... */</style>
<script>/* ... */</script>
<template>...</template>

<!-- 正例 -->
<!-- componentA.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>
  • 【推荐】 如果一组

    v-if

    +

    v-else

    的元素类型相同,最好使用 key (比如两个

    元素)。

    • 默认情况下,Vue 会尽可能高效的更新 DOM。这意味着其在相同类型的元素之间切换时,会修补已存在的元素,而不是将旧的元素移除然后在同一位置添加一个新元素。如果本不相同的元素被识别为相同,则会出现

      意料之外的结果

<!-- 反例 -->
<div v-if="error">
	错误:{{ error }}
</div>
<div v-else>
	{{ results }}
</div>

<!-- 正例 -->
<div
  v-if="error"
  key="search-status">
  错误:{{ error }}
</div>
<div
  v-else
  key="search-results">
  {{ results }}
</div>

  • 【强制】

    父子应该优先通过 prop 和事件进行父子组件之间的通信,而不是 this.$parent 或 使用其他通信方式。
  • 【推荐】 跨组件通信, 优先使用 eventBus,而不是 vuex。
/* 反例 */ 
Vue.component('todo-item', {
	props: {
		todo: {
			type: Object,
			required: true
		}
	},
	methods: {
		removeTodo () {
			var vm = this;
			vm.$parent.todos = vm.$parent.todos.filter(function (todo) {
				return todo.id !== vm.todo.id;
			})
		}
	},
	template: `
		<span>
			{{ todo.text }}
			<button @click="removeTodo">
				X
			</button>
		</span>
	`
})

/* 正例 */ 
Vue.component('todo-item', {
	props: {
		todo: {
			type: Object,
			required: true
		}
	},
	template: `
		<span>
			{{ todo.text }}
			<button @click="$emit('delete')">
				X
			</button>
		</span>
	`
})
  • 【推荐】为了提升性能,不需要响应式处理的数据,不要直接在data上声明。

    • 可以创建一个声明变量的初始化函数,在created函数中调用。
    • 针对常量不需要修改的数据,可以使用 Object.freeze(常量),进行冻结。

  • 【强制】

    钩子函数中严禁写逻辑代码,逻辑代码应该写在函数中,然后在钩子函数中调用。
  • 【推荐】针对复杂的组件,应该进行对js进行拆分,且每个文件应该按照其功能进行分类,然后设置

    命名空间



6.2 eventBus规范

  • 【推荐】 如果不是大型单页面应用,使用 Vuex 可能是繁琐冗余的, 一个简单的 eventBus 就足够您所需了, 如果是全局使用, 那么统一称为

    globalBus


  • 【强制】

    globalBus 采用以下结构:
├─src    					  #  src 第一级结构
│  ├─globalBus				  #  event bus 目录
│  │   ├─ index.js            # 我们组装模块并导出 globalBus 的地方
│  │   ├─ extend              # 事件扩展的js
│  │   └──request             # 事件用到的请求
│  │   		└──  request.js   # 参考template中的request.js 写法 
//  globalBus=> index.js 模板
// vue框架
import Vue from 'vue';
/**
 * @namespace  global
 * 全局事件命名规则必须是 global+moduleName +  children moduleName
 * 存在globalEventBus的数据,命名必须 以  common 开头,代表通用。
 */
// 全局的eventBus
const globalBus = new Vue({
	mixins: [ ],
	data() {
		return {
			// 通用用户信息
			commonUserInfo: {userId: ''}
		};
	},
	created() {
		// 初始化 globalBus 模块
		this.init();
	},
	beforeDestroy() {
		this.unbindGlobalEvent();
	},
	methods: {
		// 绑定全局事件
		bindGlobalEvent() {
			// 绑定通用数据的事件
			this.commonBindGlobalEvent();
		},
		// 取消全局事件
		unbindGlobalEvent() {
			// 取消绑定通用数据的事件
			this.commonUnbindGlobalEvent();
		},
		// 设置信息
		commonSetUserInfo(commonUserInfo) {
			this.commonUserInfo = commonUserInfo;
		},
		// 绑定通用数据的事件
		commonBindGlobalEvent() {
			// 绑定全局事件给草稿箱添加数据条目
			this.$on('global-common-userInfo', this.commonSetUserInfo);
		},
		// 取消绑定通用数据的事件
		commonUnbindGlobalEvent() {
			// 绑定全局事件给草稿箱添加数据条目
			this.$off('global-common-userInfo', this.commonSetUserInfo);
		}
	}

});
// 绑定全局的eventBus
Vue.prototype.globalBus =globalBus;
// 导出模块
export default globalBus

  • 【强制】

    globalBus 为全局的eventBus ,

    全局事件命名

    必须遵循以下规则:


      • global + moduleName + children moduleName
  • 【推荐】 eventBus 能不用就尽量别用,万一需要使用 eventBus的组件,

    必须新建 文件globalEvent.js

    , 然后混入到组件,该组件的全局事件全部写入该文件,禁止分散写, globalEvent.js 的基本内容如下:

export default {
	data() {
		return {commonActiveNodeInfo: {}};  
	},
	created() {
		// 绑定全局事件
		this.bindGlobalEvent();
	},
	beforeDestroy() {
		// 取消全局事件
		this.unbindGlobalEvent();
	},
	methods: {
		// 设置当前选中节点信息
		setCommonActiveNodeInfo(data) {
			this.commonActiveNodeInfo = data;
		},
		// 绑定全局事件
		bindGlobalEvent() {
			if (this.global) {
				// 绑定设置当前选中节点信息
				this.global.$on('global-common-activeNodeInfo', this.setCommonActiveNodeInfo);
		   }
		},
		// 取消全局事件
		unbindGlobalEvent() {
			if (this.global) {
				// 取消绑定设置当前选中节点信息
				this.global.$off('global-common-activeNodeInfo', this.setCommonActiveNodeInfo);
			 }
		},
		// 触发全局事件
		emitGlobalEvent(callback) {
			if (this.global) {
				callback();
			}
		}
	}
};



6.3 Vuex使用规范

  • 【推荐】 如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,推荐使用

    Vuex

    • vuex 项目结构
├─src    					  #  src 第一级结构
│  ├─store					  #  vuex 目录
│  │   ├─ index.js            # 我们组装模块并导出 store 的地方
│  │   ├─ actions.js          # 根级别的 action
│  │   ├─ mutations.js        # 根级别的 mutation
│  │   ├─ state.js            # 根级别的 state
│  │   ├─ getters.js          # 根级别的 getters
│  │   └──modules             # 根级别的 modules
│  │   		├── cart.js       # 购物车模块
│  │		└── products.js   # 产品模块
  • 【推荐】 vuex命名:

    • state

      • 命名 name
    • mutations

      • 命名 set + Name
    • actions

      • 命名 async + Set + Name
  • 【推荐】 vuex 参考示例:

<script>
// store/modules/todos.js
export default {
	state: {
		// 列表数据
		list: []
	},
	mutations: {
		// 同步设置列表数据  set +List (数据名)
		setList (state, dataList) {
			state.list = dataList;
		}
	},
	actions: {
		// 异步设置列表数据 async + Set + List (数据名)
		asyncSetList ({ commit, state }) {
			setTimeout(() => {
				const dataList = [];
				 commit('list', dataList)
			}, 1000)
		}
	}
}
</script>

<!-- todo-item.vue -->
<template>
	<span>
		{{ todo.text }}
		<button @click="asyncSetList()">
			异步设置数据
		</button>
		 <button @click="setList([])">
			同步设置数据
		</button>
	</span>
</template>

<script src="./index.js">
import { mapActions } from 'vuex'
export default {
	props: {
		todo: {
			type: Object,
			required: true
		}
	},
	methods: {
		...mapActions(['asyncSetList']),
		...mapMutations(['setList']),
	}
}
</script>




第七章 工程结构规范



7.1 项目整体结构


  • 【强制】

    项目结构应该统一按照以下示例,可根据项目情况进行增加和删减。
├─build
├─config
├─doc
│  ├─sonar-doc
│  │  └─images
│  ├─webpack升级
│  ├─前后端分离规范
│  │  └─前端编码规范
│  ├─工程改造
│  ├─语法
│  │  └─git
│  └─问题处理文档
├─src
│  ├─components
│  │  ├─app
│  │  │  ├─module
│  │  │  │  └─a
│  │  │  └─unit-test
│  │  │      ├─test1
│  │  │      ├─test2
│  │  │      └─test3
│  │  │          └─request
│  │  ├─common
│  │  │  ├─notice
│  │  │  │  ├─ajax-loading
│  │  │  │  │  └─images
│  │  │  │  ├─alert
│  │  │  │  └─message
│  │  │  │      └─images
│  │  │  └─other
│  │  │      └─scrollbar
│  │  │          ├─extend
│  │  │          ├─horizontal-scrollbar
│  │  │          ├─preview
│  │  │          ├─test
│  │  │          │  └─static
│  │  │          └─vertical-scrollbar
│  │  ├─config
│  │  ├─template
│  │  │  ├─extend
│  │  │  └─request
│  │  └─tools
│  │      └─extend
│  ├─css
│  │  ├─animation
│  │  ├─common
│  │  ├─components
│  │  │  ├─app
│  │  │  │  └─module
│  │  │  │      └─a
│  │  │  └─common
│  │  ├─config
│  │  ├─mixins
│  │  │  ├─clearfix
│  │  │  └─mask
│  │  └─pages
│  │      ├─page-a
│  │      ├─page-b
│  │      └─page-unit
│  ├─images
│  ├─js
│  │  └─app
│  │      ├─common
│  │      ├─dataTable
│  │      ├─directive
│  │      │  └─clickoutside
│  │      ├─filter
│  │      │  └─capitalize
│  │      └─message
│  ├─pages
│  │  ├─page-a
│  │  ├─page-b
│  │  └─page-unit
│  └─router
├─static
│  ├─js
│  └─json
│      └─test
└─test
    └─unit
        └─specs
            └─unit-test

  • 【强制】

    default: 项目名称。

  • 【强制】

    build:webpack 相关配置。

  • 【强制】

    config:webpack服务器相关配置。

  • 【强制】

    doc:项目文档。

  • 【强制】

    src:前端源码文件夹。

  • 【强制】

    static:前端静态资源。

  • 【强制】

    test:前端单元测试目录。

  • 【强制】

    package.json:项目包管理文件。

  • 【强制】

    readme.md:项目说明文件。

  • 【强制】

    index.html:单页面项目入口文件。


配置文件:


  • 【强制】

    .eslintrc:eslint 配置 eslintrcDoc.js 为eslint每项说明文档。

  • 【强制】

    .stylelintrc:stylelint 配置 stylelintrcDoc.js 为stylintlint每项说明文档。

  • 【强制】

    .babelrc:babel配置。

  • 【强制】

    .jsdoc.conf.json:jsdoc 文档生成配置文件。

  • 【强制】

    .gitignore:git 忽略文件配置。

  • 【强制】

    .eslintignore:eslint 验证忽略配置。

  • 【强制】


    doc目录

    里面包含了开发文档,和工程改造说明,以及一些语法指导文档,不熟悉的在项目开始前先通读文档。使用cl命令新建项目时,务必按照必读文件做一遍。

  • 【强制】


    static目录

    为项目的静态资源,内部目录结构按照【文件类型】进行划分模块,【模块内部】目录结构按照【子模块】进行划分,以此类推。

    • flash:存放项目需要的flash。
    • js:存放项目外部依赖的js 。
    • json:存放项目所需要的所有mock json文件, 前端后项目一定不要受制于后端服务器。
    • svg:存放项目所需要的所有svg文件。



7.2 项目源码结构



7.2.1 项目源码整体结构

├─src
│  ├─components
│  ├─css
│  ├─images
│  ├─js
│  ├─pages
│  ├─router
│  ├─store
│  ├─globalBus
│  ├─APP.vue
│  └─main.js

  • 【强制】

    components : 存放系统所有的组件,另外包含部分工具方法。

  • 【强制】

    css :存放项目需要的所有css(系统样式文件) 。

  • 【强制】

    images:存放项目需要的所有图片。

  • 【强制】

    js:存放项目需要的所有js。

  • 【强制】

    pages:存放项目需要的所有页面(系统模块页面)。

  • 【强制】

    router: 存放系统中的路由配置文件。

  • 【强制】

    store: 存放vuex状态管理文件。

  • 【强制】

    globalBus: 存放全局的eventBus管理文件。

  • 【强制】

    App.vue:系统入口组件。

  • 【强制】

    main.js:系统入口js文件,该文件引入了 App.vue, 另外全局变量,全局组件,全局配置,路由等都是在该文件进行注册。



7.2.2 项目源码components文件夹内部结构

├─components
│  ├─app
│  │   ├─common
│  │   ├─module
│  │   ├─unit-test
│  ├─common
│  │   ├─notice
│  │   ├─other
│  │   ├─index.js
│  │   └─readme.md
│  ├─config
│  ├─template
│  └─tools

  • 【强制】

    app:放系统业务组件。

  • 【强制】

    common:放系统通用组件。

  • 【强制】

    config:组件的配置文件。

  • 【强制】

    template:组件编写的模块文件, 在编写公用组件和业务组件之前,大家可以直接复制template到目标区域,然后把template修改成自己的组件名即可。

  • 【强制】

    tools:通用的工具类。
  • 【说明】 App, common 其内部结构根据组件的分类划分类型结构,如上图app 下有 common类,module类, unit-test类, 为提升复用性,原则上组件的css全部写到外层css目录components目录下,通用组件的css可以直接在组件内部建一个index.less,单独编写,方便其他系统复用。
├─template
│  ├─extend
│  │   └─template-extend.js
│  ├─request
│  │   └─request.js
│  ├─doc.js
│  ├─index.js
│  ├─index.less
│  ├─index.vue
│  └─readme.md

  • 【强制】

    index.vue组件html结构。

  • 【强制】

    index.less组件的css。

  • 【强制】

    index.js组件的js。

  • 【强制】

    extend:该文件夹存放组件拆分的js。

  • 【强制】

    request:该文件夹存放组件用到的所有请求方法,请求多的话,可以进行分类,请求命名空间为

    request

    , 每个请求返回一个promise, 请求内部禁止写其他逻辑代码。
//request.js
// 参考脚手架template模板中的request.js
export default {
    methods: {
        // 请求【模块名】=> 【获取用户数据】
        requestUserData(queryData) {
            return new Promise((resolve, reject) => {
              // ..  请求代码
            });
        }
    }
};

  • 【推荐】 组件内容少于

    200行

    可以将css,js 写到index.vue文件,其他情况,js,css,html 必须按照上述结构编写。



7.2.3 项目源码css文件夹内部结构

├─css 
│  ├─animation
│  ├─common
│  ├─components
│  ├─config
│  ├─mixins
│  ├─pages
│  ├─unit
│  └─index.less

  • 【强制】

    css 目录结构按照类型进行划分,各个类型下有一个index.less,用于串联其下的后代css。

  • 【强制】

    animation:动画类css。

  • 【强制】

    common:公用类css。

  • 【强制】

    components:组件类css, 内部目录结构和组件的文件夹一致。

  • 【强制】

    config:配置类css,因为采用less语法,所以可以配置变量。

  • 【强制】

    mixins:混入类css,加强css的复用。

  • 【强制】

    pages:页面模块类css, 各个页面的css。

  • 【强制】

    unit:元件类css。

  • 【强制】

    index.less 是整个项目的css 入口,里面串联各类型的css。
  • 【推荐】 按照项目需要,大家可以在

    animation

    文件夹编写一些公用的动画方法,以【动画效果】作为文件的名,然后在index.less中进行引入,这样在整个系统都可以通用此动画。
├─animation 
│  ├─index.less(引入其他less)
│  ├─ease.less
│  ├─move.less
│  ├─fade.less
│  ├─rotate.less
│  └─slide.less

  • 【强制】

    公用类CSS需遵守以下规范:

    • normalize.less这里是重置浏览器的样式,来源网络 。
    • base.less 此文件是在 normalize.less上额外增加的全局样式改造 。
    • function.less 这里全部是功能性命名,全部严格模版执行,不可更改,前端统一,有需要修改的可以提出来,然后新增进去,请各位重视。具体使用,可以查看function.md。
├─common 
│  ├─index.less (引入其他less)
│  ├─normalize.less
│  ├─base.less
│  ├─function.less
│  └─function.md



7.2.4 项目源码js文件夹内部结构


├─js 
│  ├─app 
│  │  ├─common
│  │  ├─fdDataTable
│  │  ├─fdDirective
│  │  ├─fdFilter
│  │  └─fdMessage
│  ├─lib 
│  │  └─plugin
│  ├─config.js
│  └─server-config.js


  • 【强制】

    app :项目依赖的、所有自己写的js放这里。

  • 【强制】

    lib : 项目依赖的外部库,插件js全部放这里。

  • 【强制】

    config.js 项目的配置文件,包含请求方法、后端服务器地址、日志、调试多个配置项,大家可以在这里配置项目需要的其他项。

  • 【强制】

    server-config.js 此文件为后端接口api的配置文件。
  • 【推荐】 config.js基本配置。
/**
 * @file config.js
 * @version 1.0.1
 * @author jj
 * @createTime 2019/10/17 - 20:37
 * @updateTime 2019/10/17 - 20:37
 * @see [jsDoc中文文档]{@link  http://www.dba.cn/book/jsdoc/JSDOCKuaiBiaoQianBLOCKTAGS/CONSTRUCTS.html}
 * @description  config.js ,所有的配置文件  详细说明看注释  !important
 */
// 服务器配置
import serverUrl from './server-config.js';
// let production = process.env.NODE_ENV !== 'production'
// 默认开发环境
const develop = true;
// 配置项
const config = {
    //  是否是调试模式,true 为json数据,false 为服务器数据
    isDebug: develop,
    // ajax查询方式   GET
    methodGet: 'GET',
    // ajax查询方式  POST
    methodPost: develop ? 'GET' : 'POST',
    // ajax查询方式  PUT
    methodPut: develop ? 'GET' : 'PUT',
    // ajax查询方式  DELETEsocketio
    methodDelete: develop ? 'GET' : 'DELETE',
    // ajax查询方式  PATCH
    methodPatch: develop ? 'GET' : 'PATCH',
    //  url链接,也就是数据的地址
    url: {},
    // 是否显示日志
    showLog: false,
    // 服务器地址
    dirServicePath: window.serverConfig.dirServicePath
};
// 本地数据
const localUrl = {
    // 测试模块
    test: {
        // 测试模块首页数据
        index: '/static/json/test/index.json'
    }
};
config.url = config.isDebug ? localUrl : serverUrl;
// 注册全局变量,fdConfig
window.fdConfig = config;

  • 【强制】


    lib目录

    存放第三方库,以库名作为分类名称。所有的插件js一律放到plugin中,如果涉及的插件多,种类多,可以在里面继续建文件夹分类。
├─lib 
│  ├─angular
│  ├─echarts
│  ├─jquery
│  ├─plugin
│  │  ├─tree.js
│  │  └─tree.min.js
│  ├─raphael
│  ├─require
│  └─snap

  • 【强制】

    app内部结构如下
├─app 
│  ├─common
│  ├─fdDataTable
│  ├─fdDirective
│  ├─fdFilter
│  └─fdMessage
  • 结构含义

    • fd前缀模块代表

      通用模块

      ,其他模块不可使用此类命名。

      • 如:fdFilter、fdDirective,强制命名,目的在于统一,防止冲突,最后工具合并请求。
    • common: 公用的js文件。

      • 文件名: global.js, 模块名: fdGLobal,表示全局方法。
    • dataTable:前台代码值对应表。

      • 文件名:fdDataTable.js, 模块名: fdDataTable,表示全局数据字典。
      • 具体写法看模块中的 fdDataTable.js。
    • directive:通用指令。

      • 文件名:fdDirective.js,模块名: fdDirective, 表示全局指令, 具体写法看模块中的 fdDirective.js。
    • filter: 通用过滤器。

      • 文件名:fdFilter.js,模块名: fdFilter,表示全局过滤器, 具体写法看模块中的 fdFilter.js。
    • message:消息模块。

      • 文件名:fdMessage.js, 模块名:fdMessage,表示全局消息,里面绑定了window.onmessage,大家根据项目需要,自行判断是否需要。
    • 大家可以根据项目需要,在app下添加其他模块,原则:

      【按模块划分类型】



7.2.5 项目源码pages文件夹内部结构


  • 【强制】

    Pages 用于存放路由用的各个页面, 按照模块划分内部结构,里面存在index.vue 作为页面入口,page-a 表示 a页面(大家不用将page-作为前缀,此处只是示意)。
├─pages 
│  ├─page-a 
│  │  ├─index.vue
│  │  ├─index.less
│  │  └─index.js
│  ├─page-b 
│  │  ├─index.vue
│  │  ├─index.less
│  │  └─index.js
│  └─page-unit
│     ├─index.vue
│     ├─index.less
│     └─index.js



7.2.6 项目源码images文件夹内部结构

├─images 
│  ├─pluginName
│  └─loading.gif

  • 【强制】

    所有图片全部放到 images文件下,如果用了插件的,用插件名为名称建立一个文件夹,存放对应的图片。



7.2.7 项目源码router文件夹内部结构

├─router 
│  └─index.js

  • 【强制】

    此文件夹为 路由配置文件,大家按照自己的需要配置即可。



版权声明:本文为m0_37296026原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。