前端代码规范的笔记(一)

为了方便团队其他人员的阅读本人代码,减少团队交流成本,提高工作效率。代码规范很重要,公司这段时间尤其对这一块重视。

本人对这块的学习改正重点为如下:


HTML

一,class和ID的命名问题:

1.应该以内容和功能命名,不要以表现形式命名。

2.字母为小写,多个字母时用中划线-分隔

3.ID为js hook,避免使用空的class样式

二,ID统一使用双引号

三,标签语意化

标签语义
<p> 段落
<h1> <h2> <h3> ... 标题
<ul> 无序列表
<ol> 有序列表
<blockquote> 大段引用
<cite> 一般引用
<b> 为样式加粗而加粗
<storng> 为强调内容而加粗
<i> 为样式倾斜而倾斜
<em> 为强调内容而倾斜
code 代码标识
abbr 缩写

可以看看这个百度文库里面的优秀文件:https://wenku.baidu.com/view/0a8d3774f242336c1eb95ea9.html

四,HEAD

HEAD模版<!DOCTYPE html>

<html lang="zh-cmn-Hans">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Style Guide</title>
  
   <!-- SEO优化 -->
<meta name="description" content="不超过150个字符"> <meta name="keywords" content=""> <meta name="author" content="name, email@gmail.com"> <!-- 为移动设备添加 viewport --> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- iOS 图标 --> <link rel="apple-touch-icon-precomposed" href="/apple-touch-icon-57x57-precomposed.png"> <link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml" /> <link rel="shortcut icon" href="path/to/favicon.ico"> </head>

1.语言属性的设置

<!-- 中文 -->
<html lang="zh-Hans">

<!-- 简体中文 -->
<html lang="zh-cmn-Hans">

<!-- 繁体中文 -->
<html lang="zh-cmn-Hant">

<!-- English -->
<html lang="en">

2.字符编码

utf-8

3.IE兼容模式

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

4.SEO优化 (搜索引擎优化)

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <!-- SEO -->
    <title>Style Guide</title>
    <meta name="keywords" content="your keywords">
    <meta name="description" content="your description">
    <meta name="author" content="author,email address">
</head>

5.viewport

<meta name="viewport" content="width=device-width, initial-scale=1.0">
  • viewport: 一般指的是浏览器窗口内容区的大小,不包含工具条、选项卡等内容;
  • width: 浏览器宽度,输出设备中的页面可见区域宽度;
  • device-width: 设备分辨率宽度,输出设备的屏幕可见宽度;
  • initial-scale: 初始缩放比例;
  • maximum-scale: 最大缩放比例;

6.favicon

link指定favicon.ico文件

<link rel="shortcut icon" href="path/to/favicon.ico">

CSS

良好的注释是非常重要的。请留出时间来描述组件(component)的工作方式、局限性和构建它们的方法。不要让你的团队其它成员 来猜测一段不通用或不明显的代码的目的。

汇总:

  • 以 Components 的角度思考,以两个单词命名(.screenshot-image
  • Components 中的 Elements,以一个单词命名(.blog-post .title
  • Variants,以中划线-作为前缀(.shop-banner.-with-icon
  • Components 可以互相嵌套
  • 记住,你可以通过继承让事情变得更简单

一,class和ID命名

  • 使用语义化、通用的命名方式;
  • 使用连字符 - 作为 ID、Class 名称界定符,不要驼峰命名法和下划线;
  • 避免选择器嵌套层级过多,尽量少于 3 级;
  • 避免选择器和 Class、ID 叠加使用;

避免class,ID和选择器混合式使用,若改了class名称还要去改CSS代码,不利于后期的维护

二,声明块格式

  • 选择器分组时,保持独立的选择器占用一行;
  • 声明块的左括号 { 前添加一个空格;
  • 声明块的右括号 } 应单独成行;
  • 声明语句中的 : 后应添加一个空格;
  • 声明语句应以分号 ; 结尾;
  • 一般以逗号分隔的属性值,每个逗号后应添加一个空格;
  • rgb()rgba()hsl()hsla() 或 rect() 括号内的值,逗号分隔,但逗号后不添加一个空格;
  • 对于属性值或颜色参数,省略小于 1 的小数前面的 0 (例如,.5 代替 0.5-.5px 代替 -0.5px);
  • 十六进制值应该全部小写和尽量简写,例如,#fff 代替 #ffffff
  • 避免为 0 值指定单位,例如,用 margin: 0; 代替 margin: 0px;

三,声明顺序

相关属性应为一组,推荐的样式编写顺序

  1. Positioning(由于定位(positioning)可以从正常的文档流中移除元素,并且还能覆盖盒模型(box model)相关的样式,因此排在首位)
  2. Box model(盒模型决定了组件的尺寸和位置,因此排在第二位)
  3. Typographic(排版相关)
  4. Visual(视觉)
  5. Other(其他)

四,引号的使用

  1. url() 、属性选择符、属性值使用双引号。

五,媒体查询(Media query)的位置

  将媒体查询放在尽可能相关规则的附近。不要将他们打包放在一个单一样式文件中或者放在文档底部。如果你把他们分开了,将来只会被大家遗忘。

六,不要使用 @import

七,Components 最少以两个单词命名,通过 - 分离

  • 点赞按钮 (.like-button)
  • 搜索框 (.search-form)
  • 文章卡片 (.article-card)

八,Elements 是 Components 中的元素 Elements 命名就用一个单词;

 .search-form {
    > .field { /* ... */ }
    > .action { /* ... */ }
  }

对于倘若需要两个或以上单词表达的 Elements 类名,不应使用中划线和下划线连接,应直接连接

  .profile-box {
    > .firstname { /* ... */ }
    > .lastname { /* ... */ }
    > .avatar { /* ... */ }
  }

任何时候尽可能使用 classnames。标签选择器在使用上没有问题,但是其性能上稍弱,并且表意不明确。避免使用标签选择器。

倘若你需要为组件设置定位,应将在组件的上下文(父元素)中进行处理,比如以下例子中,将 widths 和 floats 应用在 list component(.article-list) 当中,而不是 component(.article-card) 自身。

当出现多个嵌套的时候容易失去控制,应保持不超过一个嵌套

关于CSS的性能优化

一,慎重选择高消耗的样式

  • box-shadows
  • border-radius
  • transparency(透明)
  • transforms(动画)
  • CSS filters(滤镜 性能杀手)

二,避免重排列

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

三,正确的使用display属性

Display 属性会影响页面的渲染,请合理使用。

  • display: inline后不应该再使用 width、height、margin、padding 以及 float;

  • display: inline-block 后不应该再使用 float;

  • display: block 后不应该再使用 vertical-align;

  • display: table-* 后不应该再使用 margin 或者 float;

四,不滥用float

五,动画性能的优化

动画的基本概念:

  • 帧:在动画过程中,每一幅静止画面即为一“帧”;
  • 帧率:即每秒钟播放的静止画面的数量,单位是fps(Frame per second);
  • 帧时长:即每一幅静止画面的停留时间,单位一般是ms(毫秒);
  • 跳帧(掉帧/丢帧):在帧率固定的动画中,某一帧的时长远高于平均帧时长,导致其后续数帧被挤压而丢失的现象。

一般浏览器的渲染刷新频率是 60 fps,所以在网页当中,帧率如果达到 50-60 fps 的动画将会相当流畅,让人感到舒适。

  • 如果使用基于 javaScript 的动画,尽量使用 requestAnimationFrame. 避免使用 setTimeout, setInterval.
  • 避免通过类似 jQuery animate()-style 改变每帧的样式,使用 CSS 声明动画会得到更好的浏览器优化。
  • 使用 translate 取代 absolute 定位就会得到更好的 fps,动画会更顺滑。

六,多利用硬件能力,如通过 3D 变形开启 GPU 加速

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

七,提升CSS选择器的性能

理解了CSS选择器从右到左匹配的机制后,明白只要当前选择符的左边还有其他选择符,样式系统就会继续向左移动,直到找到和规则匹配的选择符,或者因为不匹配而退出。我们把最右边选择符称之为关键选择器

1、避免使用通用选择器

2、避免使用标签或 class 选择器限制 id 选择器

3、避免使用标签限制 class 选择器

4、避免使用多层标签选择器。使用 class 选择器替换,减少css查找

/* Not recommended */
treeitem[mailfolder="true"] > treerow > treecell {}
/* Recommended */
.treecell-mailfolder {}

5、避免使用子选择器

/* Not recommended */
treehead treerow treecell {}
/* Recommended */
treehead > treerow > treecell {}
/* Much to recommended */
.treecell-header {}

6、使用继承

/* Not recommended */
#bookmarkMenuItem > .menu-left { list-style-image: url(blah) }
/* Recommended */
#bookmarkMenuItem { list-style-image: url(blah) }

JavaScript

一,注释

原则:

  • As short as possible(如无必要,勿增注释):尽量提高代码本身的清晰性、可读性。
  • As long as necessary(如有必要,尽量详尽):合理的注释、空行排版等,可以让代码更易阅读、更具美感。

1. 单行注释

必须独占一行。// 后跟一个空格,缩进与下一行被注释说明的代码一致。

2. 多行注释

避免使用 /*...*/ 这样的多行注释。有多行注释内容时,使用多个单行注释。

3. 函数/方法注释

  1. 函数/方法注释必须包含函数说明,有参数和返回值时必须使用注释标识。;
  2. 参数和返回值注释必须包含类型信息和说明;
  3. 当函数是内部函数,外部不可访问时,可以使用 @inner 标识;
/**
 * 函数描述
 *
 * @param {string} p1 参数1的说明
 * @param {string} p2 参数2的说明,比较长
 *     那就换行了.
 * @param {number=} p3 参数3的说明(可选)
 * @return {Object} 返回值描述
 */
function foo(p1, p2, p3) {
    var p3 = p3 || 10;
    return {
        p1: p1,
        p2: p2,
        p3: p3
    };
}

4. 文件注释

文件注释用于告诉不熟悉这段代码的读者这个文件中包含哪些东西。 应该提供文件的大体内容, 它的作者, 依赖关系和兼容性信息。如下:

/**
 * @fileoverview Description of file, its uses and information
 * about its dependencies.
 * @author user@meizu.com (Firstname Lastname)
 * Copyright 2009 Meizu Inc. All Rights Reserved.
 */

二,命名

变量

  1. 变量使用‘驼峰’命名法
  2. 私有属性、变量和方法以下划线 _ 开头。
  3. 常量, 使用全部字母大写,单词间下划线分隔的命名方式。

函数

  函数:

  1. 函数, 使用 Camel 命名法。
  2. 函数的参数, 使用 Camel 命名法。

  类

  1. , 使用 Pascal 命名法
  2. 类的 方法 / 属性, 使用 Camel 命名法

  枚举属性

  1. 枚举变量 使用 Pascal 命名法。
  2. 枚举的属性, 使用全部字母大写,单词间下划线分隔的命名方式。

  由多个单词组成的 缩写词,在命名中,根据当前命名法和出现的位置,所有字母的大小写与首字母的大小写保持一致。

三,命名语法

  1. 类名,使用名词。
  2. 函数名,使用动宾短语。
  3. boolean 类型的变量使用 is 或 has 开头。
  4. Promise 对象用动宾短语的进行时表达。

四,接口命名规范

  1. 可读性强,见名晓义;
  2. 尽量不与 jQuery 社区已有的习惯冲突;
  3. 尽量写全。不用缩写,除非是下面列表中约定的;(变量以表达清楚为目标,uglify 会完成压缩体积工作)
常用词说明
options 表示选项,与 jQuery 社区保持一致,不要用 config, opts 等
active 表示当前,不要用 current 等
index 表示索引,不要用 idx 等
trigger 触点元素
triggerType 触发类型、方式
context 表示传入的 this 对象
object 推荐写全,不推荐简写为 o, obj 等
element 推荐写全,不推荐简写为 el, elem 等
length 不要写成 len, l
prev previous 的缩写
next next 下一个
constructor 不能写成 ctor
easing 示动画平滑函数
min minimize 的缩写
max maximize 的缩写
DOM 不要写成 dom, Dom
.hbs 使用 hbs 后缀表示模版
btn button 的缩写
link 超链接
title 主要文本
img 图片路径(img标签src属性)
dataset html5 data-xxx 数据接口
theme 主题
className 类名
classNameSpace class 命名空间

五,True 和 False 布尔表达式

类型检测优先使用 typeof。对象类型检测使用 instanceof。null 或 undefined 的检测使用 == null。

下面的布尔表达式都返回 false:

  • null
  • undefined
  • '' 空字符串
  • 0 数字0

但小心下面的, 可都返回 true:

  • '0' 字符串0
  • [] 空数组
  • {} 空对象

六,不要在 Array 上使用 for-in 循环

for-in 循环只用于 object/map/hash 的遍历, 对 Array 用 for-in 循环有时会出错. 因为它并不是从 0 到 length - 1 进行遍历, 而是所有出现在对象及其原型链的键值。

// Not recommended
function printArray(arr) {
  for (var key in arr) {
    print(arr[key]);
  }
}

printArray([0,1,2,3]);  // This works.

var a = new Array(10);
printArray(a);  // This is wrong.

a = document.getElementsByTagName('*');
printArray(a);  // This is wrong.

a = [0,1,2,3];
a.buhu = 'wine';
printArray(a);  // This is wrong again.

a = new Array;
a[3] = 3;
printArray(a);  // This is wrong again.

// Recommended
function printArray(arr) {
  var l = arr.length;
  for (var i = 0; i < l; i++) {
    print(arr[i]);
  }
}

七,二元和三元操作符

操作符始终写在前一行, 以免分号的隐式插入产生预想不到的问题。

var x = a ? b : c;

var y = a ?
    longButSimpleOperandB : longButSimpleOperandC;

var z = a ?
        moreComplicatedB :
        moreComplicatedC;

. 操作符也是如此:

var x = foo.bar().
    doSomething().
    doSomethingElse();

八,条件(三元)操作符(?:)

三元操作符用于替代 if 条件判断语句。

// Not recommended
if (val != 0) {
  return foo();
} else {
  return bar();
}

// Recommended
return val ? foo() : bar();

九,&& 和 ||

二元布尔操作符是可短路的, 只有在必要时才会计算到最后一项。

// Not recommended
function foo(opt_win) {
  var win;
  if (opt_win) {
    win = opt_win;
  } else {
    win = window;
  }
  // ...
}

if (node) {
  if (node.kids) {
    if (node.kids[index]) {
      foo(node.kids[index]);
    }
  }
}

// Recommended
function foo(opt_win) {
  var win = opt_win || window;
  // ...
}

var kid = node && node.kids && node.kids[index];
if (kid) {
  foo(kid);
}

jQuery规范

一,使用最新版本的 jQuery

最新版本的 jQuery 会改进性能和增加新功能,若不是为了兼容旧浏览器,建议使用最新版本的 jQuery。以下是三条常见的 jQuery 语句,版本越新,性能越好

$('.elem')
$('.elem', context)
context.find('.elem')

 分别使用 1.4.2、1.4.4、1.6.2 三个版本测试浏览器在一秒内能够执行多少次,结果 1.6.2 版执行次数远超两个老版本。

二,jQuery 变量

  1. 存放 jQuery 对象的变量以 $ 开头;
  2. 将 jQuery 选择器返回的对象缓存到本地变量中复用;
  3. 使用驼峰命名变量;
var $myDiv = $("#myDiv");
$myDiv.click(function(){...});

三,选择器

  1. 尽可能的使用 ID 选择器,因为它会调用浏览器原生方法 document.getElementById 查找元素。当然直接使用原生 document.getElementById 方法性能会更好;
  2. 在父元素中选择子元素使用 .find() 方法性能会更好, 因为 ID 选择器没有使用到 Sizzle 选择器引擎来查找元素;
// Not recommended
var $productIds = $("#products .class");

// Recommended
var $productIds = $("#products").find(".class");

四,DOM 操作

  1. 当要操作 DOM 元素的时候,尽量将其分离节点,操作结束后,再插入节点;
  2. 使用字符串连接或 array.join 要比 .append()性能更好;
var $myList = $("#list-container > ul").detach();
//...a lot of complicated things on $myList
$myList.appendTo("#list-container");
// Not recommended
var $myList = $("#list");
for(var i = 0; i < 10000; i++){
    $myList.append("<li>"+i+"</li>");
}

// Recommended
var $myList = $("#list");
var list = "";
for(var i = 0; i < 10000; i++){
    list += "<li>"+i+"</li>";
}
$myList.html(list);

// Much to recommended
var array = [];
for(var i = 0; i < 10000; i++){
    array[i] = "<li>"+i+"</li>";
}
$myList.html(array.join(''));

五,事件

  1. 如果需要,对事件使用自定义的 namespace,这样容易解绑特定的事件,而不会影响到此 DOM 元素的其他事件监听;
  2. 对 Ajax 加载的 DOM 元素绑定事件时尽量使用事件委托。事件委托允许在父元素绑定事件,子代元素可以响应事件,也包括 Ajax 加载后添加的子代元素;
$("#myLink").on("click.mySpecialClick", myEventHandler);
$("#myLink").unbind("click.mySpecialClick");
// Not recommended
$("#list a").on("click", myClickHandler);

// Recommended
$("#list").on("click", "a", myClickHandler);

六,链式写法

  1. 尽量使用链式写法而不是用变量缓存或者多次调用选择器方法;
  2. 当链式写法超过三次或者因为事件绑定变得复杂后,使用换行和缩进保持代码可读性;
$("#myDiv").addClass("error").show();
$("#myLink")
  .addClass("bold")
  .on("click", myClickHandler)
  .on("mouseover", myMouseOverHandler)
  .show();

七,其他

  1. 多个参数使用对象字面量存储;
  2. 不要将 CSS 写在 jQuery 里面;
  3. 正则表达式仅准用 .test() 和 .exec() 。不准用 "string".match() ;

八,jQuery插件模版

// jQuery Plugin Boilerplate
// A boilerplate for jumpstarting jQuery plugins development
// version 1.1, May 14th, 2011
// by Stefan Gabos

// remember to change every instance of "pluginName" to the name of your plugin!
(function($) {

    // here we go!
    $.pluginName = function(element, options) {

        // plugin's default options
        // this is private property and is  accessible only from inside the plugin
        var defaults = {

            foo: 'bar',

            // if your plugin is event-driven, you may provide callback capabilities
            // for its events. execute these functions before or after events of your
            // plugin, so that users may customize those particular events without
            // changing the plugin's code
            onFoo: function() {}

        }

        // to avoid confusions, use "plugin" to reference the
        // current instance of the object
        var plugin = this;

        // this will hold the merged default, and user-provided options
        // plugin's properties will be available through this object like:
        // plugin.settings.propertyName from inside the plugin or
        // element.data('pluginName').settings.propertyName from outside the plugin,
        // where "element" is the element the plugin is attached to;
        plugin.settings = {}

        var $element = $(element), // reference to the jQuery version of DOM element
             element = element;    // reference to the actual DOM element

        // the "constructor" method that gets called when the object is created
        plugin.init = function() {

            // the plugin's final properties are the merged default and
            // user-provided options (if any)
            plugin.settings = $.extend({}, defaults, options);

            // code goes here

        }

        // public methods
        // these methods can be called like:
        // plugin.methodName(arg1, arg2, ... argn) from inside the plugin or
        // element.data('pluginName').publicMethod(arg1, arg2, ... argn) from outside
        // the plugin, where "element" is the element the plugin is attached to;

        // a public method. for demonstration purposes only - remove it!
        plugin.foo_public_method = function() {

            // code goes here

        }

        // private methods
        // these methods can be called only from inside the plugin like:
        // methodName(arg1, arg2, ... argn)

        // a private method. for demonstration purposes only - remove it!
        var foo_private_method = function() {

            // code goes here

        }

        // fire up the plugin!
        // call the "constructor" method
        plugin.init();

    }

    // add the plugin to the jQuery.fn object
    $.fn.pluginName = function(options) {

        // iterate through the DOM elements we are attaching the plugin to
        return this.each(function() {

            // if plugin has not already been attached to the element
            if (undefined == $(this).data('pluginName')) {

                // create a new instance of the plugin
                // pass the DOM element and the user-provided options as arguments
                var plugin = new $.pluginName(this, options);

                // in the jQuery version of the element
                // store a reference to the plugin object
                // you can later access the plugin and its methods and properties like
                // element.data('pluginName').publicMethod(arg1, arg2, ... argn) or
                // element.data('pluginName').settings.propertyName
                $(this).data('pluginName', plugin);

            }

        });

    }

})(jQuery);

九,性能优化

1,避免不必要的 DOM 操作

浏览器遍历 DOM 元素的代价是昂贵的。最简单优化 DOM 树查询的方案是,当一个元素出现多次时,将它保存在一个变量中,就避免多次查询 DOM 树了。

// Recommended
var myList = "";
var myListHTML = document.getElementById("myList").innerHTML;

for (var i = 0; i < 100; i++) {
  myList += "<span>" + i + "</span>";
}

myListHTML = myList;

// Not recommended
for (var i = 0; i < 100; i++) {
  document.getElementById("myList").innerHTML += "<span>" + i + "</span>";
}

2,缓存数组的长度

循环无疑是和 JavaScript 性能非常相关的一部分。通过存储数组的长度,可以有效避免每次循环重新计算。

注: 虽然现代浏览器引擎会自动优化这个过程,但是不要忘记还有旧的浏览器。

var arr = new Array(1000),
    len, i;
// Recommended - size is calculated only 1 time and then stored
for (i = 0, len = arr.length; i < len; i++) {

}

// Not recommended - size needs to be recalculated 1000 times
for (i = 0; i < arr.length; i++) {

}

3,异步加载第三方内容

当你无法保证嵌入第三方内容比如 Youtube 视频或者一个 like/tweet 按钮可以正常工作的时候,你需要考虑用异步加载这些代码,避免阻塞整个页面加载。

(function() {

    var script,
        scripts = document.getElementsByTagName('script')[0];

    function load(url) {
      script = document.createElement('script');
      script.async = true;
      script.src = url;
      scripts.parentNode.insertBefore(script, scripts);
    }

    load('//apis.google.com/js/plusone.js');
    load('//platform.twitter.com/widgets.js');
    load('//s.widgetsite.com/widget.js');

}());

4,避免使用jQuery实现动画

  1. 禁止使用 slideUp/Down() fadeIn/fadeOut() 等方法;
  2. 尽量不使用 animate() 方法;

移动端优化

移动Web问题小结

http://www.alloyteam.com/2015/06/yi-dong-web-wen-ti-xiao-jie/

移动端统计

https://github.com/jtyjty99999/mobileTech

关于无线端Web解决方案

http://am-team.github.io/about/about.html

click 的300ms延迟响应

click 事件因为要等待双击确认,会有 300ms 的延迟,体验并不是很好。

开发者大多数会使用封装的 tap 事件来代替click 事件,所谓的 tap 事件由 touchstart 事件 + touchmove 判断 + touchend 事件封装组成。

原文地址:https://www.cnblogs.com/Webzhoushifa/p/9523613.html