Coder Social home page Coder Social logo

blog's Introduction

Sam.gao 的网络日志

喜欢的话点 star 或 watch,不要fork!!!

一、网络

二、前端

Css 系列

JavaScript系列

TypeScript系列

工程化

框架

三、后端

四、多端

投放&商业化相关

五、其他

六、我的图书

七、友情链接

blog's People

Contributors

samgao0312 avatar

Stargazers

 avatar

Watchers

 avatar  avatar

Forkers

houdq

blog's Issues

【npm】package.json和package-lock.json的区别?

发现每个项目下面都会有 package-lock.jsonpackage.json这两个 文件,之前并没有去理清楚两者之间的区别,今天网上查了!


两者区别

首先 ,直接说下结论吧!

package-lock 就是用来锁定安装依赖包的版本号的。。这个文件是需要上传到git上的,这样才能保证其他人在 install 时候,大家装的依赖版本都是相同的。

官方文档:
这个 package-lock.json 是在 npm install 时生成一份文件,用以记录当前状态下实际安装的各个npm package 的具体来源 及版本号。


举个栗子🌰

跟 package.json 的区别在于(举个栗子):

"dependencies": {
 "@types/node": "^8.0.33",
},

这里的 ^ 向上尖号 是定义向后(新)兼容依赖。
如果 types/node 版本是超过 8.0.33,并且是在大版本(8)上相同,就允许下载最新的types/node包。
同一个大版本不同版本号之间存在差异,导致依赖库包行为特征有时候不兼容。

package.json 文件只能锁定大版本,即版本号的第一位,不能锁定后面的小版本,你每次 npm install 时候拉取的该大版本下面最新的版本,可能有些童鞋之前就踩过类似的坑。

但是,一般为了稳定性考虑我们不能随意升级依赖包,因为如果换包导致兼容性bug出现很难排查。

所以, package-lock.json 就是来解决 包锁定不升级 问题的。npm最新的版本就开始自动有了生成 package-lock.json 文件的功能,目的就是确保所有库包与你上次安装的完全一样。


怎么升级 package-lock.json 里面的安装包

如果要升级package-lock.json里面的库包,只需要重新安装指定版本的包即可:

npm install [email protected] 

【文档】 混合开发 远程调试文档

一、Android

利用 Chrome 开发者工具远程调试 Android 中的原生 WebView

  1. 第一步: 打开手机开发者模式;
  2. 第二步: 通过 USB 数据线链接手机和电脑,打开USB调试模式。
  3. 第三步: 打开 Chrome 浏览器,输入URL: chrome://inspect
  4. 第四步: 在手机中打开app中H5页面,这个时候webview 中的 H5 页面链接就会出现在下面。然后点击 inspect 按钮即弹出控制台。之后调试就完全跟直接在Chrome 浏览器中一样了。

<br / >

二、IOS

2.1 Safari 远程调试 iOS webview

  1. 第一步: 打开手机 设置 -> Safari浏览器 -> 高级 -> 勾选上“Javascript”“Web 检测器这两项”
  2. 第二步: 电脑 Safari浏览器偏好设置 -> 高级-> 底部勾上 【在菜单栏中显示“开发”菜单】
  3. 第三步: 通过数据线链接手机和电脑。
  4. 第四步: 打开app中对应的 webview 页面;
  5. 第五步: 在菜单栏 【开发】选项里选择自己的手机(模拟器也是可以的)。列表里会显示加载的url,选择对应的url就可以开始调试了,可以看js,打断点,控制台输命令等操作。

2.2 chrome 远程调试 iOS webview

  1. 安装 ios-webkit-debug-proxy
brew install ios-webkit-debug-proxy
  1. 启动代理
ios_webkit_debug_proxy -f chrome-devtools://devtools/bundled/inspector.html

命令行回显类似这样的结果,其中9222对应模拟器,9223对应真机:

ios_webkit_debug_proxy -f chrome-devtools://devtools/bundled/inspector.html
Listing devices on :9221
Connected :9222 to SIMULATOR (SIMULATOR)
Connected :9223 to iPhone (2) (3aa60e1e6f85130d48a9cbe7f8091237d96baf9a)

输入地址 localhost:9221, 然后页面上会显示对应的一些链接。复制打开 -> 打开chrome debug工具调试;

前端代码规范 —— JavaScript篇

JavaScript编码规范


一、 前言

二、 代码风格

  2.1 文件

  2.2 结构

    2.2.1 缩进

    2.2.2 空格

    2.2.3 换行

    2.2.4 语句

  2.3 命名

  2.4 注释

    2.4.1 单行注释

    2.4.2 多行注释

    2.4.3 文档化注释

    2.4.4 类型定义

    2.4.5 文件注释

    2.4.6 命名空间注释

    2.4.7 类注释

    2.4.8 函数/方法注释

    2.4.9 事件注释

    2.4.10 常量注释

    2.4.11 复杂类型注释

    2.4.12 AMD 模块注释

    2.4.13 细节注释

三、 语言特性

  3.1 变量

  3.2 条件

  3.3 循环

  3.4 类型

    3.4.1 类型检测

    3.4.2 类型转换

  3.5 字符串

  3.6 对象

  3.7 数组

  3.8 函数

    3.8.1 函数长度

    3.8.2 参数设计

四、 浏览器环境

  4.1 DOM

    4.1.1 元素获取

    4.1.2 样式获取

    4.1.3 样式设置

    4.1.4 DOM 操作

    4.1.5 DOM 事件


一、 前言

写这个文档的目标是使 JavaScript 代码风格保持一致,容易被理解和被维护。

虽然本文档是针对 JavaScript 设计的,但是在使用各种 JavaScript 的预编译语言(如 TypeScript 等)时,适用的部分也应尽量遵循本文档的约定。


二、 代码风格

2.1 文件

[建议] JavaScript 文件使用无 BOMUTF-8 编码。

解释:UTF-8 编码具有 更广泛的适应性。BOM 在使用程序或工具处理文件时可能造成不必要的干扰。

[建议] 在文件结尾处,保留一个空行。

2.2 结构

2.2.1 缩进

[强制] 使用 2 个空格做为一个缩进层级,不允许使用 4 个空格 或 tab 字符。
[强制] switch 下的 casedefault 必须增加一个缩进层级。

示例:

// good
switch (variable) {

    case '1':
        // do...
        break;

    case '2':
        // do...
        break;

    default:
        // do...

}

// bad
switch (variable) {

case '1':
    // do...
    break;

case '2':
    // do...
    break;

default:
    // do...

}

2.2.2 空格

[强制] 二元运算符两侧必须有一个空格,一元运算符与操作对象之间不允许有空格。

示例:

var a = !arr.length;
a++;
a = b + c;
[强制] 用作代码块起始的左花括号 { 前必须有一个空格。

示例:

// good
if (condition) {
}

while (condition) {
}

function funcName() {
}

// bad
if (condition){
}

while (condition){
}

function funcName(){
}
[强制] if / else / for / while / function / switch / do / try / catch / finally 关键字后,必须有一个空格。

示例:

// good
if (condition) {
}

while (condition) {
}

(function () {
})();

// bad
if(condition) {
}

while(condition) {
}

(function() {
})();
[强制] 在对象创建时,属性中的 : 之后必须有空格,: 之前不允许有空格。

示例:

// good
var obj = {
    a: 1,
    b: 2,
    c: 3
};

// bad
var obj = {
    a : 1,
    b:2,
    c :3
};
[强制] 函数声明、具名函数表达式、函数调用中,函数名和 ( 之间不允许有空格。

示例:

// good
function funcName() {
}

var funcName = function funcName() {
};

funcName();

// bad
function funcName () {
}

var funcName = function funcName () {
};

funcName ();
[强制] ,; 前不允许有空格。如果不位于行尾,,; 后必须跟一个空格。

示例:

// good
callFunc(a, b);

// bad
callFunc(a , b) ;
[强制] 在函数调用、函数声明、括号表达式、属性访问、if / for / while / switch / catch 等语句中,()[] 内紧贴括号部分不允许有空格。

示例:

// good

callFunc(param1, param2, param3);

save(this.list[this.indexes[i]]);

needIncream && (variable += increament);

if (num > list.length) {
}

while (len--) {
}


// bad

callFunc( param1, param2, param3 );

save( this.list[ this.indexes[ i ] ] );

needIncreament && ( variable += increament );

if ( num > list.length ) {
}

while ( len-- ) {
}

2.2.3 换行

[强制] 每个独立语句结束后必须换行。
[强制] 每行不得超过 120 个字符。
[强制] 在函数声明、函数表达式、函数调用、对象创建、数组创建、for 语句等场景中,不允许在 ,; 前换行。

示例:

// good
var obj = {
    a: 1,
    b: 2,
    c: 3
};

foo(
    aVeryVeryLongArgument,
    anotherVeryLongArgument,
    callback
);


// bad
var obj = {
    a: 1
    , b: 2
    , c: 3
};

foo(
    aVeryVeryLongArgument
    , anotherVeryLongArgument
    , callback
);
[建议] 不同行为或逻辑的语句集,使用空行隔开,更易阅读。

示例:

// 仅为按逻辑换行的示例,不代表setStyle的最优实现
function setStyle(element, property, value) {
    if (element == null) {
        return;
    }

    element.style[property] = value;
}

2.2.4 语句

[强制] 不得省略语句结束的分号。
[强制] 在 if / else / for / do / while 语句中,即使只有一行,也不得省略块 {...}

示例:

// good
if (condition) {
    callFunc();
}

// bad
if (condition) callFunc();
if (condition)
    callFunc();
[强制] 函数定义结束不允许添加分号。

示例:

// good
function funcName() {
}

// bad
function funcName() {
};

// 如果是函数表达式,分号是不允许省略的。
var funcName = function () {
};
[强制] IIFE 必须在函数表达式外添加 (,非 IIFE 不得在函数表达式外添加 (

解释:

IIFE = Immediately-Invoked Function Expression.

额外的 ( 能够让代码在阅读的一开始就能判断函数是否立即被调用,进而明白接下来代码的用途。而不是一直拖到底部才恍然大悟。

示例:

// good
var task = (function () { //IIFE
   // Code
   return result;
})();

var func = function () { //非IIFE
};


// bad
var task = function () { // IIFE
    // Code
    return result;
}();

var func = (function () { //非IIFE
});

2.3 命名

[强制] 变量 使用 Camel命名法

示例:

var loadingModules = {};
[强制] 常量 使用 全部字母大写,单词间下划线分隔 的命名方式。

示例:

var HTML_ENTITY = {};
[强制] 函数 使用 Camel命名法

示例:

function stringFormat(source) {
}
[强制] 函数的 参数 使用 Camel命名法

示例:

function hear(theBells) {
}
[强制] 使用 Pascal命名法

示例:

function TextNode(options) {
}
[强制] 类的 方法 / 属性 使用 Camel命名法

示例:

function TextNode(value, engine) {
    this.value = value;
    this.engine = engine;
}

TextNode.prototype.clone = function () {
    return this;
};
[强制] 枚举变量 使用 Pascal命名法枚举的属性 使用 全部字母大写,单词间下划线分隔 的命名方式。

示例:

var TargetState = {
    READING: 1,
    READED: 2,
    APPLIED: 3,
    READY: 4
};
[强制] 命名空间 使用 Camel命名法

示例:

equipments.heavyWeapons = {};
[强制] 由多个单词组成的缩写词,在命名中,根据当前命名法和出现的位置,所有字母的大小写与首字母的大小写保持一致。

示例:

function XMLParser() {
}

function insertHTML(element, html) {
}

var httpRequest = new HTTPRequest();
[强制] 类名 使用 名词

示例:

function Engine(options) {
}
[建议] 函数名 使用 动宾短语

示例:

function getStyle(element) {
}
[建议] boolean 类型的变量使用 ishas 开头。

示例:

var isReady = false;
var hasMoreCommands = false;
[建议] Promise对象动宾短语的进行时 表达。

示例:

var loadingData = ajax.get('url');
loadingData.then(callback);

2.4 注释

2.4.1 单行注释

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

2.4.2 多行注释

[建议] 使用 /*...*/ 这样的多行注释。或使用多个单行注释。

2.4.3 文档化注释

[强制] 为了便于代码阅读和自文档化,以下内容必须包含以 /**...*/ 形式的块注释中。

解释:

  1. 文件
  2. namespace
  3. 函数或方法
  4. 类属性
  5. 事件
  6. 全局变量
  7. 常量
  8. AMD 模块
[强制] 文档注释前必须空一行。
[建议] 自文档化的文档说明 what,而不是 how。

2.4.4 类型定义

[强制] 类型定义都是以 { 开始, 以 } 结束。

解释:

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

类型不仅局限于内置的类型,也可以是自定义的类型。比如定义了一个类 Developer,就可以使用它来定义一个参数和返回值的类型。

[强制] 对于基本类型 {string}, {number}, {boolean},首字母必须小写。
类型定义 语法示例 解释
String {string} --
Number {number} --
Boolean {boolean} --
Object {Object} --
Function {Function} --
RegExp {RegExp} --
Array {Array} --
Date {Date} --
单一类型集合 {Array.<string>} 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 变长参数,类型不限

2.4.5 文件注释

[强制] 文件顶部必须包含文件注释,用 @file 标识文件说明。

示例:

/**
 * @file Describe the file
 */
[建议] 文件注释中可以用 @author 标识开发者信息。

解释:
开发者信息 能够体现开发人员对文件的贡献,并且能够让遇到问题或希望了解相关信息的人找到维护人。通常情况文件在被创建时标识的是创建者。随着项目的进展,越来越多的人加入,参与这个文件的开发,新的作者应该被加入 @author 标识。

@author 标识具有多人时,原则是按照 责任 进行排序。通常的说就是如果有问题,就是找第一个人应该比找第二个人有效。比如文件的创建者由于各种原因,模块移交给了其他人或其他团队,后来因为新增需求,其他人在新增代码时,添加 @author 标识应该把自己的名字添加在创建人的前面。

@author 中的名字不允许被删除。任何劳动成果都应该被尊重。

示例:

/**
 * @file Describe the file
 * @author author-name([email protected])
 *         author-name2([email protected])
 */

2.4.6 命名空间注释

[建议] 命名空间使用 @namespace 标识。

示例:

/**
 * @namespace
 */
var util = {};

2.4.7 类注释

[建议] 使用 @class 标记类或构造函数。

解释:

对于使用对象 constructor 属性来定义的构造函数,可以使用 @constructor 来标记。

示例:

/**
 * 描述
 *
 * @class
 */
function Developer() {
    // constructor body
}
[建议] 使用 @extends 标记类的继承信息。

示例:

/**
 * 描述
 *
 * @class
 * @extends Developer
 */
function Fronteer() {
    Developer.call(this);
    // constructor body
}
util.inherits(Fronteer, Developer);
[强制] 使用包装方式扩展类成员时, 必须通过 @lends 进行重新指向。

解释:

没有 @lends 标记将无法为该类生成包含扩展类成员的文档。

示例:

/**
 * 类描述
 *
 * @class
 * @extends Developer
 */
function Fronteer() {
    Developer.call(this);
    // constructor body
}

util.extend(
    Fronteer.prototype,
    /** @lends Fronteer.prototype */{
        getLevel: function () {
            // TODO
        }
    }
);
[强制] 类的属性或方法等成员信息不是 public 的,应使用 @protected@private 标识可访问性。

解释:

生成的文档中将有可访问性的标记,避免用户直接使用非 public 的属性或方法。

示例:

/**
 * 类描述
 *
 * @class
 * @extends Developer
 */
var Fronteer = function () {
    Developer.call(this);

    /**
     * 属性描述
     *
     * @type {string}
     * @private
     */
    this.level = 'T12';

    // constructor body
};
util.inherits(Fronteer, Developer);

/**
 * 方法描述
 *
 * @private
 * @return {string} 返回值描述
 */
Fronteer.prototype.getLevel = function () {
};

2.4.8 函数/方法注释

[强制] 函数/方法注释必须包含函数说明,有参数和返回值时必须使用注释标识。

解释:

return 关键字仅作退出函数/方法使用时,无须对返回值作注释标识。

[强制] 参数和返回值注释必须包含类型信息,且不允许省略参数的说明。
[建议] 当函数是内部函数,外部不可访问时,可以使用 @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
    };
}
[强制] 对 Object 中各项的描述, 必须使用 @param 标识。

示例:

/**
 * 函数描述
 *
 * @param {Object} option 参数描述
 * @param {string} option.url option项描述
 * @param {string=} option.method option项描述,可选参数
 */
function foo(option) {
    // TODO
}
[建议] 重写父类方法时, 应当添加 @override 标识。如果重写的形参个数、类型、顺序和返回值类型均未发生变化,可省略 @param@return,仅用 @override 标识,否则仍应作完整注释。

解释:

简而言之,当子类重写的方法能直接套用父类的方法注释时可省略对参数与返回值的注释。

2.4.9 事件注释

[强制] 必须使用 @event 标识事件,事件参数的标识与方法描述的参数标识相同。

示例:

/**
 * 值变更时触发
 *
 * @event Select#change
 * @param {Object} e e描述
 * @param {string} e.before before描述
 * @param {string} e.after after描述
 */
this.fire(
    'change',
    {
        before: 'foo',
        after: 'bar'
    }
);
[强制] 在会广播事件的函数前使用 @fires 标识广播的事件,在广播事件代码前使用 @event 标识事件。
[建议] 对于事件对象的注释,使用 @param 标识,生成文档时可读性更好。

示例:

/**
 * 点击处理
 *
 * @fires Select#change
 * @private
 */
Select.prototype.clickHandler = function () {

    /**
     * 值变更时触发
     *
     * @event Select#change
     * @param {Object} e e描述
     * @param {string} e.before before描述
     * @param {string} e.after after描述
     */
    this.fire(
        'change',
        {
            before: 'foo',
            after: 'bar'
        }
    );
};

2.4.10 常量注释

[强制] 常量必须使用 @const 标记,并包含说明和类型信息。

示例:

/**
 * 常量说明
 *
 * @const
 * @type {string}
 */
var REQUEST_URL = 'myurl.do';

2.4.11 复杂类型注释

[建议] 对于类型未定义的复杂结构的注释,可以使用 @typedef 标识来定义。

示例:

// `namespaceA~` 可以换成其它 namepaths 前缀,目的是为了生成文档中能显示 `@typedef` 定义的类型和链接。
/**
 * 服务器
 *
 * @typedef {Object} namespaceA~Server
 * @property {string} host 主机
 * @property {number} port 端口
 */

/**
 * 服务器列表
 *
 * @type {Array.<namespaceA~Server>}
 */
var servers = [
    {
        host: '1.2.3.4',
        port: 8080
    },
    {
        host: '1.2.3.5',
        port: 8081
    }
];

2.4.12 细节注释

对于内部实现、不容易理解的逻辑说明、摘要信息等,我们可能需要编写 细节注释。

[建议] 细节注释遵循单行注释的格式。说明必须换行时,每行是一个单行注释的起始。

示例:

function foo(p1, p2, opt_p3) {
    // 这里对具体内部逻辑进行说明
    // 说明太长需要换行
    for (...) {
        ....
    }
}
[强制] 有时我们会使用一些特殊标记进行说明。特殊标记必须使用单行注释的形式。下面列举了一些常用标记:

解释:

  1. TODO: 有功能待实现。此时需要对将要实现的功能进行简单说明。
  2. FIXME: 该处代码运行没问题,但可能由于时间赶或者其他原因,需要修正。此时需要对如何修正进行简单说明。
  3. HACK: 为修正某些问题而写的不太好或者使用了某些诡异手段的代码。此时需要对思路或诡异手段进行描述。
  4. XXX: 该处存在陷阱。此时需要对陷阱进行描述。

三、 语言特性

3.1 变量

[强制] 变量、函数在使用前必须先定义。

解释:不通过 var 定义变量将导致变量污染全局环境。

示例:

// good
var name = 'MyName';

// bad
name = 'MyName';

原则上不建议使用全局变量,对于已有的全局变量或第三方框架引入的全局变量,需要根据检查工具的语法标识。

示例:

/* globals jQuery */
var element = jQuery('#element-id');
[强制] 每个 var 只能声明一个变量。

解释:一个 var 声明多个变量,容易导致较长的行长度,并且在修改时容易造成逗号和分号的混淆。

示例:

// good
var hangModules = [];
var missModules = [];
var visited = {};

// bad
var hangModules = [],
    missModules = [],
    visited = {};
[强制] 变量必须 即用即声明,不得在函数或其它形式的代码块起始位置统一声明所有变量。

解释:

变量声明与使用的距离越远,出现的跨度越大,代码的阅读与维护成本越高。虽然JavaScript的变量是函数作用域,还是应该根据编程中的意图,缩小变量出现的距离空间。

示例:

// good
function kv2List(source) {
    var list = [];

    for (var key in source) {
        if (source.hasOwnProperty(key)) {
            var item = {
                k: key,
                v: source[key]
            };

            list.push(item);
        }
    }

    return list;
}

// bad
function kv2List(source) {
    var list = [];
    var key;
    var item;

    for (key in source) {
        if (source.hasOwnProperty(key)) {
            item = {
                k: key,
                v: source[key]
            };

            list.push(item);
        }
    }

    return list;
}

3.2 条件

[强制] 在 Equality Expression 中使用类型严格的 ===。仅当判断 nullundefined 时,允许使用 == null

解释:

使用 === 可以避免等于判断中隐式的类型转换。

示例:

// good
if (age === 30) {
    // ......
}

// bad
if (age == 30) {
    // ......
}
[建议] 尽可能使用简洁的表达式。

示例:

// 字符串为空

// good
if (!name) {
    // ......
}

// bad
if (name === '') {
    // ......
}
// 字符串非空

// good
if (name) {
    // ......
}

// bad
if (name !== '') {
    // ......
}
// 数组非空

// good
if (collection.length) {
    // ......
}

// bad
if (collection.length > 0) {
    // ......
}
// 布尔不成立

// good
if (!notTrue) {
    // ......
}

// bad
if (notTrue === false) {
    // ......
}
// null 或 undefined

// good
if (noValue == null) {
  // ......
}

// bad
if (noValue === null || typeof noValue === 'undefined') {
  // ......
}
[建议] 按执行频率排列分支的顺序。

解释:

按执行频率排列分支的顺序好处是:

  1. 阅读的人容易找到最常见的情况,增加可读性。
  2. 提高执行效率。
[建议] 对于相同变量或表达式的多值条件,用 switch 代替 if

示例:

// good
switch (typeof variable) {
    case 'object':
        // ......
        break;
    case 'number':
    case 'boolean':
    case 'string':
        // ......
        break;
}

// bad
var type = typeof variable;
if (type === 'object') {
    // ......
}
else if (type === 'number' || type === 'boolean' || type === 'string') {
    // ......
}

3.3 循环

[建议] 不要在循环体中包含函数表达式,事先将函数提取到循环体外。

解释:循环体中的函数表达式,运行过程中会生成循环次数个函数对象。

示例:

// good
function clicker() {
    // ......
}

for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    addListener(element, 'click', clicker);
}


// bad
for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    addListener(element, 'click', function () {});
}
[建议] 对循环内多次使用的不变值,在循环外用变量缓存。

示例:

// good
var width = wrap.offsetWidth + 'px';
for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    element.style.width = width;
    // ......
}


// bad
for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    element.style.width = wrap.offsetWidth + 'px';
    // ......
}

3.4 类型

3.4.1 类型检测

[建议] 类型检测优先使用 typeof。对象类型检测使用 instanceofnullundefined 的检测使用 == null

示例:

// string
typeof variable === 'string'

// number
typeof variable === 'number'

// boolean
typeof variable === 'boolean'

// Function
typeof variable === 'function'

// Object
typeof variable === 'object'

// RegExp
variable instanceof RegExp

// Array
variable instanceof Array

// null
variable === null

// null or undefined
variable == null

// undefined
typeof variable === 'undefined'

3.4.2 类型转换

[建议] 转换成 string 时,使用 + ''

示例:

// good
num + '';

// bad
new String(num);
num.toString();
String(num);
[建议] 转换成 number 时,通常使用 +

示例:

// good
+str;

// bad
Number(str);
[建议] string 转换成 number,要转换的字符串结尾包含非数字并期望忽略时,使用 parseInt

示例:

var width = '200px';
parseInt(width, 10);
[强制] 使用 parseInt 时,必须指定进制。

示例:

// good
parseInt(str, 10);

// bad
parseInt(str);
[建议] 转换成 boolean 时,使用 !!

示例:

var num = 3.14;
!!num;
[建议] number 去除小数点,使用 Math.floor / Math.round / Math.ceil,不使用 parseInt

示例:

// good
var num = 3.14;
Math.ceil(num);

// bad
var num = 3.14;
parseInt(num, 10);

3.5 字符串

[强制] 字符串开头和结束使用单引号 '

解释:

  1. 输入单引号不需要按住 shift,方便输入。
  2. 实际使用中,字符串经常用来拼接 HTML。为方便 HTML 中包含双引号而不需要转义写法。

示例:

var str = '我是一个字符串';
var html = '<div class="cls">拼接HTML可以省去双引号转义</div>';
[建议] 使用 数组+ 拼接字符串。

解释:

  1. 使用 + 拼接字符串,如果拼接的全部是 StringLiteral,压缩工具可以对其进行自动合并的优化。所以,静态字符串建议使用 + 拼接。
  2. 在现代浏览器下,使用 + 拼接字符串,性能较数组的方式要高。
  3. 如需要兼顾老旧浏览器,应尽量使用数组拼接字符串。

示例:

// 使用数组拼接字符串
var str = [
    // 推荐换行开始并缩进开始第一个字符串, 对齐代码, 方便阅读.
    '<ul>',
        '<li>第一项</li>',
        '<li>第二项</li>',
    '</ul>'
].join('');

// 使用 `+` 拼接字符串
var str2 = '' // 建议第一个为空字符串, 第二个换行开始并缩进开始, 对齐代码, 方便阅读
    + '<ul>',
    +    '<li>第一项</li>',
    +    '<li>第二项</li>',
    + '</ul>';
[建议] 使用字符串拼接的方式生成HTML,需要根据语境进行合理的转义。

解释:

JavaScript 中拼接,并且最终将输出到页面中的字符串,需要进行合理转义,以防止安全漏洞。下面的示例代码为场景说明,不能直接运行。

示例:

// HTML 转义
var str = '<p>' + htmlEncode(content) + '</p>';

// HTML 转义
var str = '<input type="text" value="' + htmlEncode(value) + '">';

// URL 转义
var str = '<a href="/?key=' + htmlEncode(urlEncode(value)) + '">link</a>';

// JavaScript字符串 转义 + HTML 转义
var str = '<button onclick="check(\'' + htmlEncode(strLiteral(name)) + '\')">提交</button>';

3.6 对象

[强制] 使用对象字面量 {} 创建新 Object

示例:

// good
var obj = {};

// bad
var obj = new Object();
[建议] 对象创建时,如果一个对象的所有 属性 均可以不添加引号,建议所有 属性 不添加引号。

示例:

var info = {
    name: 'someone',
    age: 28
};
[建议] 对象创建时,如果任何一个 属性 需要添加引号,则所有 属性 建议添加 '

解释:

如果属性不符合 Identifier 和 NumberLiteral 的形式,就需要以 StringLiteral 的形式提供。

示例:

// good
var info = {
    'name': 'someone',
    'age': 28,
    'more-info': '...'
};

// bad
var info = {
    name: 'someone',
    age: 28,
    'more-info': '...'
};
[强制] 不允许修改和扩展任何原生对象和宿主对象的原型。

示例:

// 以下行为绝对禁止
String.prototype.trim = function () {
};
[建议] 属性访问时,尽量使用 .

解释:

属性名符合 Identifier 的要求,就可以通过 . 来访问,否则就只能通过 [expr] 方式访问。

通常在 JavaScript 中声明的对象,属性命名是使用 Camel 命名法,用 . 来访问更清晰简洁。部分特殊的属性(比如来自后端的 JSON ),可能采用不寻常的命名方式,可以通过 [expr] 方式访问。

示例:

info.age;
info['more-info'];
[建议] for in 遍历对象时, 使用 hasOwnProperty 过滤掉原型中的属性。

示例:

var newInfo = {};
for (var key in info) {
    if (info.hasOwnProperty(key)) {
        newInfo[key] = info[key];
    }
}

3.7 数组

[强制] 使用数组字面量 [] 创建新数组,除非想要创建的是指定长度的数组。

示例:

// good
var arr = [];

// bad
var arr = new Array();
[强制] 遍历数组不使用 for in

解释:

数组对象可能存在数字以外的属性, 这种情况下 for in 不会得到正确结果。

示例:

var arr = ['a', 'b', 'c'];

// 这里仅作演示, 实际中应使用 Object 类型
arr.other = 'other things';

// 正确的遍历方式
for (var i = 0, len = arr.length; i < len; i++) {
    console.log(i);
}

// 错误的遍历方式
for (var i in arr) {
    console.log(i);
}
[建议] 不因为性能的原因自己实现数组排序功能,尽量使用数组的 sort 方法。

解释:

自己实现的常规排序算法,在性能上并不优于数组默认的 sort 方法。以下两种场景可以自己实现排序:

  1. 需要稳定的排序算法,达到严格一致的排序结果。
  2. 数据特点鲜明,适合使用桶排。
[建议] 清空数组使用 .length = 0

3.8 函数

3.8.1 函数长度

[建议] 一个函数的长度控制在 50 行以内。

解释:

将过多的逻辑单元混在一个大函数中,易导致难以维护。一个清晰易懂的函数应该完成单一的逻辑单元。复杂的操作应进一步抽取,通过函数的调用来体现流程。

特定算法等不可分割的逻辑允许例外。

示例:

function syncViewStateOnUserAction() {
    if (x.checked) {
        y.checked = true;
        z.value = '';
    }
    else {
        y.checked = false;
    }

    if (a.value) {
        warning.innerText = '';
        submitButton.disabled = false;
    }
    else {
        warning.innerText = 'Please enter it';
        submitButton.disabled = true;
    }
}

// 直接阅读该函数会难以明确其主线逻辑,因此下方是一种更合理的表达方式:

function syncViewStateOnUserAction() {
    syncXStateToView();
    checkAAvailability();
}

function syncXStateToView() {
    y.checked = x.checked;

    if (x.checked) {
        z.value = '';
    }
}

function checkAAvailability() {
    if (a.value) {
        clearWarnignForA();
    }
    else {
        displayWarningForAMissing();
    }
}

3.8.2 参数设计

[建议] 一个函数的参数控制在 6 个以内。

解释:

除去不定长参数以外,函数具备不同逻辑意义的参数建议控制在 6 个以内,过多参数会导致维护难度增大。

某些情况下,如使用 AMD Loader 的 require 加载多个模块时,其 callback 可能会存在较多参数,因此对函数参数的个数不做强制限制。

[建议] 通过 options 参数传递非数据输入型参数。

解释:

有些函数的参数并不是作为算法的输入,而是对算法的某些分支条件判断之用,此类参数建议通过一个 options 参数传递。

如下函数:

/**
 * 移除某个元素
 *
 * @param {Node} element 需要移除的元素
 * @param {boolean} removeEventListeners 是否同时将所有注册在元素上的事件移除
 */
function removeElement(element, removeEventListeners) {
    element.parent.removeChild(element);

    if (removeEventListeners) {
        element.clearEventListeners();
    }
}

可以转换为下面的签名:

/**
 * 移除某个元素
 *
 * @param {Node} element 需要移除的元素
 * @param {Object} options 相关的逻辑配置
 * @param {boolean} options.removeEventListeners 是否同时将所有注册在元素上的事件移除
 */
function removeElement(element, options) {
    element.parent.removeChild(element);

    if (options.removeEventListeners) {
        element.clearEventListeners();
    }
}

这种模式有几个显著的优势:

  • boolean 型的配置项具备名称,从调用的代码上更易理解其表达的逻辑意义。
  • 当配置项有增长时,无需无休止地增加参数个数,不会出现 removeElement(element, true, false, false, 3) 这样难以理解的调用代码。
  • 当部分配置参数可选时,多个参数的形式非常难处理重载逻辑,而使用一个 options 对象只需判断属性是否存在,实现得以简化。

四、 浏览器环境

4.1 DOM

4.1.1 元素获取

[建议] 对于单个元素,尽可能使用 document.getElementById 获取,避免使用document.all
[建议] 对于多个元素的集合,尽可能使用 context.getElementsByTagName 获取。其中 context 可以为 document 或其他元素。指定 tagName 参数为 * 可以获得所有子元素。
[建议] 遍历元素集合时,尽量缓存集合长度。如需多次操作同一集合,则应将集合转为数组。

解释:

原生获取元素集合的结果并不直接引用 DOM 元素,而是对索引进行读取,所以 DOM 结构的改变会实时反映到结果中。

示例:

<div></div>
<span></span>

<script>
var elements = document.getElementsByTagName('*');

// 显示为 DIV
alert(elements[0].tagName);

var div = elements[0];
var p = document.createElement('p');
docpment.body.insertBefore(p, div);

// 显示为 P
alert(elements[0].tagName);
</script>
[建议] 获取元素的直接子元素时使用 children。避免使用childNodes,除非预期是需要包含文本、注释和属性类型的节点。

4.1.2 样式获取

[建议] 获取元素实际样式信息时,应使用 getComputedStylecurrentStyle

解释:

通过 style 只能获得内联定义或通过 JavaScript 直接设置的样式。通过 CSS class 设置的元素样式无法直接通过 style 获取。

4.1.3 样式设置

[建议] 尽可能通过为元素添加预定义的 className 来改变元素样式,避免直接操作 style 设置。
[强制] 通过 style 对象设置元素样式时,对于带单位非 0 值的属性,不允许省略单位。

解释:

除了 IE,标准浏览器会忽略不规范的属性值,导致兼容性问题。

4.1.4 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 操作也是非常耗时的一种操作,减少 DOM 操作有助于提高性能。

4.1.5 DOM 事件

[建议] 优先使用 addEventListener / attachEvent 绑定事件,避免直接在 HTML 属性中或 DOM 的 expando 属性绑定事件处理。

解释:

expando 属性绑定事件容易导致互相覆盖。

[建议] 使用 addEventListener 时第三个参数使用 false

解释:

标准浏览器中的 addEventListener 可以通过第三个参数指定两种时间触发模型:冒泡和捕获。而 IE 的 attachEvent 仅支持冒泡的事件触发。所以为了保持一致性,通常 addEventListener 的第三个参数都为 false。

[建议] 在没有事件自动管理的框架支持下,应持有监听器函数的引用,在适当时候(元素释放、页面卸载等)移除添加的监听器。

【VScode】前端开发环境配置

Tip: 本配置文档是假设你用的是mac前提,如果你用的是window系统,可能配置上会有区别,那么请自行研究,欢迎贡献完善本文档!

写在前面:
本文档只是从介绍 开发工具配置 上来统一代码风格和代码检测,目的是希望方便日后每个前端的小伙伴加入后参照该文档进行本地开发环境配置。而具体编码风格, 例如:
(1)、每行代码结束必须要有分号;(有没有是风格问题,我们希望这里能够统一)
(2)、使用 2空格(javascript使用2个空格,css使用4空格)缩进;
我们会在另外一个文档来对前端编码规范做详细说明。

开发工具配置

本文档 将对你的开发工具配置给出建议,目的是为了统一团队内的代码风格。
我们通过 Eslint、Prettier、Csscomb 三个插件配置来达到目的。

  • Eslint 执行的是代码检测 与 格式化;
  • Prettier 很单纯的孩子,只负责做代码的格式化工作;
  • Csscomb: 我们使用它执行css、sass、less文件的格式化,这里包括样式声明顺序(目的是保证团队内样式风格的统一和易读性);

javascript:

  • 每行代码结束必须要有分号;(有没有是风格问题,我们希望这里能够统一)
  • 适用 2空格(javascript两个空格,css是使用4空格)缩进;

Prettier 与 Eslint

两者区别

  • Eslint 是代码质量工具,执行的是代码检测。(确保没有未使用的变量、没有全局变量,等等)
  • Prettier 其实就是简单的代码格式工具。只关心格式化文件(最大长度、混合标签和空格、引用样式等)。

可见,代码格式统一的问题,交给Prettirer再合适不过了。和Eslint配合使用,风味更佳。


安装配置 Prettier

介绍

  • Prettier 是一个规范代码格式的工具。它只能规范格式,并不具备 lint 那种语法检测的能力。
  • 支持目前大多数的编程语言:包括JavaScript · Flow · TypeScript · CSS · SCSS · Less · JSX · Vue · GraphQL · JSON · Markdown,这代表着, 我们几乎可以用一个工具都能搞定所有的代码格式化问题。

安装配置 与 使用

安装

在vscode 中直接搜 prettier,第一个就是,直接安装即可。

安装成功后, Idea 默认的格式化处理就会被prettier代替, 默认快捷键是alt + shift + f

配置

安装成功后, vscode 的设置选项中就会有 prettier 相关的配置节点。

在项目的根目录下,新建一个prettier 的配置文件,名为: .prettierrc, 内容如下:

{
  "tabWidth": 2,
  "singleQuote": true, //使用单引号
  "semi": true, // 句末加分号
  "trailingComma": "es5", //最后一个对象元素加逗号([a,b,c,d,] 数组项d后面的逗号就是尾逗号)。可选项有none/es5/all
  "printWidth": 140, // 换行字符串阈值
  "arrowParens": "avoid", // (x) => {} 是否要有小括号
  "bracketSpacing": true, //对象,数组加空格
  "overrides": [
    {
      "files": ".prettierrc",
      "options": { "parser": "json" }
    }
  ],
  "proseWrap": "preserve" // 是否要换行
}

之后,去设置文件下,添加或修改 "editor.formatOnSave": true, 意思是每次保存文件时执行格式话。



beautiful 插件 (现在已经不建议使用了!)

为什么用 beautiful 插件呢?因为我发现 prettier 对单独的 sass 文件没有格式化。。尼玛 奇怪了。所以,就引入 beautiful 这个插件,但是考虑到它格式化与prettier的格式化之间存在冲突覆盖,所以我们只用它来单独格式化特定的某几个文件 —— 如 css\sass\html 等(对的,这里限制来n beautiful 这个插件格式化的范围,目的是为了避免和 prettier 产生冲突);

在设置中添加下面代码:

}
    ...
    "beautify.language": {
       "html": ["html", "htm"],
       "css": ["css", "scss"]
   }
   ...
}

Csscomb: 规范样式代码格式

安装 Csscomb。完了之后在用户设置下面添加如下代码:

    ....
    "csscomb.formatOnSave": true,
    "csscomb.preset": {}
    ....

"csscomb.preset": {} 这部分可以分两部分看,分别是排序规则——sort-order,和其他自定义规则。

** 其他规则: **

 "csscomb.preset": {
      "exclude": [
          ".git/**",
          "node_modules/**",
          "bower_components/**"
      ],
      "always-semicolon": true, //一直使用分号
      "block-indent": "    ", //缩进
      "color-case": "lower", //颜色值小写
      "color-shorthand": true,
      "element-case": "lower", //元素名小写
      "eof-newline": true,
      "leading-zero": false,
      "lines-between-rulesets": 1,  //不同分类的规则之间 加一行进行 分隔
      "quotes": "single", //使用单引号
      "remove-empty-rulesets": true, //自动删除空规则
      "space-after-colon": " ", // ':' 后两空格
      "space-after-combinator": " ",
      "space-after-opening-brace": "\n",
      "space-after-selector-delimiter": "\n",
      "space-before-closing-brace": "\n",
      "space-before-colon": "",
      "space-before-combinator": " ",
      "space-before-opening-brace": " ", // “{” 前使用一个空格
      "space-before-selector-delimiter": "",
      "space-between-declarations": "\n", // 每行只显示一条样式规则
      "strip-spaces": true,
      "unitless-zero": true,
      "vendor-prefix-align": true,
      "sort-order": [

第二部分: 排序规则以及呈现样式

有三种 排序规则 可选,可以在 https://github.com/csscomb/csscomb.js/tree/master/config 找到,选择一种自己喜欢的即可。

补充 - VsCode 插件设置

打开vscode工具的设置(快捷键 Ctrl + ,)里面有两个设置。

  • USER SETTINGS(用户设置): 也就是全局配置,其他项目也会应用这个配置。
  • WORKSPACE SETTINGS(工作区设置): 也就是项目配置,会在当前项目的根路径里创建一个.vscode/settings.json文件,然后配置只在当前项目生效。

ESLint 和 Prettier 的冲突修复

由于需要同时使用prettier和eslint,而prettier的一些规则和eslint的一些规则可能存在冲突,例如prettier字符串默认是用双引号而esLint定义的是单引号的话这样格式化之后就不符合ESLint规则了。

所以要解决冲突就需要在Prettier的规则配置里也配置上和ESLint一样的规则,直接覆盖掉,ESLint和Prettier的配置文件内容如下:

.eslintrc.js
配置使用单引号、结尾不能有分号。

module.exports = {
  root: true,
  env: {
    node: true
  },
  extends: ['plugin:vue/essential', 'eslint:recommended'],
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    //强制使用单引号
    quotes: ['error', 'single'],
    //强制不使用分号结尾
    semi: ['error', 'never']
  },
  parserOptions: {
    parser: 'babel-eslint'
  }
}

.prettierrc

配置使用单引号、结尾不能有分号。

{
   //开启 eslint 支持
  "eslintIntegration": true,
  //使用单引号
  "singleQuote": true,
  //结尾不加分号
  "semi": false
}

也可以直接在vscode工作区配置prettier:

{
    //开启 eslint 支持
    "prettier.eslintIntegration": true,
    //使用单引号
    "prettier.singleQuote": true,
    //结尾不加分号
    "prettier.semi": false,
}

Input 获取焦点,隐藏 placeholder 里面的值

不能!

因为,不同内核浏览器上实现不一致,多数是获取焦点时并不会消失,当输入框中输入了字符之后就会显示。。感觉默认的属于主流逻辑。所以,觉得在这个问题上花时间琢磨不值当 也没必要!

hashHistory Vs browserHistory 的区别!

HashHistory 和 BrowserHistory 模式区别

  • hashHistory: 不需要服务器配置,在 URL 生成一个 hash 来跟踪状态,通常在测试环境使用,也可以作为发布环境使用。如果设为 hashHistory,路由将通过 URLhash 部分(#)切换,URL 的形式类似 example.com/#/some/path
  • browserHistory: 需要服务器端做配置,路径是真实的 URL,是 react-router/vue 官方推荐首选。如果设为 browserHistory,浏览器的路由就不再通过 Hash 完成了,而显示正常的路径 example.com/some/path,背后调用的是浏览器的 History API

大多数情况下,browserHistory 模式明显是优于 hashHistory 模式的,但 browserHistory 模式 需要在服务器上进行一定的配置,否则用户直接向服务器请求某个子路由,会显示网页找不到的 404 错误。

browserHistory 模式为什么需要配置服务器?

browserHistory 模式下,URL 是指向真实 URL 的资源路径,当通过真实 URL 访问网站的时候(首页),这个时候可以正常加载我们的网站资源,而用户在非首页下手动刷新网页时,由于路径是指向服务器的真实路径,但该路径下并没有相关资源,用户访问的资源不存在,返回给用户的是 404 错误

browserHistory 模式如何配置服务器?

如果开发服务器使用的是 webpack-dev-server,加上 --history-api-fallback 参数就可以了。

$ webpack-dev-server --inline --content-base . --history-api-fallback

当服务器为 nginx 时,\*.conf 配置如下:

 server{
          listen 8080;  # 端口
          server_name localhost;   # 绑定域名
          location ~ .*?\.(js|css|jpg|png|jpeg|less|sass)   # 规则
          {
              root /document/mine/blog;  # web目录
              expires 3d;  # 文件缓存时间
              rewrite .*?([^\/\\\]*?\.(js|css|jpg|png|jpeg|less|sass)) /build/$1 break
              # rewrite:指令; .*?([^\/\\])*?\.(js|css|jpg|png|jpeg|less|sass):匹配文件的正则;
              # /build/$1:($1正则匹配分组1内容,即文件名)重定向的文件路径
           }
           location / {
              root /document/mine/blog;
              try_files $uri /index.html;
              # try_files:检查文件; $uri:监测的文件路径; /index.html:文件路径重定向的新路径
              index index.html index.htm index.php;
           }
}

注意:nginx 只匹配 / ,剩下的应该由 react-router 来做。

针对于其他服务器配置,原理都是一样的,即把路由都指向 index.html,静态资源指向真实的文件夹

使用 hashHistory 模式时,像这样 ?_k=ckuvup 没用的在 URL 中是什么?

使用 hashHistory 模式时,打开链接后,会自动生成一个参数 “?\_k=kegot3”,并且每次点击该参数的值都会变化,如:http://ms.tms.codoon.com/performance/index.html#/?_k=kegot3。像这样 ?\_k=ckuvup 没用的在 URL 中是什么?解释如下:

当一个 history 通过应用程序的 pushStatereplaceState 跳转时,它可以在新的 location 中存储 “location state” 而不显示在 URL 中,这就像是在一个 HTMLpost 的表单数据。在 DOM API 中,这些 hash history 通过 window.location.hash = newHash 很简单地被用于跳转,且不用存储它们的 location state。但我们想全部的 history 都能够使用 location state,因此我们要为每一个 location 创建一个唯一的 key,并把它们的状态存储在 session storage 中。当访客点击“后退”和“前进”时,我们就会有一个机制去恢复这些 location state

参考

Google Tag Manager (Google 跟踪代码管理器)

一、快速入门指南

Google跟踪代码管理 器容器代码段是您粘贴到网页中的一小段JavaScript和非JavaScript代码。
它使标记管理器可以通过将gtm.js插入页面来触发标记(或者在JavaScript不可用时使用iframe)。

要在您的网站上实施Google跟踪代码管理器:

  1. 复制以下JavaScript并将其粘贴到您网站的每个页面上尽可能靠近开头标记,将GTM-XXXX替换为您的容器ID:
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXX');</script>
<!-- End Google Tag Manager -->
  1. 复制以下代码段并在网站的每个页面上的开始标记后立即将其粘贴,将GTM-XXXX替换为您的容器ID:
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

只需执行基本代码安装即可实现 许多跟踪代码管理操作,但如果您希望对 跟踪事件 或 数据 进行更精细的控制,则可能需要使用我们的异步方法进行一些自定义。

注意:Google跟踪代码管理器代码段必须直接放在您要跟踪的页面中。
将其放在隐藏的iframe中或在另一个标记管理系统中部署它将阻止某些标记准确跟踪父页面。

有关如何将当前现场标记配置迁移到GTM的更多信息,我们还有以下文章:

要进一步自定义安装,请查看以下其他资源:

  • 添加事件和变量 - 了解如何使用Google跟踪代码管理器收集动态数据和跟踪事件。
  • 多个域 - 了解跨多个域实施Google跟踪代码管理器的最佳做法。
  • 重命名数据层 - 在某些情况下,您可能希望更改数据层的名称。
  • 安全性 - 了解Google跟踪代码管理器的其他功能,这些功能可以帮助网站所有者解决高级安全问题。

您还可以阅读Google跟踪代码管理器 故障排除最佳做法

二、开发者指南

本文档介绍如何在您的网站上使用Google代码管理器的。

使用数据层

将数据层变量添加到页面

将数据层与HTML事件处理程序一起使用

一推,多变量

异步语法的工作原理

将标记迁移到谷歌标记管理器

多域名

一个页面上有多个容器

Flash / Actionscript

为不支持JavaScript的设备添加数据层变量

安全

限制标签(跟踪代码)部署

使用协议相关URL



三、增强型电子商务(UA)



四、故障排除

使用 javascript 实现”添加到主屏幕“ 功能

参考阅读:

背景:

目标:

webApp可以在iphone、andorid机型上实现 ”添加到主屏幕“ 功能,从而达到推广、及留住用户的设想;


实现方案:

本身 apple 是不支持(允许)开发者通过 脚本 执行这种操作的,只能通过界面才可以;

第三方解决方案

add-to-homescreen

https://github.com/cubiq/add-to-homescreen


Mobile Bookmark Bubble

https://github.com/h5bp/mobile-boilerplate/wiki/Mobile-Bookmark-Bubble

Mobile Bookmark Bubble是一个JavaScript库,可在您的移动Web应用程序底部添加促销泡泡,邀请用户将应用程序添加到其设备的主屏幕。

该库使用HTML5本地存储来跟踪是否已经显示促销,以避免不断唠叨用户。

有两个新版本的实现,一个仅支持Mobile Safari,另一个支持Mobile Safari,Android,Blackberry触控智能手机和Playbook。

  • 仅适用于Mobile Safari:https://github.com/cubiq/add-to-homescreen
  • Mobile Safari +其他:https://github.com/okamototk/jqm-mobile-bookmark-bubble

这两个版本基于Google Code上的原始存储库。

前端代码规范 —— CSS篇

前端代码规范 —— CSS篇

一、 前言

二、 代码风格

  2.1 文件

  2.2 缩进

  2.3 空格

  2.4 行长度

  2.5 选择器

  2.6 属性

三、 通用

  3.1 选择器

  3.2 属性缩写

  3.3 属性书写顺序

  3.4 清除浮动

  3.5 !important

  3.6 z-index

四、 值与单位

  4.1 文本

  4.2 数值

  4.3 url()

  4.4 长度

  4.5 颜色

  4.6 2D 位置

五、 文本编排

  5.1 字体族

  5.2 字号

  5.3 字体风格

  5.4 字重

  5.5 行高

六、 变换与动画

七、 响应式

八、命名

  8.1 Css文件命名

  8.2 ClassName命名

一、 前言

CSS 作为网页样式的描述语言,在百度一直有着广泛的应用。本文档的目标是使 CSS 代码风格保持一致,容易被理解和被维护。

虽然本文档是针对 CSS 设计的,但是在使用各种 CSS 的预编译器(如 less、sass、stylus 等)时,适用的部分也应尽量遵循本文档的约定。

二、 代码风格

2.1 文件

[建议] CSS 文件使用无 BOMUTF-8 编码。

解释:

UTF-8 编码具有更广泛的适应性。BOM 在使用程序或工具处理文件时可能造成不必要的干扰。

2.2 缩进

[强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格 或 tab 字符。

示例:

.selector {
  margin: 0;
  padding: 0;
}

2.3 空格

[强制] 选择器{ 之间必须包含空格。

示例:

.selector {
}

[强制] 属性名 与之后的 : 之间不允许包含空格, :属性值 之间必须包含空格。

示例:

margin: 0;

[强制] 列表型属性值 书写在单行时,, 后必须跟一个空格。

示例:

font-family: Arial, sans-serif;

2.4 行长度

[强制] 每行不得超过 120 个字符,除非单行不可分割。

解释:

常见不可分割的场景为 URL 超长。

[建议] 对于超长的样式,在样式值的 空格 处或 , 后换行,建议按逻辑分组。

示例:

/* 不同属性值按逻辑分组 */
background: transparent url(aVeryVeryVeryLongUrlIsPlacedHere) no-repeat 0 0;

/* 可重复多次的属性,每次重复一行 */
background-image: url(aVeryVeryVeryLongUrlIsPlacedHere) url(anotherVeryVeryVeryLongUrlIsPlacedHere);

/* 类似函数的属性值可以根据函数调用的缩进进行 */
background-image: -webkit-gradient(
  linear,
  left bottom,
  left top,
  color-stop(0.04, rgb(88, 94, 124)),
  color-stop(0.52, rgb(115, 123, 162))
);

2.5 选择器

[强制] 当一个 rule 包含多个 selector 时,每个选择器声明必须独占一行。

示例:

/* good */
.post,
.page,
.comment {
  line-height: 1.5;
}

/* bad */
.post,
.page,
.comment {
  line-height: 1.5;
}

[强制] >+~ 选择器的两边各保留一个空格。

示例:

/* good */
main > nav {
  padding: 10px;
}

label + input {
  margin-left: 5px;
}

input:checked ~ button {
  background-color: #69c;
}

/* bad */
main > nav {
  padding: 10px;
}

label + input {
  margin-left: 5px;
}

input:checked ~ button {
  background-color: #69c;
}

[强制] 属性选择器中的值必须用双引号包围。

解释:

不允许使用单引号,不允许不使用引号。

示例:

/* good */
article[character="juliet"] {
  voice-family: "Vivien Leigh", victoria, female;
}

/* bad */
article[character="juliet"] {
  voice-family: "Vivien Leigh", victoria, female;
}

2.6 属性

[强制] 属性定义必须另起一行。

示例:

/* good */
.selector {
  margin: 0;
  padding: 0;
}

/* bad */
.selector {
  margin: 0;
  padding: 0;
}

[强制] 属性定义后必须以分号结尾。

示例:

/* good */
.selector {
  margin: 0;
}

/* bad */
.selector {
  margin: 0;
}

三、通用

3.1 选择器

[强制] 如无必要,不得为 idclass 选择器添加类型选择器进行限定。

解释:

在性能和维护性上,都有一定的影响。

示例:

/* good */
#error,
.danger-message {
  font-color: #c00;
}

/* bad */
dialog#error,
p.danger-message {
  font-color: #c00;
}

[建议] 选择器的嵌套层级应不大于 4 级,位置靠后的限定条件应尽可能精确。

示例:

/* good */
#username input {
}
.comment .avatar {
}

/* bad */
.page .header .login #username input {
}
.comment div * {
}

3.2 属性缩写

[建议] 在可以使用缩写的情况下,尽量使用属性缩写。

示例:

/* good */
.post {
  font: 12px/1.5 arial, sans-serif;
}

/* bad */
.post {
  font-family: arial, sans-serif;
  font-size: 12px;
  line-height: 1.5;
}

[建议] 使用 border / margin / padding 等缩写时,应注意隐含值对实际数值的影响,确实需要设置多个方向的值时才使用缩写。

解释:

border / margin / padding 等缩写会同时设置多个属性的值,容易覆盖不需要覆盖的设定。如某些方向需要继承其他声明的值,则应该分开设置。

示例:

/* centering <article class="page"> horizontally and highlight featured ones */
article {
  margin: 5px;
  border: 1px solid #999;
}

/* good */
.page {
  margin-right: auto;
  margin-left: auto;
}

.featured {
  border-color: #69c;
}

/* bad */
.page {
  margin: 5px auto; /* introducing redundancy */
}

.featured {
  border: 1px solid #69c; /* introducing redundancy */
}

3.3 属性书写顺序

[建议] 同一 rule set 下的属性在书写时,应按功能进行分组,并以 Formatting Model(布局方式、位置) > Box Model(尺寸) > Typographic(文本相关) > Visual(视觉效果) 的顺序书写,以提高代码的可读性。

解释:

  • Formatting Model 相关属性包括:position / top / right / bottom / left / float / display / overflow
  • Box Model 相关属性包括:border / margin / padding / width / height
  • Typographic 相关属性包括:font / line-height / text-align / word-wrap
  • Visual 相关属性包括:background / color / transition / list-style

另外,如果包含 content 属性,应放在最前面。

示例:

.sidebar {
  /* formatting model: positioning schemes / offsets / z-indexes / display / ...  */
  position: absolute;
  top: 50px;
  left: 0;
  overflow-x: hidden;

  /* box model: sizes / margins / paddings / borders / ...  */
  width: 200px;
  padding: 5px;
  border: 1px solid #ddd;

  /* typographic: font / aligns / text styles / ... */
  font-size: 14px;
  line-height: 20px;

  /* visual: colors / shadows / gradients / ... */
  background: #f5f5f5;
  color: #333;
  -webkit-transition: color 1s;
  -moz-transition: color 1s;
  transition: color 1s;
}

3.4 清除浮动

[建议] 当元素需要撑起高度以包含内部的浮动元素时,通过对伪类设置 clear 或触发 BFC 的方式进行 clearfix。尽量不使用增加空标签的方式。

解释:

触发 BFC 的方式很多,常见的有:

  • float 非 none
  • position 非 static
  • overflow 非 visible

如希望使用更小副作用的清除浮动方法,参见 A new micro clearfix hack 一文。

另需注意,对已经触发 BFC 的元素不需要再进行 clearfix。

3.5 !important

[建议] 尽量不使用 !important 声明。

[建议] 当需要强制指定样式且不允许任何场景覆盖时,通过标签内联和 !important 定义样式。

解释:

必须注意的是,仅在设计上 确实不允许任何其它场景覆盖样式 时,才使用内联的 !important 样式。通常在第三方环境的应用中使用这种方案。下面的 z-index 章节是其中一个特殊场景的典型样例。

3.6 z-index

[建议] 将 z-index 进行分层,对文档流外绝对定位元素的视觉层级关系进行管理。

解释:

同层的多个元素,如多个由用户输入触发的 Dialog,在该层级内使用相同的 z-index 或递增 z-index

建议每层包含 100 个 z-index 来容纳足够的元素,如果每层元素较多,可以调整这个数值。

[建议] 在可控环境下,期望显示在最上层的元素,z-index 指定为 999999

解释:

可控环境分成两种,一种是自身产品线环境;还有一种是可能会被其他产品线引用,但是不会被外部第三方的产品引用。

不建议取值为 2147483647。以便于自身产品线被其他产品线引用时,当遇到层级覆盖冲突的情况,留出向上调整的空间。

[建议] 在第三方环境下,期望显示在最上层的元素,通过标签内联和 !important,将 z-index 指定为 2147483647

解释:

第三方环境对于开发者来说完全不可控。在第三方环境下的元素,为了保证元素不被其页面其他样式定义覆盖,需要采用此做法。

四、 值与单位

4.1 文本

[强制] 文本内容必须用双引号包围。

解释:

文本类型的内容可能在选择器、属性值等内容中。

示例:

/* good */
html[lang|="zh"] q:before {
  font-family: "Microsoft YaHei", sans-serif;
  content: "“";
}

html[lang|="zh"] q:after {
  font-family: "Microsoft YaHei", sans-serif;
  content: "”";
}

/* bad */
html[lang|="zh"] q:before {
  font-family: "Microsoft YaHei", sans-serif;
  content: "“";
}

html[lang|="zh"] q:after {
  font-family: "Microsoft YaHei", sans-serif;
  content: "”";
}

4.2 数值

[强制] 当数值为 0 - 1 之间的小数时,省略整数部分的 0

示例:

/* good */
panel {
  opacity: 0.8;
}

/* bad */
panel {
  opacity: 0.8;
}

4.3 url()

[强制] url() 函数中的路径不加引号。

示例:

body {
  background: url(bg.png);
}

[建议] url() 函数中的绝对路径可省去协议名。

示例:

body {
  background: url(//baidu.com/img/bg.png) no-repeat 0 0;
}

4.4 长度

[强制] 长度为 0 时须省略单位。 (也只有长度单位可省)

示例:

/* good */
body {
  padding: 0 5px;
}

/* bad */
body {
  padding: 0px 5px;
}

4.5 颜色

[强制] RGB 颜色值必须使用十六进制记号形式 #rrggbb。不允许使用 rgb()

解释:

带有 alpha 的颜色信息可以使用 rgba()。使用 rgba() 时每个逗号后必须保留一个空格。

注意:很多时候设计给到前端的设计稿中颜色使用的就是 rgb 格式,如 rgb(47, 47, 47), 此时我们建议改成 rgba 格式,如 rgba(47, 47, 47, 1);

示例:

/* good */
.success {
  box-shadow: 0 0 2px rgba(0, 128, 0, 0.3);
  border-color: #008000;
}

/* bad */
.success {
  box-shadow: 0 0 2px rgba(0, 128, 0, 0.3);
  border-color: rgb(0, 128, 0);
}

[强制] 颜色值可以缩写时,必须使用缩写形式。

示例:

/* good */
.success {
  background-color: #aca;
}

/* bad */
.success {
  background-color: #aaccaa;
}

[强制] 颜色值不允许使用命名色值。

示例:

/* good */
.success {
  color: #90ee90;
}

/* bad */
.success {
  color: lightgreen;
}

[建议] 颜色值中的英文字符采用小写。如不用小写也需要保证同一项目内保持大小写一致。

示例:

/* good */
.success {
  background-color: #aca;
  color: #90ee90;
}

/* good */
.success {
  background-color: #aca;
  color: #90ee90;
}

/* bad */
.success {
  background-color: #aca;
  color: #90ee90;
}

4.6 2D 位置

[强制] 必须同时给出水平和垂直方向的位置。

解释:

2D 位置初始值为 0% 0%,但在只有一个方向的值时,另一个方向的值会被解析为 center。为避免理解上的困扰,应同时给出两个方向的值。background-position 属性值的定义

示例:

/* good */
body {
  background-position: center top; /* 50% 0% */
}

/* bad */
body {
  background-position: top; /* 50% 0% */
}

五、 文本编排

5.1 字体族

[强制] font-family 属性中的字体族名称应使用字体的英文 Family Name,其中如有空格,须放置在引号中。

解释:

所谓英文 Family Name,为字体文件的一个元数据,常见名称如下:

字体 操作系统 Family Name
宋体 (中易宋体) Windows SimSun
黑体 (中易黑体) Windows SimHei
微软雅黑 Windows Microsoft YaHei
微软正黑 Windows Microsoft JhengHei
华文黑体 Mac/iOS STHeiti
冬青黑体 Mac/iOS Hiragino Sans GB
文泉驿正黑 Linux WenQuanYi Zen Hei
文泉驿微米黑 Linux WenQuanYi Micro Hei

示例:

h1 {
  font-family: "Microsoft YaHei";
}

[强制] font-family 按「西文字体在前、中文字体在后」、「效果佳 (质量高/更能满足需求) 的字体在前、效果一般的字体在后」的顺序编写,最后必须指定一个通用字体族( serif / sans-serif )。

解释:

更详细说明可参考本文

示例:

/* Display according to platform */
.article {
  font-family: Arial, sans-serif;
}

/* Specific for most platforms */
h1 {
  font-family: "Helvetica Neue", Arial, "Hiragino Sans GB", "WenQuanYi Micro Hei", "Microsoft YaHei", sans-serif;
}

[强制] font-family 不区分大小写,但在同一个项目中,同样的 Family Name 大小写必须统一。

示例:

/* good */
body {
  font-family: Arial, sans-serif;
}

h1 {
  font-family: Arial, "Microsoft YaHei", sans-serif;
}

/* bad */
body {
  font-family: arial, sans-serif;
}

h1 {
  font-family: Arial, "Microsoft YaHei", sans-serif;
}

5.2 字号

[强制] 需要在 Windows 平台显示的中文内容,其字号应不小于 12px

解释:

由于 Windows 的字体渲染机制,小于 12px 的文字显示效果极差、难以辨认。

5.3 字体风格

[建议] 需要在 Windows 平台显示的中文内容,不要使用除 normal 外的 font-style。其他平台也应慎用。

解释:

由于中文字体没有 italic 风格的实现,所有浏览器下都会 fallback 到 obilique 实现 (自动拟合为斜体),小字号下 (特别是 Windows 下会在小字号下使用点阵字体的情况下) 显示效果差,造成阅读困难。

5.4 字重

[强制] font-weight 属性必须使用数值方式描述。

解释:

CSS 的字重分 100 – 900 共九档,但目前受字体本身质量和浏览器的限制,实际上支持 400700 两档,分别等价于关键词 normalbold

浏览器本身使用一系列启发式规则来进行匹配,在 <700 时一般匹配字体的 Regular 字重,>=700 时匹配 Bold 字重。

但已有浏览器开始支持 =600 时匹配 Semibold 字重 (见此表),故使用数值描述增加了灵活性,也更简短。

示例:

/* good */
h1 {
  font-weight: 700;
}

/* bad */
h1 {
  font-weight: bold;
}

5.5 行高

[建议] line-height 在定义文本段落时,应使用数值。

解释:

line-height 设置为数值,浏览器会基于当前元素设置的 font-size 进行再次计算。在不同字号的文本段落组合中,能达到较为舒适的行间间隔效果,避免在每个设置了 font-size 都需要设置 line-height

line-height 用于控制垂直居中时,还是应该设置成与容器高度一致。

示例:

.container {
  line-height: 1.5;
}

六、 变换与动画

[强制] 使用 transition 时应指定 transition-property

示例:

/* good */
.box {
  transition: color 1s, border-color 1s;
}

/* bad */
.box {
  transition: all 1s;
}

[建议] 尽可能在浏览器能高效实现的属性上添加过渡和动画。

解释:

本文,在可能的情况下应选择这样四种变换:

  • transform: translate(npx, npx);
  • transform: scale(n);
  • transform: rotate(ndeg);
  • opacity: 0..1;

典型的,可以使用 translate 来代替 left 作为动画属性。

示例:

/* good */
.box {
  transition: transform 1s;
}
.box:hover {
  transform: translate(20px); /* move right for 20px */
}

/* bad */
.box {
  left: 0;
  transition: left 1s;
}
.box:hover {
  left: 20px; /* move right for 20px */
}

七、 响应式

[强制] Media Query 不得单独编排,必须与相关的规则一起定义。

示例:

/* Good */
/* header styles */
@media (...) {
  /* header styles */
}

/* main styles */
@media (...) {
  /* main styles */
}

/* footer styles */
@media (...) {
  /* footer styles */
}

/* Bad */
/* header styles */
/* main styles */
/* footer styles */

@media (...) {
  /* header styles */
  /* main styles */
  /* footer styles */
}

[强制] Media Query 如果有多个逗号分隔的条件时,应将每个条件放在单独一行中。

示例:

@media (-webkit-min-device-pixel-ratio: 2),
  /* Webkit-based browsers */ (min--moz-device-pixel-ratio: 2),
  /* Older Firefox browsers (prior to firefox 16) */ (min-resolution: 2dppx),
  /* The standard way */ (min-resolution: 192dpi) {
  /* dppx fallback */
  /* Retina-specific stuff here */
}

[建议] 尽可能给出在高分辨率设备 (Retina) 下效果更佳的样式。

八、命名

8.1 Css 文件命名

  • 确保文件命名总是以字母开头而不是数字
  • 且字母一律小写
  • 以下划线连接且不带其他标点符号

如:

<!-- SASS -->
jdc.scss
jdc_list.scss
jdc_detail.scss

8.2 ClassName 命名

https://guide.aotu.io/docs/name/classname.html

正则表达式

目录


什么是正则表达式

  • Regular Expression 使用单个字符串来描述 匹配一系列符合某个句法规则的字符串。
  • 说简单了,就是按照某种规则去匹配复合条件的字符串。

开始

正则表达式图形化工具

总结

  • \b 单词边界
  • \d 数字
  • + 一个或多个
  • {2} 重复两个
  • {2, 5} 两到五个
  • . 任意字符
  • \ 转义字符
  • [] 或者,例如:[/-]表示/或者-
  • ^ 开始
  • $ 结束

JS RegExp对象

  • JavaScript通过内置对象RegExp支持正则表达式

  • 两种方式实例化RegExp对象:字面量、构造函数。

  • Js replace(正则表达式,替换后的字符传),常备用来替换字符。

字面量法

var str = "He is a boy, This is a dog. Where is she?";
var reg = '/\bis\b/';  //只匹配第一个
str.replace(reg, 'IS');  //He IS a boy, This is a dog. Where is she?


var reg2 = '/\bis\b/g';  //全部匹配
str.replace(reg2, 'IS');  //He IS a boy, This IS a dog. Where IS she?

构造函数写法

var str = "He is a boy, This is a dog. Where is she?";
var reg = new RegExp('/\bis\b/');  //只匹配第一个
str.replace(reg, 'IS');  //He IS a boy, This is a dog. Where is she?


var reg2 = new RegExp('/\bis\b/', 'g');  //全部匹配
str.replace(reg2, 'IS');  //He IS a boy, This IS a dog. Where IS she?

修饰符

  • g: global 全文搜索,不添加,搜索到第一个匹配停止。
  • i: ignore case 忽略大小写,默认大小写敏感。
  • m: mutiple lines 多行搜索。
"He is a boy, This Is a dog. Where is she?".replace(/\bis\b/g, 0);
// "He 0 a boy, This Is a dog. Where 0 she?"

"He is a boy, This Is a dog. Where is she?".replace(/\bis\b/gi, 0);
// "He 0 a boy, This 0 a dog. Where 0 she?"

元字符

正则表达式由两种基本字符类型组成:

  • 原义文本字符: 如“a”, "abc"

  • 元字符: 如:"\b"

  • 元字符 是正则表达式中有特殊含义的非字母字符

  • \t 水平制表符

  • \v 垂直制表符

  • \n 换行符

  • \r 回车符

  • \0 空字符

  • \f 换页符

  • \cX 与X对应的控制字符(Ctry + X)

字符类

一般情况下,正则表达式一个字符对应字符串的一个字符。
但是,某些时候我们需要的是匹配满足一系列某个特征的字符,那么怎么办呢?对,这个时候就是用到字符类的时候了。

  • 元字符[]构建一个简单的类
  • 所谓类,是指符合某些特性的对象,一个泛指,而不是特质某个字符。
  • 表达式[abc]把字符a或者b或者c归为一类,表达式可以匹配这类字符。
'a1b2c3d4'.replace(/[abc]/g, 'X');
// "X1X2X3d4"

字符类取反

  • 使用字符类^ 创建反向类/负向类
  • 反向类的意义是指不属于某类的内容
  • 表达式[^abc]表示不是字符a或者b或者c的内容。
'a1b2c3d4'.replace(/[^abc]/g, 'X');
// "aXbXcXXX"

范围类

  • 我们可以使用[a-z]两个字符,从a到z的任意字符。
  • 这是闭区间,也就是包含a和z。
'a1b2c3d4z5'.replace(/[a-z]/g, 'Q')
// "Q1Q2Q3Q4Q5"

// 同时匹配大小写
'a1b2c3d4z5'.replace(/[a-zA-Z]/g, 'Q')

'2016-01-09'.replace(/[0-9]/g, 'A')
// "AAAA-AA-AA"
'2016-01-09'.replace(/[0-9-]/g, 'A')
// "AAAAAAAAAA"

预定义类

  • 正则表达式提供预定义类 来匹配常见的字符类

预定义类包括以下:

字符 等价类 含义
. [^\r\n] 除了回车符或者换行符之外的所有字符
\d [0-9] 数字字符
\D [^0-9] 非数字字符
\s [\t\n\x0B\f\r] 空白符
\S [^\t\n\x0B\f\r] 非空白符
\w [a-zA-Z_0-9] 单词字符(字母、数字下划线)
\W [^a-zA-Z_0-9] 非单词字符

边界

  • 最终表达式还提供了几个常用的边界匹配字符
字符 含义
^ 以.....开始
$ 以.....结束
\b 单词边界
\B 非单词边界
m 处理多行
'This is a boy'.replace(/is/g, '0');  // "Th0 0 a boy"
'This is a boy'.replace(/\bis\b/g, '0');  // "This 0 a boy"
'This is a boy'.replace(/\Bis\b/g, '0');  // "Th0 is a boy"


'@123@abc@'.replace(/@./g, 0);  // "0230bc@"
'@123@abc@'.replace(/^@./g, 0);  // "023@abc@"
'@123@abc@'.replace(/.@/g, 0);   // "@120ab0"
'@123@abc@'.replace(/.@$/g, 0);  // "@123@ab0"

"@123
@456
@789".replace(/^@\d/g, 'X');
// "X123
// @456
// @789"

"@123
@456
@789".replace(/^@\d/gm, 'X');
// "X123
// X456
// X789"

量词

  • 量词表示任意字符出现的次数。
字符 含义
出现零次或者一次
+ 出现一次或者多次
* 出现零次或者多次(人一次)
{n} 出现n次
{n,m} 出现n到m次(注意,,与数字之间不要有空格)
{n,} 至少出现n次

贪婪模式与非贪婪模式

贪婪模式

  • 正则表达式会尽可能多的匹配,直到匹配结束
'12345678'.replace(/\d{3,6}/g, 'X')  // X78

非贪婪模式

  • 让正则表达式尽可能的少匹配,也就是说一旦成功匹配不在继续尝试。这就是非贪婪模式。
  • 在量词后面加个?
'12345678'.replace(/\d{3,6}?/g, 'X')   // "XX78"

分组

  • 例如:匹配字符Byron连续出现3次的情景。
  • 使用()可以达到分组的功能,使得量词作用于分组。
'a1b2c3d4'.replace(/([a-z]\d){3}/g, 'X');  // "Xd4"

'ByronCasper'.replace(/Byron|Casper/g, 'X');   // "XX"

'ByronsperByrCasper'.replace(/Byr(on|Ca)sper/g, 'X');  // "XX

反向引用

  • $ 引用
  • 引用的是每个分组内的内容
'2018-09-16'.replace(/(\d{4})-(\d{2})-(\d{2})/g, '$1/$2/$3');   // "2018/09/16"

忽略分组

  • 不希望捕获某个分子,只需要在分组内加上“?” 、或":"就可以了。
  • 如: (?:Byron)

前瞻

  • 正则表达式是从文本头部向文本尾部解析的,文本尾部方向,称为”前“
  • 前瞻,就是在正则表达式匹配到规则时,向前检查是否符合断言。后顾/后瞻方向相反。
  • JavaScript不支持后顾。
  • 符合特定断言 称为 肯定/正向 断言。
  • 不符合特定断言 称为 否定/负向 断言。
名称 正则 含义
正向前瞻 exp(?=assert)
负向前瞻 exp(?!assert)
正向后顾 exp(?<=assert) Js 不支持
负向后顾 exp(?<!assert) Js 不支持
'a2*3'.replace(/\w(?=\d)/g, 'X');  // "X2*3"

'a2*34v8'.replace(/\w(?=\d)/g, 'X');   // "X2*X4X8"

'a2*34vv'.replace(/\w(?=\d)/g, 'X');   // "X2*X4vv"

'a2*34vv'.replace(/\w(?!\d)/g, 'X');   // "aX*3XXX"

JS 对象属性

  • global 是否全文搜索,默认值是false
  • ignore case 是否大小写敏感,默认值是false
  • multiline 多行搜索,默认值是false
  • lastIndex 当前匹配到内容的最后一个字符的下一个位置
  • source 正则表达式的文本字符串

test() 和 exec()

正则表达式常用方法

test()

  • 匹配字符串,如果匹配成功就返回真,匹配失败就返回假。
  • 语法: 正则.test(字符串)。
var str='abcdef';
var re=/b/; 

//bc一个整体也在字符串中,弹出true,但是写bd,弹出false,因为字符串中没有bd这么一个整体
console.log( re.test(str) );

search()

  • 匹配字符串,如果匹配成功,就返回匹配成功的位置,如果匹配失败就返回-1
  • 语法: 字符串.search(正则)
var str="Visit W3School!"
str.search(/W3School/);
// 6

var str2 = "Visit W3School!";
str2.search(/w3school/);
// -1

var str3 = "Visit W3School!"
str3.search(/w3school/i);
// 6

match()

  • 匹配字符串,如果匹配成功,就返回匹配成功的数组,如果匹配不成功,就返回null
  • 语法: 字符串.match(正则)
var str = "dgfhfgh254bhku289fgdhdy675";
var reg = /\d/;
var reg1 = /\d/g;

console.log( str.match(reg) );   // ["2"]
console.log( str.match(reg1) );  // ["2", "5", "4", "2", "8", "9", "6", "7", "5"]

replace()

  • 正则去匹配字符串,匹配成功的字符去替换新的字符串
  • 语法: 字符串.replace(正则,新的字符串)
  • 第二个参数,可以使字符串 or 回调函数(回调函数的第一个参数,就是匹配成功的字符)
var str = "aaa";
var re = /a/;

str = str.replace(re,"b");
alert(str);  // 输出baa

H5 Input 唤起不同类型软键盘

背景

本周开发了一个退款页(内嵌到APP webview里展示的H5),其中有个让用户输入退款账户的输入框。想实现成当获取输入框焦点之时打开英文键盘(上家公司里有类似封装好的方法——公共部门开发的,但是没有想到去研究过)。于是网上查找了一番,发现我的需求还可以进一步优化 —— 根据不同类型输入框,显示不同类型的软键盘。如:输入邮箱的显示带@符号的键盘,输入手机号的显示数字键盘、输入URL的显示带http/ 的英文键盘。

参考阅读

Vuex 再学习(一)—— 基础中的基础

什么是 Vuex

专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态。

四个核心概念要知道吧

  • State: 单一状态书树。vuex的状态存储是响应式的。通过在根组件注入 store选型 让 vuex实例注入到每个自组件变成现实。这样一来我们就可以在任意子组件里获取 vuex 中存储的状态了。
  • Getter: 可看作是 vuex 的计算属性。用于基于 state 派生状态!getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。getter 接受 state 作为第一个参数!
  • Mutation: 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。所以 mutation 类似事件。。
  • Action:

gulp 学习笔记

参考阅读

常用插件

插件 描述
gulp-webp 用于将图片转换为WebP
gulp-imagemin 用于压缩图片文件(包括PNG、JPEG、GIF和SVG图片
gulp-load-plugins 自动加载插件
gulp-notify 我们用notify的功能主要有两点,显示报错信息和报错后不终止当前gulp任务。
gulp-webpack gulp的webpack插件(注意:已经被废弃)
gulp-replace 字符串替换
gulp-html-replace 。。。
gulp-rename 用户重命名文件流中的文件
gulp-uglify 用于压缩 js 代码
gulp-minify-css 压缩css (注意:已被废弃)
gulp-clean-css 用于压缩c s s
gulp-angular-templatecache 在$ templateCache中连接并注册AngularJS模板
gulp-jshint 检查 js 语法错误
gulp-autoprefixer 使用gulp-autoprefixer根据设置浏览器版本自动处理浏览器前缀。使用她我们可以很潇洒地写代码,不必考虑各浏览器兼容前缀。
gulp-minify-html 压缩html (注意:已被弃用, 取而代之的是 gulp-htmlmin)
gulp-htmlmin 压缩html
gulp-sass 编译sass
gulp-sourcemaps 。。。
gulp-manifest 生成HTML5高速缓存清单文件
gulp-zip 压缩导出 ZIP文件

前端代码规范 —— HTML篇

HTML编码规范

一、 代码风格

  1.1 缩进与换行

  1.2 命名

  1.3 标签

  1.4 属性

二、 通用

  2.1 DOCTYPE

  2.2 编码

  2.3 CSS 和 JavaScript 引入

三、 head

  3.1 title

  3.2 favicon

  3.3 viewport

四、 图片

五、 表单

  5.1 控件标题

  5.2 按钮

  5.3 可访问性 (A11Y)


一、 代码风格

1.1 缩进与换行

[强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格 或 tab 字符。

解释:
对于非 HTML 标签之间的缩进,比如 script 或 style 标签内容缩进,与 script 或 style 标签的缩进同级。

示例:

<style>
/* 样式内容的第一级缩进与所属的 style 标签对齐 */
ul {
    padding: 0;
}
</style>
<ul>
    <li>first</li>
    <li>second</li>
</ul>
<script>
// 脚本代码的第一级缩进与所属的 script 标签对齐
require(['app'], function (app) {
    app.init();
});
</script>

[建议] 每行不得超过 120 个字符。

解释:

过长的代码不容易阅读与维护。但是考虑到 HTML 的特殊性,不做硬性要求。

1.2 命名

[强制] class 必须单词的全字母小写,单词间以 - 分隔。

[强制] class 必须代表相应模块或部件的内容或功能,不得以样式信息进行命名。

示例:

<!-- good -->
<div class="sidebar"></div>

<!-- bad -->
<div class="left"></div>

[强制] 元素 id 必须保证页面唯一。

解释:

同一个页面中,不同的元素包含相同的 id,不符合 id 的属性含义。并且使用 document.getElementById 时可能导致难以追查的问题。

[建议] id 建议单词全字母小写,单词间以 - 分隔。同项目必须保持风格一致。

[建议] idclass 命名,在避免冲突并描述清楚的前提下尽可能短。

示例:

<!-- good -->
<div id="nav"></div>
<!-- bad -->
<div id="navigation"></div>

<!-- good -->
<p class="comment"></p>
<!-- bad -->
<p class="com"></p>

<!-- good -->
<span class="author"></span>
<!-- bad -->
<span class="red"></span>

[强制] 禁止为了 hook 脚本,创建无样式信息的 class

解释:

不允许 class 只用于让 JavaScript 选择某些元素,class 应该具有明确的语义和样式。否则容易导致 CSS class 泛滥。

使用 id、属性选择作为 hook 是更好的方式。

[强制] 同一页面,应避免使用相同的 nameid

解释:

IE 浏览器会混淆元素的 idname 属性, document.getElementById 可能获得不期望的元素。所以在对元素的 idname 属性的命名需要非常小心。

一个比较好的实践是,为 idname 使用不同的命名法。

示例:

<input name="foo">
<div id="foo"></div>

<script>
<!-- IE6 将显示 INPUT -->
alert(document.getElementById('foo').tagName);
</script>

1.3 标签

[强制] 标签名 必须使用小写字母。

[强制] 对于无需自闭合的标签,不允许自闭合。

解释:

常见无需自闭合标签有 inputbrimghr 等。

示例:

<!-- good -->
<input type="text" name="title">

<!-- bad -->
<input type="text" name="title" />

[强制] 对 HTML5 中规定允许省略的闭合标签,不允许省略闭合标签。

示例:

<!-- good -->
<ul>
    <li>first</li>
    <li>second</li>
</ul>

<!-- bad -->
<ul>
    <li>first
    <li>second
</ul>

[强制] 标签使用必须符合标签嵌套规则。

解释:

比如 div 不得置于 p 中,tbody 必须置于 table 中。

详细的标签嵌套规则参见HTML DTD中的 Elements 定义部分。

[建议] HTML 标签的使用应该遵循标签的语义。

解释:

下面是常见标签语义

  • p - 段落
  • h1,h2,h3,h4,h5,h6 - 层级标题
  • strong,em - 强调
  • ins - 插入
  • del - 删除
  • abbr - 缩写
  • code - 代码标识
  • cite - 引述来源作品的标题
  • q - 引用
  • blockquote - 一段或长篇引用
  • ul - 无序列表
  • ol - 有序列表
  • dl,dt,dd - 定义列表

示例:

<!-- good -->
<p>Esprima serves as an important <strong>building block</strong> for some JavaScript language tools.</p>

<!-- bad -->
<div>Esprima serves as an important <span class="strong">building block</span> for some JavaScript language tools.</div>

[建议] 在 CSS 可以实现相同需求的情况下不得使用表格进行布局。

解释:

在兼容性允许的情况下应尽量保持语义正确性。对网格对齐和拉伸性有严格要求的场景允许例外,如多列复杂表单。

[建议] 标签的使用应尽量简洁,减少不必要的标签。

示例:

<!-- good -->
<img class="avatar" src="image.png">

<!-- bad -->
<span class="avatar">
    <img src="image.png">
</span>

1.4 属性

[强制] 属性名必须使用小写字母。

示例:

<!-- good -->
<table cellspacing="0">...</table>

<!-- bad -->
<table cellSpacing="0">...</table>

[强制] 属性值必须用双引号包围。

解释:

不允许使用单引号,不允许不使用引号。

示例:

<!-- good -->
<script src="esl.js"></script>

<!-- bad -->
<script src='esl.js'></script>
<script src=esl.js></script>

[建议] 布尔类型的属性,建议不添加属性值。

示例:

<input type="text" disabled>
<input type="checkbox" value="1" checked>

[建议] 自定义属性建议以 xxx- 为前缀,推荐使用 data-

解释:

使用前缀有助于区分自定义属性和标准定义的属性。

示例:

<ol data-ui-type="Select"></ol>

二、 通用

2.1 DOCTYPE

[强制] 使用 HTML5doctype 来启用标准模式,建议使用大写的 DOCTYPE

示例:

<!DOCTYPE html>

[建议] 启用 IE Edge 模式。

示例:

<meta http-equiv="X-UA-Compatible" content="IE=Edge">

[建议] 在 html 标签上设置正确的 lang 属性。

解释:

有助于提高页面的可访问性,如:让语音合成工具确定其所应该采用的发音,令翻译工具确定其翻译语言等。

示例:

<html lang="zh-CN">

2.2 编码

[强制] 页面必须使用精简形式,明确指定字符编码。指定字符编码的 meta 必须是 head 的第一个直接子元素。

解释:

HTML5 Charset能用吗 一文。

示例:

<html>
    <head>
        <meta charset="UTF-8">
        ......
    </head>
    <body>
        ......
    </body>
</html>

[建议] HTML 文件使用无 BOMUTF-8 编码。

解释:

UTF-8 编码具有更广泛的适应性。BOM 在使用程序或工具处理文件时可能造成不必要的干扰。

2.3 CSS 和 JavaScript 引入

[强制] 引入 CSS 时必须指明 rel="stylesheet"

示例:

<link rel="stylesheet" href="page.css">

[建议] 引入 CSSJavaScript 时无须指明 type 属性。

解释:

text/csstext/javascripttype 的默认值。

[建议] 展现定义放置于外部 CSS 中,行为定义放置于外部 JavaScript 中。

解释:

结构-样式-行为的代码分离,对于提高代码的可阅读性和维护性都有好处。

[建议] 在 head 中引入页面需要的所有 CSS 资源。

解释:

在页面渲染的过程中,新的CSS可能导致元素的样式重新计算和绘制,页面闪烁。

[建议] JavaScript 应当放在页面末尾,或采用异步加载。

解释:

script 放在页面中间将阻断页面的渲染。出于性能方面的考虑,如非必要,请遵守此条建议。

示例:

<body>
    <!-- a lot of elements -->
    <script src="init-behavior.js"></script>
</body>

[建议] 移动环境或只针对现代浏览器设计的 Web 应用,如果引用外部资源的 URL 协议部分与页面相同,建议省略协议前缀。

解释:

使用 protocol-relative URL 引入 CSS,在 IE7/8 下,会发两次请求。是否使用 protocol-relative URL 应充分考虑页面针对的环境。

示例:

<script src="//s1.bdstatic.com/cache/static/jquery-1.10.2.min_f2fb5194.js"></script>

三、 head

3.1 title

[强制] 页面必须包含 title 标签声明标题。

[强制] title 必须作为 head 的直接子元素,并紧随 charset 声明之后。

解释:

title 中如果包含 ASCII 之外的字符,浏览器需要知道字符编码类型才能进行解码,否则可能导致乱码。

示例:

<head>
    <meta charset="UTF-8">
    <title>页面标题</title>
</head>

3.2 favicon

[强制] 保证 favicon 可访问。

解释:

在未指定 favicon 时,大多数浏览器会请求 Web Server 根目录下的 favicon.ico 。为了保证 favicon 可访问,避免 404,必须遵循以下两种方法之一:

  1. 在 Web Server 根目录放置 favicon.ico 文件。
  2. 使用 link 指定 favicon。

示例:

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

3.3 viewport

[建议] 若页面欲对移动设备友好,需指定页面的 viewport

解释:

viewport meta tag 可以设置可视区域的宽度和初始缩放大小,避免在移动设备上出现页面展示不正常。

比如,在页面宽度小于 980px 时,若需 iOS 设备友好,应当设置 viewport 的 width 值来适应你的页面宽度。同时因为不同移动设备分辨率不同,在设置时,应当使用 device-widthdevice-height 变量。

另外,为了使 viewport 正常工作,在页面内容样式布局设计上也要做相应调整,如避免绝对定位等。关于 viewport 的更多介绍,可以参见 Safari Web Content Guide的介绍

四、 图片

[强制] 图片命名

图片命名建议以以下顺序命名:
图片业务(可选) +(mod_)图片功能类别(必选)+ 图片模块名称(可选) + 图片精度(可选)

  • 图片业务:

    • pp_:拍拍
    • wx_:微信
    • sq_:手Q
  • jd_:京东商城

  • 图片功能类别:

    • mod_:是否公共,可选
    • icon:模块类固化的图标
    • logo:LOGO类
    • spr:单页面各种元素合并集合
    • btn:按钮
    • bg:可平铺或者大背景
  • 图片模块名称:

    • goodslist:商品列表
    • goodsinfo:商品信息
    • userava tar:用户头像
  • 图片精度或尺寸:

如下面例子:

公共模块:
wx_mod_btn_goodlist@2x.png
wx_mod_btn_goodlist.png
mod_btn_goodlist.png 

非公共模块:
wx_btn_goodlist@2x.png
wx_btn_goodlist.png
btn_goodlist.png

[强制] 禁止 imgsrc 取值为空。延迟加载的图片也要增加默认的 src

解释:

src 取值为空,会导致部分浏览器重新加载一次当前页面,参考:https://developer.yahoo.com/performance/rules.html#emptysrc

[建议] 避免为 img 添加不必要的 title 属性。

解释:

多余的 title 影响看图体验,并且增加了页面尺寸。

[建议] 为重要图片添加 alt 属性。

解释:

可以提高图片加载失败时的用户体验。

[建议] 添加 widthheight 属性,以避免页面抖动。

[建议] 有下载需求的图片采用 img 标签实现,无下载需求的图片采用 CSS 背景图实现。

解释:

  1. 产品 logo、用户头像、用户产生的图片等有潜在下载需求的图片,以 img 形式实现,能方便用户下载。
  2. 无下载需求的图片,比如:icon、背景、代码使用的图片等,尽可能采用 CSS 背景图实现。

五、 表单

5.1 控件标题

[强制] 有文本标题的控件必须使用 label 标签将其与其标题相关联。

解释:

有两种方式:

  1. 将控件置于 label 内。
  2. labelfor 属性指向控件的 id

推荐使用第一种,减少不必要的 id。如果 DOM 结构不允许直接嵌套,则应使用第二种。

示例:

<label><input type="checkbox" name="confirm" value="on"> 我已确认上述条款</label>

<label for="username">用户名:</label> <input type="textbox" name="username" id="username">

5.2 按钮

[强制] 使用 button 元素时必须指明 type 属性值。

解释:

button 元素的默认 typesubmit,如果被置于 form 元素中,点击后将导致表单提交。为显示区分其作用且方便理解,我们要求必须给出 type 属性。

示例:

<button type="submit">提交</button>
<button type="button">取消</button>

[建议] 尽量不要使用按钮类元素的 name 属性。

解释:

由于浏览器兼容性问题,使用按钮的 name 属性会带来许多难以发现的问题。具体情况可参考此文

5.3 可访问性 (A11Y)

[建议] 负责主要功能的按钮在 DOM 中的顺序应靠前。

解释:

负责主要功能的按钮应相对靠前,以提高可访问性。如果在 CSS 中指定了 float: right 则可能导致视觉上主按钮在前,而 DOM 中主按钮靠后的情况。

示例:

<!-- good -->
<style>
.buttons .button-group {
    float: right;
}
</style>

<div class="buttons">
    <div class="button-group">
        <button type="submit">提交</button>
        <button type="button">取消</button>
    </div>
</div>

<!-- bad -->
<style>
.buttons button {
    float: right;
}
</style>

<div class="buttons">
    <button type="button">取消</button>
    <button type="submit">提交</button>
</div>

[建议] 当使用 JavaScript 进行表单提交时,如果条件允许,应使原生提交功能正常工作。

解释:

当浏览器 JS 运行错误或关闭 JS 时,提交功能将无法工作。如果正确指定了 form 元素的 action 属性和表单控件的 name 属性时,提交仍可继续进行。

示例:

<form action="/login" method="post">
    <p><input name="username" type="text" placeholder="用户名"></p>
    <p><input name="password" type="password" placeholder="密码"></p>
</form>

[建议] 在针对移动设备开发的页面时,根据内容类型指定输入框的 type 属性。

解释:

根据内容类型指定输入框类型,能获得能友好的输入体验。

示例:

<input type="date">

CSS实现footer“吸底”效果

需求背景

最近做了一个新项目官网,除顶部导航和底部footer外中间部分是通过请求拉取得到的,这样就有个问题——在页面初始化或其他操作刷新时中间主题部分并没有足够多的内容吃撑整个页面。出现的情况就是在初始化过程中主体部分信息还未拉取渲染出来时底部footer顶到顶部导航下面了。。

Tip: 实际上footer始终居底显示效果已经不知道写过多少遍了,也可能因为老了把记性不好了,太久没写了就忘了。工作中遇到记录下来回来重新整理记录加深下理解。

目标

当主题内容区域的内容较少时,footer始终居底显示在屏幕的最下方。
当主体区域内容较多时,footer随着主题内容区增高而撑开,始终显示在页面的最底部。

实现

参看阅读

https://juejin.im/post/5bbc9cb4f265da0add51dc0f#heading-6

flex: 1 是什么意思?

我们知道 flex 属性是 flex-grow、flex-shrink 和 flex-basis 的缩写,它的默认值是 0 1 auto,这表示:

flex-grow: 0; 
flex-shrink: 1; 
flex-basis: auto;  

flex: 1 表示的是一下内容:

flex-grow: 1; //这意味着div将以与窗口大小相同的比例增长
flex-shrink: 1; //这意味着div将以与窗口大小相同的比例缩小
flex-basis: 0;  // 这意味着div没有这样的起始值,并且会根据可用的屏幕尺寸占用屏幕,例如:-如果包装中有3个div,则每个div将占33%。

https://stackoverflow.com/questions/37386244/what-does-flex-1-mean
https://xbuba.com/questions/37386244/what-does-flex-1-mean
https://www.w3.org/TR/css-flexbox-1/#flex-common
https://developer.mozilla.org/en-US/docs/Web/CSS/flex

vh、vw、vmin、vmax 知多少 !

介绍一些 CSS3 新增的单位,平时可能用的比较少,但是由于单位的特性,在一些特殊场合会有妙用。

vw and vh

  1. vw 等于1/100的视口宽度 (Viewport Width)
  2. vh 等于1/100的视口高度 (Viewport Height)

综上,一个页面而言,它的视窗的高度就是 100vh,宽度就是 100vw 。看个例子:

CodePen Demo

响应式web设计离不开百分比。但是,CSS百分比并不是所有的问题的最佳解决方案。CSS的宽度是相对于包含它的最近的父元素的宽度的。但是如果你就想用视口(viewpoint)的宽度或者高度,而不是父元素的,那该肿么办? 这就是 vh 和 vw 单位为我们提供的。

1vh 等于1/100的视口高度。栗子:浏览器高度900px, 1 vh = 900px/100 = 9 px。同理,如果视口宽度为750, 1vw = 750px/100 = 7.5 px。

可以想象到的,他们有很多很多的用途。比如,我们用很简单的方法只用一行CSS代码就实现同屏幕等高的框。

.slide {
    height: 100vh;
}

假设你要来一个和屏幕同宽的标题,你只要设置这个标题的font-size的单位为vw,那标题的字体大小就会自动根据浏览器的宽度进行缩放,以达到字体和viewport大小同步的效果。

vmin and vmax

vh和 vw 依据于视口的高度和宽度,相对的,vmin 和 vmax则关于视口高度和宽度两者的最小或者最大值

  1. vmin — vmin的值是当前vw和vh中较小的值。
  2. vmax — vw和vh中较大的值。

这个单位在横竖屏的切换中,十分有用。

在一些 Demo 示例,或者大页面中,我们经常都会看到上述 4 个单位的身影。灵活使用,就可以减少很多 CSS 的代码量。

react-router 学习笔记~

API

withRouter

withRouter是 react-router 的一个高阶组件,可获取history。
render时会把match, location和history传入props。

在 react 中只有经过路由渲染的组件才拥有路由参数,例如:使用this.props.history.push('/a')跳转到对应路由的页面。而withRouter作用就是将路由参数传入this.props中,这样一来那些没有使用路由跳转的组件,也能够获取路由参数了。

⚠️注意:

withRouter组件有两种使用方法:(1)withRouter(App) (2)直接在组件上使用'@withRouter'。
使用@这种写法的话,需要babel-plugin-transform-decorators-legacy包。

npm install babel-plugin-transform-decorators-legacy --save-dev

还需要在packag文件中的babel中配置,具体实现方式可以查看react @装饰器相关文档。

{
    "plugins":[
        "transform-decorators-legacy"
    ]
}

通过 withRouter 高阶组件可以访问 history 对象的属性,以及最近的匹配项。每次渲染组件时(renders)时,withRouter都会将更新的匹配(match)、位置(location) 和 history props传递给包装组件(wrapped component)。

import React from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router";

// 显示当前路径名
class ShowTheLocation extends React.Component {
  static propTypes = {
    match: PropTypes.object.isRequired,
    location: PropTypes.object.isRequired,
    history: PropTypes.object.isRequired
  };

  render() {
    const { match, location, history } = this.props;

    return <div>You are now at {location.pathname}</div>;
  }
}

// Create a new component that is "connected" (to borrow redux terminology) to the router.
//创建一个 “连接(connected)” 到路由器的新组件(借用redux术语)。
const ShowTheLocationWithRouter = withRouter(ShowTheLocation);

重点:

withRouter 不像 React Redux 的 connect 那样订阅位置更改来进行状态更改。
而是在位置更改后从 组件传播出去后重新渲染。
这意味着 withRouter 不会在路由转换时重新呈现,除非其父组件重新呈现。

静态方法与属性
包装组件所有不是 react 的(no-react)特定的静态方法和属性自动复制到“已连接”组件。

Component.WrappedComponent

包装的组件在返回的组件上作为静态属性 WrappedComponent 公开,它可以用于隔离测试组件等。

// MyComponent.js
export default withRouter(MyComponent)

// MyComponent.test.js
import MyComponent from './MyComponent'
render(<MyComponent.WrappedComponent location={{...}} ... />)

wrappedComponentRef: func

该函数将作为ref prop传递给包装的组件。

class Container extends React.Component {
  componentDidMount() {
    this.component.doSomething();
  }

  render() {
    return (
      <MyComponent wrappedComponentRef={c => (this.component = c)} />
    );
  }
}

Lottie-web 入门文档

lottie
lottie


一、背景介绍

刚来到新公司,接手的第一个任务就是“任务中心养花”动画,整个动画部分由前端开发完成,最后内嵌到客户端webview。。之前还真没这样玩过啊!!

设计稿上有几部分组成,其中花🌹本身是可以交互的,比如点击它会晃动(需求分析会上我表示这让给你给我前端怎么实现,这过渡效果用js写估计会搞死)。后来,UI 说 动画 部分它会做好,最后给到我的是json文件。这里我开始是有点懵的,之前也没这样搞过啊。没关系,回头周末google 找来下,还真有这种玩法,这里要夸夸我们公司的UI小哥 真棒👍👍


二、什么是 lottie

Lottie是一个库,可以解析使用AE制作的动画(需要用bodymovin导出为json格式),支持web、ios、android和react native。在web侧,lottie-web库可以解析导出的动画json文件,并将其以svg或者canvas的方式将动画绘制到我们页面中。


三、API

一个动画有以下几个主要方法:play、stop、pause

生成一个动画实🌰 —— lottie.loadAnimation()

调用 lottie.loadAnimation() 来启动一个动画。它接受一个对象作为参数;

  • animationData: 被导出的动画数据对象,通常是一个json文件。
  • path: 指向动画数据文件的链接。 (animationData and path 是互斥的,既只能有一个)
  • loop: 是否循环播放动画(true / false / number);
  • autoplay: 是否自动播放,true / false
  • name: 定义一个动画名称,方便后面引用;
  • renderer: 设置渲染类型。有'svg' / 'canvas' / 'html' 三种类型可选;
  • container: 渲染动画的容器;

它返回的是一个动画实力,我们可以通过play、pause、setSpeed等来控制它;

lottie.loadAnimation({
  container: element, // the dom element that will contain the animation
  renderer: 'svg',
  loop: true,
  autoplay: true,
  path: 'data.json' // the path to the animation json
});

动画实🌰方法列表:

方法 描述
anim.play() 播放该动画(从目前停止的帧开始播放)
anim.stop() 停止播放该动画 ( 回到第0帧 )
anim.pause() 暂停该动画 ( 在当前帧停止并保持)
anim.setLocationHref(locationHref)
anim.setSpeed(speed) 设置播放速度,speed为1表示正常速度
anim.goToAndStop(value, isFrame) 跳到某个时刻/帧并停止。isFrame(默认false)指示value表示帧还是时间(毫秒)
anim.goToAndPlay(value, isFrame) 跳到某个时刻/帧并进行播放
anim.setDirection(direction) 设置播放方向,1表示正向播放,-1表示反向播放
anim.playSegments(segments, forceFlag) arr可以包含两个数字或者两个数字组成的数组,forceFlag表示是否立即强制播放该片段
anim.setSubframe(flag)
anim.destroy() 删除该动画,移除相应的元素标签等。在unmount的时候,需要调用该方法
animation.goToAndStop(30, true); // 跳转到第30帧并停止
animation.goToAndPlay(300); // 跳转到第300毫秒并播放

animation.playSegments([10,20], false); // 播放完之前的片段,播放10-20帧
animation.playSegments([[0,5],[10,18]], true); // 直接播放0-5帧和10-18帧

Lottie的8个主要方法

方法 描述
lottie.play() 播放动画
lottie.stop() 停止播放动画
lottie.setSpeed() 设置播放速度
lottie.setDirection() 设置播放方向
lottie.searchAnimations()
lottie.loadAnimation() 返回一个动画实例单独控制
lottie.destroy() 销毁和释放资源,DOM元素会被清空
lottie.registerAnimation() 直接注册一个元素,到那时他必须又一个指向data.json链接的“data-animation-path”属性
lottie.setQuality()

事件

事件 描述
onComplete 动画播放完成触发
onLoopComplete 当前循环播放完成触发
onEnterFrame 播放一帧动画的时候触发
onSegmentStart 开始播放一个动画片段的时候触发

你也可以使用 addEventListener 监听以下事件:

事件 描述
complete 编译完成(循环播放下不会触发)
loopComplete 当前循环下播放(循环播放/非循环播放)结束时触发
enterFrame 每进入一帧就会触发,播放时每一帧都会触发一次,stop方法也会触发
segmentStart 播放指定片段时触发,playSegments、resetSegments等方法刚开始播放指定片段时会发出,如果playSegments播放多个片段,多个片段最开始都会触发。
config_ready 初始化配置完成后触发
data_ready 动画json文件加载完毕触发
DOMLoaded 动画相关的dom已经被添加到html后触发
destroy 将在动画删除时触发

四、推荐阅读

管理后台前端工程架构方案

背景

公司之前上了一个小说新项目,出于小说内容管理下发,以及后续写手管理与开放一些给写手的功能方面考虑需要做一个运营后台管理平台。

技术选型

技术侧决定使用前后分离方式开发。前端部分使用vue(不要问我为什么,还不是因为不喜欢React Jxs语法), 并打算基于第三方开源后台框架开始进行扩展开发。。对比之后最终选择基于vue-element-admin 基础模版开发。

技术栈

  • Vue 构建界面的渐进式框架
  • Vuex 是一个vue.js的状态管理插件;
  • Vue-Router 是vue.js官方路由管理器;
  • Element UI 饿了么桌面组件库;
  • Scss Css与处理语言

目录结构

├── build                      # 构建相关
├── mock                       # 项目mock 模拟数据
├── public                     # 静态资源
│   │── favicon.ico            # favicon图标
│   └── index.html             # html模板
├── src                        # 源代码
│   ├── api                    # 所有请求
│   ├── assets                 # 主题 字体等静态资源
│   ├── components             # 全局公用组件
│   ├── directive              # 全局指令
│   ├── filters                # 全局 filter
│   ├── icons                  # 项目所有 svg icons
│   ├── lang                   # 国际化 language
│   ├── layout                 # 全局 layout
│   ├── router                 # 路由
│   ├── store                  # 全局 store管理
│   ├── styles                 # 全局样式
│   ├── utils                  # 全局公用方法
│   ├── vendor                 # 公用vendor
│   ├── views                  # views 所有页面
│   ├── App.vue                # 入口页面
│   ├── main.js                # 入口文件 加载组件 初始化等
│   └── permission.js          # 权限管理
├── tests                      # 测试
├── .env.xxx                   # 环境变量配置
├── .eslintrc.js               # eslint 配置项
├── .babelrc                   # babel-loader 配置
├── .travis.yml                # 自动化CI配置
├── vue.config.js              # vue-cli 配置
├── postcss.config.js          # postcss 配置
└── package.json               # package.json

Umi.js 生态圈入门

React

dva

状态管理;

connect 与 @connect

connect

connect的作用是将组件和models结合在一起。将models中的state绑定到组件的props中。并提供一些额外的功能,譬如dispatch

@connect

其实只是connect的装饰器、语法糖罢了。

Loash

// 防抖动:作用是在短时间内多次触发同一个函数,只执行最后一次,或者只在开始时执行
import debounce from 'lodash/debounce';

antd

// 配合这 <LocaleProvider> 模块/组件使用,只改变内建的文案
import en_US from 'antd/lib/locale-provider/en_US'; // 国际化, 语言包

// 本模块仅用于组件的内建文案,若有业务文案的国际化需求,建议使用 react-intl,可参考示例:Intl demo 1 和 Intl demo 2。

antd Pro

G2

react-intl

其他

  • react-router-breadcrumbs-hoc | umi 官网推荐使用的一个面包屑插件
  • path

详解 Component Vs PureComponent

先说结论:

Component 与 PureComponent 功能基本一致,但PureComponent 性能更好,所以推荐使用PureComponent 创建组件。

问题来了:

  • 为什么 PureComponent 性能比 Component 好?
  • 为什么已知 PureComponent 性能好的前提下仍然能看到很多开源项目在使用 Component 创建组件?

为什么 PureComponent 性能比 Component 好

PureComponent 与 Component 除了在 shouldComponentUpdate 钩子实现方式不同之外,其他部分完全相同。

PureComponent, 会在 props 或者 state 发生变更时对 props 和state进行 浅比较
Component, 在 props或者state发生变更时并不会对props和state进行比较,而是直接更新组件。

重点:浅比较?
浅比较 会比较props 和 state 的当前值与原始值、数组和对下引用是否相同。

注意
浅比较也引出一个新的问题,就是当修改props或者 state 中的数组或对象时,并不会引起组件的跟更新,这是因为虽然值改变了,但是自组件比较的是之前的props 或 state 的引用。。所以并没有检测到不同。

解决办法:
你可以通过使用es6的assign方法或者数组的扩展运算符或者使用第三方库,强制返回一个新的对象。

结论

比较不同,然后只更新组件需要更新的部分总比全部更新要快的多。

[React] 入门-1: create-react-app 构建 React 项目

目录结构介绍

+-- build/                              ---打包的文件目录
+-- config/                             ---npm run eject 后的配置文件目录
+-- node_modules/                       ---依赖文件目录
+-- public/                             ---全局文件          
|   --- index.html			    ---首页入口html文件(全局文件模板)
|   --- manifest.json                       ---全局配置文件
+-- src/                                ---开发源码
|  +-- axios/                               ---http请求存放目录
|   |    ---index.js
|   +-- component/                          ---各式各样的组件存放目录
|   |   --- ...
|   |   --- ...
|   +-- style/                              ---项目的样式存放目录,主要采用less编写
|   +-- utils                               ---工具文件存放目录
|   --- App.css                             ---组件入口文件的样式文件
|   --- App.js                              ---组件入口文件
|   --- App.test.js                         ---若渲染失败显示的组件
|   --- index.css                           ---入口文件的样式文件
|   --- index.js                            ---项目的整体js入口文件,包括路由配置等
|   --- logo.svg                            ---图标
|   --- registerServiceWorker               ---保存用户的登录、更新信息
|   --- router.js                           ---实现页面跳转配置 
--- .gitignore                          ---git提交忽略文件配置
--- package.json                        ---项目配置信息
--- README.md                           ---存储一些配置信息
--- yarn.lock                           ---锁定项目所需的各种配置版本

前端性能优化

前端代码规范

【前端】代码规范

写在前面:
以后不管有多少人共同参与同一个项目,又或者前端团队扩充到多大规模,我们都希望大家执行一套代码规范,让我们的代码看上去像是一个人写的,这也才能保证代码的易读性。

JavaScript

HTML

  • 用两个空格来代替制表符(tab) -- 这是唯一能保证在所有环境下获得一致展现的方法。
  • 嵌套元素应当缩进一次(即两个空格)。
  • 对于属性的定义,确保全部使用双引号,绝不要使用单引号。
  • 不要在自闭合(self-closing)元素的尾部添加斜线。
  • 不要省略可选的结束标签(closing tag)(例如,</li> </body>)。
  • HTML5 doctype:每个h5页面第一行都是用标准模式,这样可以做到在不同浏览器中显示一致。
  • 语义化标签:任何时候都要避免 div 标签的滥用。通过最少标签、语义化标签来解决 html 文件的复杂度,提升可读性;
  • 标签一律小写;
  • 字符编码
<head>
  <meta charset="UTF-8">
</head>

通过明确声明字符编码,能够确保浏览器快速并容易的判断页面内容的渲染方式。这样做的好处是,可以避免在 HTML 中使用字符实体标记(character entity),从而全部与文档编码一致(一般采用 UTF-8 编码)。

  • 引入 CSS 和 JavaScript 文件
<!-- External CSS -->
<link rel="stylesheet" href="code-guide.css">

<!-- In-document CSS -->
<style>
  /* ... */
</style>

<!-- JavaScript -->
<script src="code-guide.js"></script>

根据 HTML5 规范,在引入 CSS 和 JavaScript 文件时一般不需要指定 type 属性,因为 text/css 和 text/javascript 分别是它们的默认值。

  • IE 兼容模式
<meta http-equiv="X-UA-Compatible" content="IE=Edge">

IE 支持通过特定的 标签来确定绘制当前页面所应该采用的 IE 版本。除非有强烈的特殊需求,否则最好是设置为 edge mode,从而通知 IE 采用其所支持的最新的模式。

  • 属性顺序

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

class
id, name
data-*
src, for, type, href, value
title, alt
role, aria-*
<a class="..." id="..." data-toggle="modal" href="#">
  Example link
</a>

<input class="form-control" type="text">

<img src="..." alt="...">

class 用于标识高度可复用组件,因此应该排在首位。id 用于标识具体组件,应当谨慎使用(例如,页面内的书签),因此排在第二位。

  • 布尔(boolean)型属性: 可以在声明时不赋值。
    元素的布尔型属性如果有值,就是 true,如果没有值,就是 false。
<input type="text" disabled>

<input type="checkbox" value="1" checked>

<select>
  <option value="1" selected>1</option>
</select>
  • 避免 非必须 情况下通过 Javascript 生成 html。
    因为它会让内容不那么容易查找,且会降低性能。

  • 注释
    我们建议html中也要写注释,很多时候这一点被忽略了。但是从html 可读方面考虑,建议通过 注释 + 空格 + 语义化的标签 来让你的 html 区块清晰,代码可读;

CSS

混合开发前端调试技巧

android

  1. 第一步:android 设备上开始开发者模式;
  2. 第二步: 手机通过数据线链接电脑,并打开 USB 调试;
  3. 第三步:chrome 浏览器地址栏输入:chrome://inspect/#devices
  4. 第四步: 之后,在手机端打开网页还是打开带有混合 H5 页面的 app 页面,chrome 就会检测到对应的页面,之后可以直接调试;

IOS

目标:

  • 实现在Mac平台使用Safari(或结合ios_webkit_dubug_proxy使用Chrome)调试手机中Safari的页面;
  • 结合Charles进行抓包请求断点
  • 在Windows中结合Fiddler与ios_webkit_debug_proxy中转实现Chrome调试手机的Safari浏览器

开启 Safari 远程调试

1、第一步: 如果,电脑上还没有安装 Xcode 的话,请先安装。安装成功之后,打开 iPhone 开发者模式。
2、第二步: 在Iphone手机端,设置-》safari-》高级-》web检查器。打开。
3、第三步: safari -> 偏好设置 -> 高级 -> 勾选“在菜单中显示‘开发’菜单”
4、第四步: 在电脑上安装 ios_webkit_debug_proxyRemoteDebug iOS WebKit Adapter

彻底搞清楚 rem、em、px三者之间的区别

一、PX

相对单位,像素 px 是相对于显示器屏幕分辨率而言的。

特点

  1. IE无法调整那些使用 px 作为单位的字体大小;
  2. 国外的大部分网站能够调整的原因在于其使用了 em 或 rem 作为字体单位;
  3. Firefox能够调整 px 、em 和 rem,但是96%以上的**网民使用IE浏览器(或内核)。

二、EM

em 是相对长度单位。相对于当前对象内文本的字体尺寸。

如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。

特点

  1. em 的值并不是固定的;
  2. em 会继承父级元素的字体大小。

注意:任意浏览器的默认字体高都是16px。所有未经调整的浏览器都符合: 1em=16px。那么12px=0.75em,10px=0.625em。为了简化font-size的换算,需要在css中的body选择器中声明Font-size=62.5%,这就使em值变为 16px*62.5%=10px, 这样12px=1.2em, 10px=1em, 也就是说只需要将你的原来的px数值除以10,然后换上em作为单位就行了。

所以我们在写CSS的时候,需要注意两点:

  1. body选择器中声明 Font-size=62.5%;
  2. 将你的原来的px数值除以10,然后换上em作为单位;
  3. 重新计算那些被放大的字体的em数值。避免字体大小的重复声明。
    也就是避免1.2 * 1.2= 1.44的现象。比如说你在#content中声明了字体大小为1.2em,那么在声明p的字体大小时就只能是1em,而不是1.2em, 因为此em非彼em,它因继承#content的字体高而变为了1em=12px。

三、REM

rem是CSS3新增的一个相对单位(root em,根em),这个单位引起了广泛关注。

特点

  • 使用 rem 为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素;
  • 集相对大小和绝对大小的优点于一身;
  • 通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。

这个单位与em有什么区别呢? 看特点!

目前,除了IE8及更早版本外,所有浏览器均已支持rem。对于不支持它的浏览器,应对方法也很简单,就是多写一个绝对单位的声明。这些浏览器会忽略用rem设定的字体大小。下面就是一个例子:

p  {
   font-size: 14px;
   font-size: .875rem;
}

Readium 初探!

readium
是使用HTML, css 和 Javascript编写的EPUB渲染引擎。

readium-shared-js: 这是Readium Chrome扩展程序和“云阅读器”之间共同共享的软件组件
readium-js-view: ReadiumJS查看器, Readium.js库的默认Web应用程序.
readium_js/epub-fetch/publication_fetcher:
readium_js/epub-fetch/iframe_zip_loader:

readium_shared_js/views/iframe_loader: xxx
readium_shared_js/views/reader_view: xxx

readium_js/epub-model/package_document_parser:

参考阅读:

绝对定位元素,如何剧中!

方法一:如果元素宽高已知的情况下

.element  {    
           position: absolute;  
           width: 600px;   
           height: 400px;  
           left: 50%; 
           top: 50%;  
           margin-top: -200px;            /* 高度的一半 */ 
           margin-left: -300px;            /* 宽度的一半 */  
           border:1px solid;
}

方法二: 使用css3 transform

.element {
        position: absolute;
        border: 1px solid black;
        width: 300px;
        padding: 10px;
        left: 50%;
        top: 20%;
        box-sizing: border-box;
        transform: translate(-50%, -20%);
}

解释:

  • transform 里的 translate偏移的百分比值是相对于自身大小的。
  • translate()方法,根据左(X轴)和顶部(Y轴)位置给定的参数,从当前元素位置移动
    如:translate(50px,100px)是从左边元素移动 50 个像素,并从顶部移动 100 像素。

设想以下,如果是要水平垂直居中呢?代码如下:

 .element { 
        width: 600px;
        height: 400px; 
        position: absolute; 
        left: 50%; 
        top: 50%;
        transform: translate(-50%, -50%);     /* 50%为自身尺寸的一半 */
  }

方法三:使用margin: auto, 实现水平垂直居中

.element {
         width: 600px; 
         height: 400px;
         position: absolute; 
         left: 0;
         top: 0;
         right: 0;
         bottom: 0; 
         margin: auto;
}

Shell 脚本编程学习笔记

#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。
echo 向窗口输出文本;
local 用于定义局部变量。(一般用在函数中使用,因为shell函数中的变量默认也是global的)

变量

注意,变量名和等号之间不能有空格(这可能和你熟悉的所有编程语言都不一样)。

VScode 插件列表

插件 描述
Prettier 代码格式话,用于统一团队代码格式
Eslint 代码检测,用于保证代码质量

react-loadable 深度总结!

是什么?

react-loadable是什么?我们首先看看官方给说明

A higher order component for loading components with dynamic imports.(用于加载具有动态导入的组件的高阶组件。)

通过 hoc 给组件提供动态加载能力。在实际业务开发中,经常遇到性能优化的问题,而其中一个重要优化的点,就是通过动态加载组件来减少首屏的 size,在 react 官方的 lazy 和 suspense 出来之前,相信这是react最流行的动态加载的库,包括现在也是。

next.js 的dynamic的实现也是基于这个库。

怎么用?

这点官方文档写的很清楚,如下所示,Loadable的loader属性中使用import来动态加载组件,同时其中的loading属性是我们可配置的loading component。

import Loadable from 'react-loadable';
import Loading from './my-loading-component';

const LoadableComponent = Loadable({
  loader: () => import('./my-component'), // 使用import动态加载组件
  loading: Loading,  // loading 组件
});

export default class App extends React.Component {
  render() {
    return <LoadableComponent/>;
  }
}

实现思路

源码解析

参考阅读

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.