Git Product home page Git Product logo

blog's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

blog's Issues

【20161020】NodeJS转发Ajax请求

请求某一个接口,然后后期可能换接口了。 如何转发接口呢?
解决该问题呢,可以用服务端来进行请求该接口,然后把返回值原封不动的返回即可。

下面是使用 NodeJs + Express 来实现转发Ajax请求的代码

var express = require('express');
var router = express.Router();
var request = require('request');

/**
 * NodeJs 转发 接口请求
 * 使用方式:127.0.0.1:23018/request?url=完整的接口地址
 */
router.get('/', function (req, res, next) {
  req.pipe(request.get(req.query.url, {
    query: req.query,
    form: req.body
  })).pipe(res);
});

module.exports = router;

【20160918】webpack 教程资源收集

【原github地址】

webpack 教程资源收集

官方文档
中文指南

✌️ 初级教程
💪 进阶教程

🔥 webpack 2.0

💠 React & webpack
🅰️ Angular & webpack
👨 Vue & webpack

【20160831】构造函数继承的几种实现方式

One Day One Tip 之 构造函数继承的几种实现方式

CreateTime:2016-08-31 14:11:49

JavaScript 实现继承的几种方式,有通过原型继承的, 有通过复制父类值继承的。


有动物类【父类】和猫类【子类】

function Animal(){
  this.species = "动物";
}

function Cat(name,color){
  this.name = name;
  this.color = color;
}

方式一、构造函数绑定

把子类的this对象传到Animal的方法里面,然后把父类的属性绑定到 子类的 this 上
Animal.apply(this,arguments)

function Cat(name,color){
  Animal.apply(this, arguments); 
  
  this.name = name;
  this.color = color;
}

var cat1 = new Cat("大毛","黄色");
alert(cat1.species); // 动物

二、prototype模式【常见】

如果"猫"的prototype对象,指向一个Animal的实例,那么所有"猫"的实例,就能继承Animal了。

Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛","黄色");
alert(cat1.species); // 动物

Cat.prototype = new Animal();
把 Cat 类的 prototype 指向 父类的实例。

Cat.prototype.constructor = Cat;
是因为每个 prototype 都有一个 constructor 属性,它指向构造函数。 并且每一个类实例也有一个 constructor 属性, 默认指向 prototype.constructor 。
如果没有添加上这句代码的话

cat1.constructor === Animal //true

虽然功能上使用没有出现什么问题,但是如果有使用到 cat.constructor 去做一些判断还是其他的操作, 会出现隐患。
cat1 明明是 从 Cat 类实例化出来的, 但是 cat.constructor却指向 Animal, 这个会造成继承紊乱。因此需要手动纠正,也就是这句代码的作用。

三、直接继承prototype

只继承 父类的 prototype 上的属性和方法

Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛","黄色");
alert(cat1.species); // 动物

与前一种方法相比,这样做的优点是效率比较高(不用执行和建立Animal的实例了),比较省内存。缺点是 Cat.prototype和Animal.prototype现在指向了同一个对象,那么任何对Cat.prototype的修改,都会反映到Animal.prototype。

所以,上面这一段代码其实是有问题的。请看第二行

Cat.prototype.constructor = Cat;

这一句实际上把Animal.prototype对象的constructor属性也改掉了!

alert(Animal.prototype.constructor); // Cat

四、利用空对象作为中介

由于"直接继承prototype"存在上述的缺点,所以就有第四种方法,利用一个空对象作为中介。

var F = function(){};
F.prototype = Animal.prototype;
Cat.prototype = new F();
Cat.prototype.constructor = Cat;

F是空对象,所以几乎不占内存。这时,修改Cat的prototype对象,就不会影响到Animal的prototype对象。

alert(Animal.prototype.constructor); // Animal

封装一个方法来实现继承

function extend(Child, Parent) {
  var F = function(){};
  F.prototype = Parent.prototype;
  Child.prototype = new F();
  Child.prototype.constructor = Child;
  Child.uber = Parent.prototype;  //备用性质,也可不加
}

使用如下

extend(Cat,Animal);
var cat1 = new Cat("大毛","黄色");
alert(cat1.species); // 动物

五、 拷贝继承

上面是采用prototype对象,实现继承。我们也可以换一种思路,纯粹采用"拷贝"方法实现继承。简单说,如果把父对象的所有属性和方法,拷贝进子对象,不也能够实现继承吗?这样我们就有了第五种方法。
首先,还是把Animal的所有不变属性,都放到它的prototype对象上。

function Animal(){}
Animal.prototype.species = "动物";

然后,再写一个函数,实现属性拷贝的目的。

function extend2(Child, Parent) {
    var p = Parent.prototype;
    var c = Child.prototype;
    for (var i in p) {
      c[i] = p[i];
      }
    c.uber = p;
  }

这个函数的作用,就是将父对象的prototype对象中的属性,一一拷贝给Child对象的prototype对象。
使用的时候,这样写:

  extend2(Cat, Animal);
  var cat1 = new Cat("大毛","黄色");
  alert(cat1.species); // 动物

转载文章

  1. Javascript面向对象编程(二):构造函数的继承

【20160914】正则断言-密码校验

question

Javascript regular expression password validation having special characters

url:http://stackoverflow.com/questions/12090077/javascript-regular-expression-password-validation-having-special-characters

var regularExpression = /^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,16}$/;

说明
必须拥有数字和特殊字符,并且在6~16位之间

Without it, your current regex only matches that you have 6 to 16 valid characters, it doesn't validate that it has at least a number, and at least a special character. That's what the lookahead above is for.

(?=.*[0-9]) - Assert a string has at least one number;
(?=.*[!@#$%^&*]) - Assert a string has at least one special character.

参考文章

  1. 正则表达式的先行断言(lookahead)和后行断言(lookbehind)

【GIT】常用GIT知识点

  • 获取git仓库源码
git clone 仓库地址
  • 获取git的最新内容
git pull
  • git pull 冲突报错如何解决
//本地修改的内容,先存放起来
git stash  

//更新
git pull

//把刚才本地修改内容,合并进来
git stash pop stash@{0}
  • 放弃本地修改的内容,还原代码
git reset --hard
  • 如何修改GIT远程仓库地址
git remote set-url origin 新地址

【20161110】【SQL】PostgreSql常用命令总结

时间:2016-11-10 14:22:03
地址:#49

背景

由于接收同事的项目,项目中使用 PostgreSql, 记录下 常用的一些命令

使用

  1. 连接数据库
psql -h 127.0.0.1 -p 54323 -U userName -d DbName

在 psql 中,切换数据库

\c dbname username serverIP port
  1. 列出所有数据库
mysql: show databases
psql: \l或\list
  1. 切换数据库
mysql: use dbname
psql: \c dbname
  1. 列出当前数据库下的数据表
mysql: show tables
psql: \d
  1. 列出指定表的所有字段
mysql: show columns from table name
psql: \d tablename
  1. 查看指定表的基本情况
mysql: describe tablename
psql: \d+ tablename
  1. 退出登录
mysql: quit 或者\q
psql:\q

【20160901】从输入URL到页面展示完成的过程系列【目录】

从输入URL到页面展示完成的过程中都发生了什么事情?

时间:2016-09-01 23:25:04

这是一道经典的面试题,没有明确的答案,因为往某个方面深入讲解下去,都可以说好多好多。当然面试不同的岗位,可以侧重讲不同的方面。

_这里挖一个大坑,后期慢慢补上。_

分为三个方向

  1. 前端

    • http相关知识
    • 页面渲染
    • 页面加载优化
    • web安全
    • nginx负载均衡
    • CDN
    • HTTP2
    • HTTPS证书校验
  2. 后端

    • web服务器相关知识(Apache/IIS/Nginx/Tomcat)
    • 接收各种协议的网络请求以及相关的各种类型参数的接收
    • MVC架构,开发,优化等
    • 数据库知识,数据库优化
    • 响应给客户端浏览器(JSON,XML,流等)
  3. 网络通讯

    • DNS查询原理
    • OSI七层模型【每一层网络协议,路由原理】
    • TCP/IP四层网络模型
    • TCP三次握手,握手失败处理等
    • 拥塞避免
    • 滑动窗口
    • IP地址划分
    • 协议安全
    • 网络拓扑结构,总线型,树状结构,网状,分布式等

参考过程【侧重HTTP和渲染】

image

参考文章

有一些是移动端页面的文章

  1. 从输入URL到页面加载完成的过程中都发生了什么事情?
  2. 从输入URL到浏览器显示页面发生了什么
  3. 浏览器中输入url后发生了什么
  4. 从输入网址到显示网页的全过程分析
  5. 从输入 URL 到页面加载完的过程中都发生了什么事情?
  6. 当···时发生了什么?

【20161015】Fackbook Yarn包管理器

前端 Yarn 包管理器

时间:2016-10-15 12:48:54
作者:zhongxia

也就两三天没有关注前端新技术,FaceBook 就开源了一个新的包管理器,叫做Yarn。 (搞不懂为什么叫这个名字,和大数据的yarn 重名了)

Yarn 开源后,(10.12~10.15 3天)没有多少天就已经有了 13817 star 了。 看来还是很火爆的。

一、Yarn 干嘛的?

yarn 是一个包管理器, 和npm的作用是一样的,但是解决了一些npm的痛点。

在还没包管理器的时候,JS工程师常常依赖于存储在他们项目中或者放在CDN上面的少量代码段。第一个主要的JS包管理器 npm 在Node.js被引用后不久就搭建起来了,并且迅速成为世界上最受欢迎的包管理器之一。上千个新的开源项目被建立了,工程师们也比以往分享了更多的代码。

二、Npm 的痛点

  • npm安装依赖包速度慢,(用 国内镜像 cnpm 会快很多)
  • 没有网络的时候,不能使用
  • 其他未知

那 yarn 解决了上面这些问题了吗?

  • yarn 下载速度比 npm 快 3~6倍
  • 支持离线下载,下载过的依赖包,会被缓存起来。 下载没有网络的时候也可用
  • 安装依赖包的时候,增加了checksums 做了一个安全验证(不太了解具体作用

小改进

  • 增加下载依赖包的时间
  • 安装依赖报错,提示哪个包中的那个包 报错了【npm 只告诉一个名字,不好找错误】

三、Yarn 的安装与使用

1. 安装

如果有了npm, 那么安装很简单【有安装nodejs,就会有npm, 所以目前直接使用 npm 安装问题不大】

//使用 npm 来安装
npm install -g yarn 

//如果显示了yarn 版本,代表安装成功
yarn --version

2. 初始化

//和 npm init 使用一样
yarn init 

3. 安装,更新,移除依赖包

yarn add jquery

yarn add [email protected]

yarn upgrade jquery 

yarn remove jquery

测试了 --save --save-dev 会报错, 已经已经没有了这两个参数

4. 离线安装

如果之前下载过了,则会缓存起来,缓存起来的可以使用离线安装

yarn add jquery --offline

5. 其他命令

//查看安装的依赖包
yarn ls   

//告诉你,为什么一个依赖被安装到项目中
//yarn why [name] 

四、yarn.lock

yarn.lock 是使用 yarn 安装依赖的时候,自动生成的文件,不要去编辑它。

这个是用来依赖的正确性,快速可靠安装的;是执行cli的时候自动生成的,在项目的根目录下,需要保留!!!!不要编辑它,这是自动生成的

在其他电脑初始化,必须记得把package.json和yarn.lock复制过去,简直就是秒下载【缓存机制】

参考

  1. Yarn:一个新的JavaScript包管理器
  2. yarn - 一个可能取代npm的新型包管理器[Facebook出品,附带中文使用教程]
  3. yarn, 不是又一个 npm 第三方客户端

【20160923】Nginx 开启 gzip和缓存

Nginx 开启 gzip和缓存

时间:2016-09-23 16:42:37

nginx 是一个高性能的 Web 服务器,之前也写过一些关于 nginx 的文章。为了提高博客的响应速度,可以从设置 nginx 的 gzip 和缓存这2方面入手。为字体开启 gzip 和缓存能大大减少带宽的消耗。

开启GZIP配置

# 开启gzip
gzip on;

# 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;

# gzip 压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
gzip_comp_level 2;

# 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;

# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;

# 禁用IE 6 gzip
gzip_disable "MSIE [1-6]\.";

gzip_comp_level 参数

Nginx开启gzip的压缩效果

从图中可以看出,压缩等级在 1 之后的压缩效果都不是很明显,因此设置的时候,设置 1 或者 2即可。

开启成功,则请求资源如下

开启缓存

配置

location ~* ^.+\.(ico|gif|jpg|jpeg|png)$ { 
        access_log   off; 
        expires      30d;
}

location ~* ^.+\.(css|js|txt|xml|swf|wav)$ {
    access_log   off;
    expires      24h;
}

location ~* ^.+\.(html|htm)$ {
        expires      1h;
}

其中的缓存时间可以自己根据需要修改。

关于字体

为静态资源开启缓存能够较少服务器带宽的消耗,特别是在css中使用字体时,同时配合gzip压缩能够大大减少下载字体造成的带宽影响。

设置字体缓存

需要注意的是,字体有很多格式,为所有字体格式设置缓存是很有必要的。

location ~* ^.+\.(eot|ttf|otf|woff|svg)$ {
        access_log   off;
        expires max;
}

启用gzip

只需要为 ttf、otf 和 svg 字体启用 gzip,对其他字体格式进行 gzip 压缩时效果不明显。

gzip_types font/ttf font/otf image/svg+xml
各种字体类型压缩效果可以参考以下测试结果:

ttf字体压缩效果

otf字体压缩效果

svg字体压缩效果

woff字体压缩效果

eot字体压缩效果

可以看到对 woff 和 eot 进行 gzip 压缩效果不好。

字体总结

扩展名 是否压缩 Content-type
.eot application/vnd.ms-fontobject
.ttf font/ttf
.otf font/opentype
.woff font/x-woff
.svg image/svg+xml

【20160909】ACE.js 自定义代码提示,自定义快捷键

ACE.js 自定义代码提示

时间:2016-09-09 14:15:41
作者:zhongxia
源码地址:https://github.com/ajaxorg/ace

Ace.js是一款开源的 web编辑器,内置强大的代码提示,快捷键功能。具体了解看官网介绍。

一、背景

由于在产品中,需要用到 输入 数据库名. 弹出数据库下所有表的提示框, 方便用户的使用。
如图:

解决方案

1、使用ACE.js的提示框,替换提示数据【还未实现

在ACE.js上进行扩展,异步获取到表名数据,然后使用ACE 自带的提示框,提示, 这个是一个比较好的解决方案,但是需要去了解下ACE自定义提示是如何实现的,然后进行扩展。 目前还没有研究透。

参考文章

  1. ACE自定义提示如何实现?

2、监听ACE的change事件[如效果图一样]

如果遇到 xxx.这种情况,就把关键字xxx取出,然后去Ajax获取表名列表。
自己实现一个提示框的插件,然后在指定的位置弹出。

//获取当前焦点的位置(提示框使用 position:fixed)
let renderer = editor.renderer;
var pos = renderer.$cursorLayer.getPixelPosition(this.base, true);
var rect = editor.container.getBoundingClientRect();
pos.top += rect.top - renderer.layerConfig.offset;
pos.left += rect.left - editor.renderer.scrollLeft;
pos.left += renderer.gutterWidth;

【20161025】【收集】优秀模板源码

说明

收集一些优秀的模板源码,方便如何要从头实现一个项目,可以直接从模板里面直接进行快速开发,省去搭建框架的时间。

收集的总类可能包含 Jquery类的模板, BootStrap,React, Vue, Ng , Rn 等等, 不局限于前端。

保存方式

提供一个效果图,然后源码保存在百度云,这里放一个分享链接。

【20161010】Ajax上传文件

Ajax使用FormData对象上传文件

FormData对象,是可以使用一系列的键值对来模拟一个完整的表单,然后使用XMLHttpRequest发送这个"表单"。

强烈推荐推荐看 这篇文章。

在 Mozilla Developer 网站 《使用FormData对象》 有详尽的FormData对象使用说明。

但上传文件部分只有底层的XMLHttpRequest对象发送上传请求,那么怎么通过jQuery的Ajax上传呢?

本文将介绍通过jQuery使用FormData对象上传文件。

使用 <form> 表单初始化FormData对象方式上传文件
HTML代码

<form id="uploadForm" enctype="multipart/form-data">
    <input id="file" type="file" name="file"/>
    <button id="upload" type="button">upload</button>
</form>

javascript代码

$.ajax({
    url: '/upload',
    type: 'POST',
    cache: false,
    data: new FormData($('#uploadForm')[0]),
    processData: false,  // 告诉jQuery不要去处理发送的数据
    contentType: false // 告诉jQuery不要去设置Content-Type请求头
}).done(function(res) {

}).fail(function(res) {

});

这里要注意几点:

  • processData设置为false。因为data值是FormData对象,不需要对数据做处理。
  • <form>标签添加enctype="multipart/form-data"属性。
  • cache设置为false,上传文件不需要缓存。
  • contentType设置为false。因为是由<form>表单构造的FormData对象,且已经声明了属性enctype="multipart/form-data",所以这里设置为false。
  • 上传后,服务器端代码需要使用从查询参数名为file获取文件输入流对象,因为<input>中声明的是name="file"。

如果不是用<form>表单构造FormData对象又该怎么做呢?

使用FormData对象添加字段方式上传文件
HTML代码

<div id="uploadForm">
    <input id="file" type="file"/>
    <button id="upload" type="button">upload</button>
</div>

这里没有<form>标签,也没有enctype="multipart/form-data"属性。

javascript代码

var formData = new FormData();
formData.append('file', $('#file')[0].files[0]);
$.ajax({
    url: '/upload',
    type: 'POST',
    cache: false,
    data: formData,
    processData: false,
    contentType: false
}).done(function(res) {

}).fail(function(res) {

});

这里有几处不一样:

append()的第二个参数应是文件对象,即$('#file')[0].files[0]。
contentType也要设置为‘false’。
从代码$('#file')[0].files[0]中可以看到一个<input type="file">标签能够上传多个文件,
只需要在<input type="file">里添加multiple或multiple="multiple"属性。

兼容性

服务器端读文件

从Servlet 3.0 开始,可以通过 request.getPart()request.getPars()两个接口获取上传的文件。
这里不多说,详细请参考官网教程 Uploading Files with Java Servlet Technology 以及示例 The fileupload Example Application

参考

  1. https://developer.mozilla.org/zh-CN/docs/Web/Guide/Using_FormData_Objects
  2. http://stackoverflow.com/questions/10292382/html-5-formdata-and-java-servlets
  3. https://docs.oracle.com/javaee/7/tutorial/servlets011.htm#BABFGCHB
  4. https://docs.oracle.com/javaee/7/tutorial/servlets016.htm#BABDGFJJ

【20160830】闭包

One Day One Tip 之 闭包

时间:2016-08-30 13:39:33
作者:zhongxia

总结:

概念:
闭包:能够读取其他函数内部变量的函数,在JavaScript中,一个函数return它内部的一个函数。

原理:通过引用变量从而阻止该变量被垃圾回收的机制

优:

  1. 封装私有属性和私有方法,加强封装性,可以达到对变量的保护作用。
  2. 更好的组织代码,比如模块化

缺:

  1. 增加了内存的消耗,并且在某些浏览器下,由于垃圾回收机制不同,有可能导致内存溢出
  2. 增加复杂度
  3. 由于闭包内部变量优先级高于外部变量,所以多查找作用域链中的一个层次,就会在一定程度上影响查找速度。

零、所需知识

要理解闭包,首先必须理解 JavaScript 特殊的变量作用域。
变量的作用域无非就是两种: 全局变量局部变量

JavaScript语言的特殊之处,就在于 函数内部可以直接读取全局变量。
不使用 var 声明的变量,则为全局变量。 b = 100;

function fn(){
  var a = b = 1;  
  // ==> var a = window.b = 1;  // a 是局部变量   b 是全局变量
}
fn();
console.log("b = ",b); // 1
console.log("a = ",a); //VM783:1 Uncaught ReferenceError: a is not defined

函数外部无法访问局部变量。 因此在外部,访问 a 变量 报错。 而 b 变量是 全局变量,因此可以访问到。

一、闭包是什么

闭包是概念?
闭包是指某种程序语言中的代码块允许一级函数存在并且在一级函数中所定义的自由变量能不被释放,直到一级函数被释放前,一级函数外也能应用这些未释放的自由变量。

我的理解就是:闭包就是能够读取其他函数内部变量的函数
由于在JavaScript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单的理解成 『定义在一个函数内部的函数
本质上: 闭包就是将函数内部和外部链接起来的一座桥梁

//eg: example
function a(x){
  var tmp = 10;
  return function(y){
     return (x+y)+(++tmp);
  }
}
var b = a(10);
b(5);  //26, 每执行一次 tmp 加 1

因为 a() 执行后,返回 的 方法 b, 内部引用了 tmp 变量, 导致 tmp 变量的标记+1, 垃圾回收机制就不会清除 tmp这个变量。
然后外部就可以继续访问到 tmp 变量。

二、闭包的作用

  1. 读取函数内部的变量
  2. 让内部的变量始终保持在内存中
  3. 设计私有方法和变量【封装框架的时候更明显,典型的如Jquery】
var jQuery = (function(){  

    var jQuery = function(){  
    //TODO  
    }  
    return (window.$ = window.jQuery = jQuery);       
});  

三、闭包的优缺点

优点

  1. 延长作用域链。
  2. 更好的组织代码,比如模块化,异步代码转同步等。
  3. 加强封装性,可以打到对变量的保护(第二点的加强)
  4. 处理异步造成的变量不能即时传递的问题

缺点

  1. 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除
  2. 增加内存的消耗
  3. IE浏览器上 因为回收机制,有内存溢出的风险
  4. 增加了代码复杂度

四、闭包用法实战

1. 对fun的计算方式进行定制

实际使用的时候,闭包可以创建出非常优雅的设计,允许对funarg上定义的多种计算方式进行定制。如下就是数组排序的例子,它接受一个排序条件函数作为参数:

[1, 2, 3].sort(function (a, b) {
  ... // 排序条件
});

同样的例子还有,数组的map方法是根据函数中定义的条件将原数组映射到一个新的数组中:

[1, 2, 3].map(function (element) {
  return element * 2;
}); // [2, 4, 6]

2. 函数式参数

使用函数式参数,可以很方便的实现一个搜索方法,并且可以支持无限制的搜索条件:

someCollection.find(function (element) {
  return element.someProperty == 'searchCondition';
});

还有应用函数,比如常见的forEach方法,将函数应用到每个数组元素:

[1, 2, 3].forEach(function (element) {
  if (element % 2 != 0) {
    alert(element);
  }
}); // 1, 3

顺便提下,函数对象的 apply 和 call方法,在函数式编程中也可以用作应用函数。 apply和call已经在讨论“this”的时候介绍过了;这里,我们将它们看作是应用函数 —— 应用到参数中的函数(在apply中是参数列表,在call中是独立的参数):

(function () {
  alert([].join.call(arguments, ';')); // 1;2;3
}).apply(this, [1, 2, 3]);

3. 延迟调用

闭包还有另外一个非常重要的应用 —— 延迟调用:

var a = 10;
setTimeout(function () {
  alert(a); // 10, after one second
}, 1000);

4. 回调函数

//...
var x = 10;
// only for example
xmlHttpRequestObject.onreadystatechange = function () {
  // 当数据就绪的时候,才会调用;
  // 这里,不论是在哪个上下文中创建
  // 此时变量“x”的值已经存在了
  alert(x); // 10
};
//...

5. 创建封装的作用域来隐藏辅助对象:

var foo = {};

// 初始化
(function (object) {

  var x = 10;

  object.getX = function _getX() {
    return x;
  };

})(foo);

alert(foo.getX()); // 获得闭包 "x" – 10

参考文章

  1. 阮一峰-学习Javascript闭包(Closure)
  2. 浅析jQuery核心架构中应用Closure(闭包)的设计模式
  3. 用一道面试题考察对闭包的理解
  4. 深入理解JavaScript系列(16):闭包(Closures)

【20160923】nginx启动,重启,关闭命令

nginx启动,重启,关闭命令

时间:2016-09-23 16:52:22

启动

nginx -c nginx配置文件地址   

停止

ps -ef | grep nginx

//从容停止Nginx:
kill -QUIT 主进程号

//快速停止Nginx:
kill -TERM 主进程号

//强制停止Nginx:
pkill -9 nginx

eg:

nginx 命令, 使用默认的配置,启动 nginx

重启

nginx -s reload

修改了nginx的配置文件, 需要重启下 nginx服务。

平滑重启

如果更改了配置就要重启Nginx,要先关闭Nginx再打开?不是的,可以向Nginx 发送信号,平滑重启。 平滑重启命令:kill -HUP 主进称号或进程号文件路径 或者使用/usr/nginx/sbin/nginx -s reload

注意:修改了配置文件后最好先检查一下修改过的配置文件是否正 确,以免重启后Nginx出现错误影响服务器稳定运行。判断Nginx配置是否正确命令如下:

//检查指定的nginx配置文件,是否正确
nginx -t -c /usr/nginx/conf/nginx.conf  

//检查默认的nginx配置文件
/usr/nginx/sbin/nginx -t

【20161026】网站静态化方案(一)静态化原理

网站静态化方案(一)静态化原理

时间:2016-10-26 15:52:04
作者:zhongxia

网站静态化,看产品或者网站的需求,不要为了静态化而静态化。
这里主要讲一些原理,没有具体的实例。

一、 为什么要静态化?

  1. 加快页面打开浏览速度,静态页面无需连接数据库打开速度较动态页面有明显提高;
  2. 有利于搜索引擎优化SEO,Baidu、Google都会优先收录静态页面,不仅被收录的快还收录的全;
  3. 减轻服务器负担,浏览网页无需调用系统数据库;
  4. 网站更安全,HTML页面不会受php相关漏洞的影响; 观看一下大一点的网站基本全是静态页面,而且可以减少攻击,防sql注入。

当然有好处,也有不足?

  1. 信息不同步。只有重新生成HTML页面,才能保持信息同步。
  2. 服务器存储问题。数据一直增加,静态HTML页面会不断增加,会占用大量的磁盘。需要考虑这个问题
  3. 静态化算法的精密性。要良好的处理数据与网页模板,及各种文件链接路径的问题,这就要求我们在静态化的算法中考虑到方方面面。稍有细小疏忽,将导致生成的页面中存在这样或那样的错误链接,甚至存在死链。因此,我们必须恰到好处的解决这些问题。既不能增加算法的可能性,又要照顾到方方面面。做到这一点,的确不容易。

二、PHP静态化

参考文章:《分享常见的几种页面静态化的方法》

PHP静态化的简单理解就是使网站生成页面以静态HTML的形式展现在访客面前,PHP静态化分纯静态化伪静态化,两者的区别在于PHP生成静态页面的处理机制不同。

纯静态化:PHP生成HTML文件
伪静态化:把内容存放在nosql内存(memcached),然后访问页面的时候,直接从内存里面读取。

大型动态网站静态化

参考文章:《大型网站的静态化处理》

大型网站(高访问量,高并发量),如果是静态网站,可以通过扩展足够多的 web服务器,然后支持超大规模的并发访问。

如果是一个动态的网站,特别是使用到了数据库的网站是很难做到通过增加web服务器数量的方式来有效的增加网站并发访问能力的。比如淘宝,京东。

静态化方案:

大型静态网站之所以能够快速响应高并发,因为他们尽量把动态网站静态化。

  1. js,css,img等资源,服务端合并在返回
  2. CDN 内容分发网络技术【网络传输的效率跟距离长短有关系的原理,通过算法,计算最近的静态服务器节点】
  3. web服务器动静结合。页面有一部分是一直不变的,比如 header, footer 部分。 那么这一部分是否可以放在缓存。web服务器 apache或ngnix, appache有一个模块叫做ESI,CSI。能够动静拼接。把静态的部分缓存在 web服务器上,然后和服务器返回的动态页面拼接在一起。
  4. 浏览器实现动静结合,前端MVC。

【20160925】Chrome 打印PDF技巧

Chrome 打印PDF技巧

原文地址:#22 欢迎star
本教程,使用Mac电脑进行演示。 常规的Chrome打印文件会比较大。 只有一个A4页面的内容,打印出来居然有7M,吓死了。 下面介绍如何不用第三方工具来缩放PDF大小。

如图:打印该页面

大小

如何缩放?

可以采用 black & white 和 reduce size 这两种选一种模式, black & white 会造成一部分外观会没掉。 reduce size 就是压缩大小

PDF大小大大的减少了。

【20160910】Mac NW.js 环境安装 和 打包

Mac Nw.js 环境搭建 和 打包

时间:2016-09-10 01:31:22
作者:zhongxia
本文章,以Mac Os 系统为例子。

一、安装NW

安装的方式有两种

1. 下载安装包 官网下载 nw.app 的安装包

把安装包放到 Application 的文件夹里面, 可以双击 nwjs.app ,打开应用。

效果图如下:

设置别名,方便使用

//1. 打开设置别名的文件
vim ~/.bash_profile 

//2.在文件里面添加 上下面这一句
alias nw="/Applications/nwjs.app/Contents/MacOS/nwjs"

//3.使别名生效
source ~/.bash_profile

此时,在命令行输入 nw , 等同双击打开应用

[如果使用了zsh, 可以在 vim ~/.zshrc 里面添加别名 【本人Mac上,别名需要在这里设置才起作用】]

如何使用 nw 打开 项目

nw .    //当前目录下的 package.json  
nw ./xxx/package.json  //其他目录下的package.json 

2. sudo npm install -g nw

由于下载nw,迟迟下载不下来,并且执行 nw 的时候, 一直报错。 后面采用第一种方式。 理论上来讲, npm 上安装好之后, 输入 nw 就可以用了。 【具体需要测试下】

2016-09-10 10:58:36
今天测试了一下是可以用的, 但是推荐使用 npm 包, nwjs 来管理 nw 的版本

npm install -g nwjs  

//列出已安装的 nw 版本
nw ls

//安装指定版本的 nw
nw install 0.17.0    

//使用指定版本的nw
nw use 0.17.0 

打包项目

在Mac 下打包 应用为一个 demo.app 很简单。

//1. 把nwjs.app 复制到你记得住的地方,比如项目的根目录,或者其他
cp -R /Applications/nwjs.app ./test.app 

//2. 把项目的代码打包成  一个 nw 文件 【在项目文件夹里面执行这一句,路径自己根据情况修改】
zip -r ../test.app/Contents/Resources/app.nw  * 

完成, 双击 test.app 即可打开程序

参考文章

  1. 使用nw.js制作桌面应用程序

【20160927】【PHP】微信录音文件转存到自己服务器

微信的录音文件上传到微信服务器上,只能保存三天。 因此需要做一个转存到自己服务器,或者七牛云的操作。

转存到自己服务器

  1. 调用微信JSSDK API 录音, 录音结束,上传到微信服务器,获取录音文件的 media_id
  2. 根据 media_id 下载录音文件(amr)格式
  3. 转存到自己服务器(amr需要转码成mp3) 或者 七牛云(有转码功能)

步骤1代码

     ...
      /**
       * 开始录音[省略了一部分代码]
       */
      startRecord: function() {
        var that = this;
        if (!that._startRecordFlag) {
          typeof wx !== "undefined" && wx.startRecord({
            success: function(res) {
              Logger.log("res", res)
              if (res.errMsg == 'startRecord:ok') {
                Logger.log("正在开始录音....")
                that._startTime = new Date().getTime();
              }
            }
          });
        }
      },

      /**
       * 结束录音,并上传
       */
      stopRecord: function() {
        that._startRecordFlag = false;
        typeof wx !== "undefined" && wx.stopRecord({

          success: function(res) {
            //上传录音
            wx.uploadVoice({
              localId: res.localId,
              isShowProgressTips: 1,
              success: function(resUpload) {
                //下载录音文件到服务器,转存起来
                Model.downloadRecordAudio(resUpload.serverId, function(result) {
                  console.log(resUpload.serverId, result.path)
                  that.attachment = result.path;
                  // that.attachment = resUpload.serverId;
                  that.stopRecordCallback && that.stopRecordCallback();
                })
              }
            });
          }
        });
      },
...

步骤2代码

<?php
//处理方法,
upload();

//media_id为微信jssdk接口上传后返回的媒体id
function upload(){
    $media_id = $_POST["media_id"];
    $access_token = getAccessToken();

    $path = "./weixinrecord/";   //保存路径,相对当前文件的路径
    $outPath = "./php/weixinrecord/";  //输出路径,给show.php 文件用,上一级

    if(!is_dir($path)){
        mkdir($path);
    }

    //微信上传下载媒体文件
    $url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token={$access_token}&media_id={$media_id}";

    $fileName = "wxupload_".time().rand(1111,9999);

    $mp3Path = $path."/".$fileName.".mp3";
    $amrPath = $path."/".$fileName.".amr";

    //下载微信录音文件
    downAndSaveFile($url,$amrPath);

    //转换成mp3文件,TODO:一直没有转换成mp3,麻烦定位下
    if(file_exists($mp3Path) != true){
        // $command = "ffmpeg -i $amrPath $mp3Path & rm $mp3Path";
        $command = "ffmpeg -i $amrPath $mp3Path";
        system($command,$error);
    }

    $data["path"] = $outPath.$filename;
    $data["msg"] = "download record audio success!";
    // $data["url"] = $url;

    echo json_encode($data);
}

//获取Token
function getAccessToken() {
    //  access_token 应该全局存储与更新,以下代码以写入到文件中做示例
    $data = json_decode(file_get_contents("./access_token.json"));
    if ($data->expire_time < time()) {
        $appid = "youappid";  //自己的appid
        $appsecret = "youappsecret";  //自己的appsecret
        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$appsecret}";
        $res = json_decode(httpGet($url));
        $access_token = $res->access_token;
        if ($access_token) {
            $data->expire_time = time() + 7000;
            $data->access_token = $access_token;
            $fp = fopen("./access_token.json", "w");
            fwrite($fp, json_encode($data));
            fclose($fp);
        }
    }
    else {
        $access_token = $data->access_token;
    }
    return $access_token;
}

//HTTP get 请求
function httpGet($url) {
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_TIMEOUT, 500);
    curl_setopt($curl, CURLOPT_URL, $url);

    $res = curl_exec($curl);
    curl_close($curl);

    return $res;
}

//根据URL地址,下载文件
function downAndSaveFile($url,$savePath){
    ob_start();
    readfile($url);
    $img  = ob_get_contents();
    ob_end_clean();
    $size = strlen($img);
    $fp = fopen($savePath, 'a');
    fwrite($fp, $img);
    fclose($fp);
}
?>

步骤3代码【略】

目前没有使用七牛云,因此该部分代码,参考七牛云官网

【20160905】webpack sourceMap 使用说明

webpack sourceMap 使用说明

时间:2016-09-05 15:23:30
作者:zhongxia
webpack文档地址:http://webpack.github.io/docs/build-performance.html#sourcemaps

image

总结

在开发环境,或者生产环境中,如果出现错误了,在浏览器中,因为代码从被Babel从JSX变成ES5的,代码调试起来很痛苦,因此webpack有了一个代码映射,把转换后的代码映射到之前自己写的代码。

英语水平有限,下面翻译可能存在问题,请帮忙指出。

devtool可选值:

  • source-map 【用于生产环境】
  • eval-source-map
  • eval-cheap-module-source-map
  • eval-cheap-source-map
  • eval 【建议开发环境用这个】
module.exports = {
  devtool: 'eval',
  ...
}

Perfect SourceMaps are slow.

越好的源码映射,越慢

source-map

devtool: "source-map" cannot cache SourceMaps for modules and need to regenerate complete SourceMap for the chunk. It’s something for production.

source-map 不能为 模块和需要重新生成的代码块 缓存SourceMaps,它适用于 生产环境。

eval-source-map

devtool: "eval-source-map" is really as good as devtool: "source-map", but can cache SourceMaps for modules. It’s much faster for rebuilds.

eval-source-mapsource-map 差不多,但是 可以为模块 缓存它可以更快的重建SourceMaps,它可以更快的重建SourceMaps

eval-cheap-module-source-map

devtool: "eval-cheap-module-source-map" offers SourceMaps that only maps lines (no column mappings) and are much faster.

eval-cheap-module-source-map 只为行(没有列映射)提供SourceMaps 并且 速度更快(相对于 source-map, eval-source-map)

eval-cheap-source-map

devtool: "eval-cheap-source-map" is similar but doesn’t generate SourceMaps for modules (i.e., jsx to js mappings).

eval-cheap-source-mapeval-cheap-module-source-map 相似,但是不为模块 生成 SourceMaps(eg:jsx 到 js 的映射)

eval

devtool: "eval" has the best performance, but it only maps to compiled source code per module. In many cases this is good enough. (Hint: combine it with output.pathinfo: true.)

eval有最好的性能,但是它只映射到每个模块编译源代码,在更多情况下是足够用的(提示:与 output.pathinfo:true 结合使用)

相关知识
output.pathinfo

Include comments with information about the modules.

require(/* ./test */23)

Do not use this in production.

Default: false

The UglifyJsPlugin use SourceMaps to map errors to source code. And SourceMaps are slow. As you should only use this in production, this is fine. If your production build is really slow (or doesn’t finish at all) you can disable it with new UglifyJsPlugin({ sourceMap: false }).

UglifyJsPlugin会让 SourceMaps 映射到源码出现错误,速度变慢。所以把UglifyJsPlugin用于生产环境,这是很好的。
如果你生产环境构建很慢(或者玩不成),可以用 new UglifyJsPlugin({ sourceMap: false }). 来禁用sourceMap。

【20161008】【CSS】Table td 不换行 超出省略号

问题

常规的给td 设置样式

table td{
  overflow:hidden;
  text-overflow:ellipsis;
}

表格该换行还是继续换行, 该占多大宽度还是占多大。 这个很坑爹,为什么不起作用呢?

CSS控制文字超出则显示 ...

CSS控制文本超出指定宽度后用省略号代替,CSS控制文本不换行。
一般的文字截断(适用于内联与块):

.text-overflow {
    display:block;/*内联对象需加*/
    width:31em;
    word-break:keep-all;/* 不换行 */
    white-space:nowrap;/* 不换行 */
    overflow:hidden;/* 内容超出宽度时隐藏超出部分的内容 */
    text-overflow:ellipsis;/* 当对象内文本溢出时显示省略标记(...) ;需与overflow:hidden;一起使用。*/
}

Table td 强制不换行,超出 则 显示 ...

对于表格文字溢出的定义:
对于表格超出范围显示省略号

table{
    width:30em;
    table-layout:fixed;/* 只有定义了表格的布局算法为fixed,下面td的定义才能起作用。 */
}
td{
    width:100%;
    word-break:keep-all;/* 不换行 */
    white-space:nowrap;/* 不换行 */
    overflow:hidden;/* 内容超出宽度时隐藏超出部分的内容 */
    text-overflow:ellipsis;/* 当对象内文本溢出时显示省略标记(...) ;需与overflow:hidden;一起使用。*/
}

table-layout

描述
automatic 默认。列宽度由单元格内容设定。
fixed 列宽由表格宽度和列宽度设定。
inherit 规定应该从父元素继承 table-layout 属性的值。

效果

需要你注意的是,这个CSS样式只对单行的文字的效,如果你想把它用在多行上,也只有第一行有作用的。 这个写法只有IE会有“...”,

其它的浏览器文本超出指定宽度时会隐藏。

以上问题可以解决

  • 使用CSS如何控制文本换行?
  • 使用CSS如何控制文本不换行?
  • 使用CSS如何控制文本超出范围后显示省略号?
  • 使用CSS如何控制文本超出范围后隐藏?
  • Table td 如何强制不换行?

【20160914】Chrome远程调试Android上的多点触控操作

Chrome远程调试Android上的多点触控操作

时间:2016-09-14 09:41:53
作者:zhongxia
背景:需要在页面上实现多点触控,但是在PC端上的Chrome上,模拟设备,目前没有找到实现多点触控的方法。因此只能找一下是否有远程调试真机页面的功能。 这里就整理以下,如何使用用Chrome远程调试真机访问的页面

需求

要开始远程调试,你需要:

  • 安装 Chrome 32 或者之后的版本。
  • 连接安卓设备用的 USB 线缆。
  • 对于通过浏览器调试:安卓 4.0 以上并且安装了 Chrome for Android。
  • 对于通过应用调试:安卓 4.4 以上并且应用包括可用于调试的 WenView 组件。
  • 提示:远程调试需要你电脑端的 Chrome 版本要高于安卓端的版本。想更好地使用此功能,请使用电脑端的 Chrome Canary (Mac/Windows) 或者 Dev channel 发行版(Linux)。

说白了,android机子一部(微信不行),PC端chrome浏览器,USB线

设置安卓设备

请按照以下说明来设置安卓设备:

1. 打开 USB 调试选项

不同的手机,打开开发者模式的方式不一样。
这边以小米手机为例,默认情况下,开发者模式是隐藏的。

  • 打开设置-》关于手机-》MIUI版本-》点击五六次,提示出现开发者模式
  • 设置-》更多设置-》开发者模式--》开启USB调试

2. 连接你的设备

将你的安卓设备和电脑用 USB 线连接起来。

注意:如果你在 Windows 下进行开发,那么你需要为你的安卓设备安装驱动。具体可以参考安卓开发者网站上的 OEM USB Drivers

在 Chrome 中找到设备
在安卓设备上设置好远程调试后,在 Chrome 中找到你的设备。

在电脑端的 Chrome 里,在地址栏输入 chrome://inspect。进入后确认 Discover USB devices 已经勾选了:

提示:你也可以从 Chrome menu > More tools > Inspect Devices 来进入 chrome://inspect
在你的设备上,会跳出一个警告,告诉你是否要允许在电脑端进行 USB 调试。选择 OK。

注意:在远程调试时, Chrome 会阻止你的设备进入休眠状态。该特性对于调试相当有用,但在安全性上有所欠缺。所以在调试的时候要注意看好你的手机!

在电脑端,打开选项卡并启用 WebViews 调试后,chrome://inspect 页面会显示全部已连接的设备。

从 chrome://inspect 也卖弄查看已连接的设备

如果从 chrome://inspect 页面查找设备时遇到了问题,请参考 Troubleshooting 章节。

调试远程浏览器

在页面 chrome://inspect 上,你可以加载 DevTools 并且调试你的远程浏览器。

要开始调试,请点击你希望调试的浏览器选项卡下面的 inspect。

接着你的电脑会加载新的 DevTools。在新的 DevTools 上,你可以在你的安卓设备上和选中的浏览器实时交互。

左边是手机上页面的实时情况,右边是Chrome开发工具,调试按照PC端怎么调试就怎么来。

注意:你设备的 Chrome 版本将会决定远程调试中 DevTools 的版本。由于这个原因,你在远程调试时使用的 DevTools 可能和你平常使用的不大一样。

调试提示

下面是使用远程调试功能的一些提示:

  • 按 F5(或者在Mac上 Cmd + r)来重新加载远程页面。
  • 让设备的网络处于打开状态。使用 Network 面板来查看实际移动设备的网络流状态。
  • 使用 Timeline 面板来分析提交数据和 CPU使用状态。在移动设备上运行的程序通常会比在开发机器上运行的要慢一些。
  • 如果你是在本地的 web 服务器上运行的,使用端口转发或者虚拟主机映射 技术来让设备访问你的站点。

参考文章

  1. 《在安卓设备上使用 Chrome 远程调试功能》

【20161104】CSS命名方式=》BEM

时间:2016-11-04 20:04:53
原文地址:#48

一、背景

挺早就听说过BEM了,也大概的知道怎么用,但是具体 BEM 指啥,具体有啥要求,还不是很清楚,然后今天就学习了下。

二、BEM(Block,Element,Modifier)

BEM的意思就是块(block)、元素(element)、修饰符(modifier),是由Yandex团队提出的一种前端命名方法论。这种巧妙的命名方法让你的CSS类对其他开发者来说更加透明而且更有意义。BEM命名约定更加严格,而且包含更多的信息,它们用于一个团队开发一个耗时的大项目。

重要的是要注意,我使用的基于BEM的命名方式是经过Nicolas Gallagher修改过的。这篇文章中介绍的这种命名技术并不是原始的BEM,但却是一个我更喜欢的改进版。无论实际使用了什么样的符号,它们其实都是基于同样的BEM原则。

命名约定的模式如下:

.block{}
.block__element{}
.block--modifier{}
  • .block 代表了更高级别的抽象或组件。
  • .block__element 代表.block的后代,用于形成一个完整的.block的整体。
  • .block--modifier代表.block的不同状态或不同版本。
    之所以使用两个连字符和下划线而不是一个,是为了让你自己的块可以用单个连字符来界定,如:
.site-search{} /* 块 */
.site-search__field{} /* 元素 */
.site-search--full{} /* 修饰符 */

三、总结

  • B: block ,某一块展示/功能区域(div, 比如: nav
  • E: Element, 这块展示/功能区域(div)里面的某个元素,比如: nav__item
  • M:Modifier, 某个元素或者某个块的状态,比如 nav--hide, nav__item--open 啥的

例子:

B:header-tabs //名字随便
E:header-tabs__item //多个tab选项
M:header-tabs__item--active //选中状态

四、参考文章

  1. BEM —— 源自Yandex的CSS 命名方法论

【20161118】再谈 CSS 预处理器

时间:2016-11-18 10:33:40
原文地址:《再谈 CSS 预处理器》

这个是目前看过文章中,最完整详细的介绍了 less, sass ,stylus 三者的异同点,因此在此记录下。
Less, Sass, Stylus 功能上 大体相同, 具体喜欢用哪一个,或者一个都不用, 这个看个人喜好。

CSS预处理器是什么?

CSS 预处理器是什么?一般来说,它们基于 CSS 扩展了一套属于自己的 DSL,来解决我们书写 CSS 时难以解决的问题:

  • 语法不够强大,比如无法嵌套书写导致模块化开发中需要书写很多重复的选择器;
  • 没有变量和合理的样式复用机制,使得逻辑上相关的属性值必须以字面量的形式重复输出,导致难以维护。

所以这就决定了 CSS 预处理器的主要目标:提供 CSS 缺失的样式层复用机制、减少冗余代码,提高样式代码的可维护性。这不是锦上添花,而恰恰是雪中送炭。

目前最主流的三个预处理器 LessSassStylus(按字母顺序排名)

总结

我(原文作者)个人认为,Less 从语言特性的设计到功能的健壮程度和另外两者相比都有一些缺陷,但因为 Bootstrap 引入了 Less,导致 Less 在今天还是有很多用户。用 Less 可以满足大多数场景的需求,但相比另外两者,基于 Less 开发类库会复杂得多,实现的代码会比较脏,能实现的功能也会受到 DSL 的制约。比 Stylus 语义更清晰、比 Sass 更接近 CSS 语法,使得刚刚转用 CSS 预编译的开发者能够更平滑地进行切换。当初 Sass 并不支持 SCSS 语法,使得转投 Sass 成本较高,所以 Alexis Sellier 才萌生开发一个更「CSS」的预处理器的念头。大获成功以后反过来影响到了 Sass,迫使其也支持类似 CSS 语法的 SCSS。另外,Less 支持浏览器端编译,这无疑降低了开发门槛,使得很多非专业的开发者能够更快地上手(对于一些个人项目来说,能让项目跑起来就行,对前端的性能并没有专业工程师那么高的要求)。

Sass 在三者之中历史最久,也吸收了其他两者的一些优点。从功能上来说 Sass 大而全,语义明晰但是代码很容易显得累赘。主项目基于 Ruby 可能也是一部分人不选择它的理由(Less 开始也是基于 Ruby 开发,后来逐渐转到 less.js 项目中)。 Sass 有一个「事实标准」库——Compass,于是对于很多开发者而言省去了选择类库的烦恼,对于提升开发效率也有不小的帮助。

Stylus 的语法非常灵活,很多语义都是根据上下文隐含的。基于 Stylus 可以写出非常简洁的代码,但对使用团队的开发素养要求也更高,更需要有良好的开发规范或约定。Stylus 是前 Node.js 圈第一大神 TJ Holowaychuk 的作品,虽然他已经弃坑了,但是仍然有不小的号召力。和 Sass 有 Compass 类似,Stylus 有一个官方开发的样式库 nib,同样提供了不少好用的 mixin。对于比较有经验的开发者,用 Stylus 可能更会有一种畅快的感觉。总的来说用一个词形容 Stylus 的话,我会用「sexy」。

总的来说,三种预处理器百分之七八十的功能是类似的。Less 适合帮助团队更快地上手预处理代码的开发,而 Sass 和 Stylus 的差异更在于口味。比如有的人喜欢 jQuery 用一个 $ 做大部分的事,而另一些人觉得不一样的功能就该有明确的语义上的差别。在这里我不会做具体的推荐。当然,再次声明一下由于我个人接触 Less 开发比较多,所以可能遇到的坑也多一些,文中没有列出 Sass 和 Stylus 的问题并不代表他们没有。

【20161103】webpack 热更新

时间:2016-11-03 10:50:54
地址:#45

webpack热更新

一、要求

  1. 局部刷新修改的地方

二、如何配置

1、配置 webpack.config.js

下面最重要的是两个地方

  • webpack入口文件,加上 'webpack-dev-server/client' 【必选】 , 'webpack/hot/only-dev-server', 【可选】

  • loader加载器, js|jsx 需要加上 react-loader 在最前面

   {
      test: /\.(js|jsx)$/,
      loader: 'react-hot-loader!babel-loader',
      exclude: /node_modules/
    },

2、配置node的web server服务器

//热更新的关键一句
 app.use(require('webpack-hot-middleware')(compiler))

完整的配置

'use strict';
var path = require('path')
var webpack = require('webpack')

module.exports = {
  devtool: 'source-map', 
  cache: true,
  entry: {
    app: [
      'webpack-dev-server/client',
      'webpack/hot/only-dev-server',
      path.join(__dirname, 'src/index')
    ],
    common: path.join(__dirname, 'src/common')
  },
  output: {
    path: path.join(__dirname, 'static'),
    filename: '[name].bundle.js',
    chunkFilename: 'chunk/[chunkhash:8].chunk.js',
    publicPath: '/FileManage/static/'
  },
  plugins: [
    new webpack.DefinePlugin({
      __DEV__: String(true)
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    new webpack.optimize.CommonsChunkPlugin('vender.js')
  ],
  module: {
    loaders: [{
      test: /\.(js|jsx)$/,
      loader: 'react-hot-loader!babel-loader',
      exclude: /node_modules/
    }, {
      test: /\.css$/,
      loader: 'style-loader!css-loader'
    }, {
      test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)(\?v=[\d\.]+)?$/,
      loader: 'file-loader?name=files/[hash:8].[ext]'
    }, {
      test: /\.json$/,
      loader: 'json-loader'
    }, {
      test: /\.less$/,
      loader: 'style!css!less'
    }]
  },
  resolve: {
    //自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名
    extensions: ['', '.js', '.jsx'],
    root: [
      path.join(__dirname, '/src'),
      path.join(__dirname, '/'),
      path.join(__dirname, '../CommonComponent'),
      path.resolve(__dirname, '../BFD-UI')
    ],
    alias: {
      Loading: 'common/components/Loading/index.js',
    }
  }
}

server.js

const express = require('express')
const debug = require('debug')('app:server')
const webpack = require('webpack')
const webpackConfig = require('../build/webpack.config')
const config = require('../config')

const app = express()
const paths = config.utils_paths

app.use(require('connect-history-api-fallback')())

// ------------------------------------
// Apply Webpack HMR Middleware
// ------------------------------------
if (config.env === 'development') {
  const compiler = webpack(webpackConfig)
  app.use(require('webpack-dev-middleware')(compiler, {
    publicPath: webpackConfig.output.publicPath,
    contentBase: paths.client(),
    hot: true,
    quiet: config.compiler_quiet,
    noInfo: config.compiler_quiet,
    lazy: false,
    stats: config.compiler_stats
  }))
  app.use(require('webpack-hot-middleware')(compiler))
  app.use(express.static(paths.client('static')))
} else {
  app.use(express.static(paths.dist()))
}

module.exports = app

【20160924】【CSS】Sass理解

Sass入门指南

时间:2016-09-24 22:56:12
作者:zhongxia
这里就不讲解Sass的安装以及语法了,因为参考文章中,阮一峰老师写的很详细,另外一篇也写的很不错,直接学习即可。 这里主要写下自己的看法,或者不懂的地方。

常规的CSS是不支持变量,函数,以及一些简单的判断,计算等。只有单纯的描述,如果多个地方使用同一个颜色,或者字体大小,要修改起来比较麻烦。

因此,就有人给CSS加入了一些编程元素,这被叫做 "CSS预处理器"(css preprocessor)

常见的 CSS预处理器,有Less, Sass , Stylus

强调

摘自《sass入门指南》

  • sass不是css的替代品,它只是让css变得更加高效、可维护
  • 永远不要修改生成后的css
  • 部署到线上的是生成的css文件,不是sass文件

sass的工作流如下图

Sass文件格式

Sass 有两种文件格式

.sass文件

.sass文件是缩进式的写法,对格式要求比较严谨,末尾不能有分号, 属性和值之间有一个空格

.test
    margin: 5px 10px
    font-size: 14px
    color: #333

.scss文件

.scss文件 和 css 一致

.test {
    margin: 5px 10px;
    font-size: 14px;
    color: #333;
}

Sass 的 import 导入功能

css有一个不太常用的特性,即@import导入功能,它允许在一个css文件中导入其他css文件。然而,结果是只有执行到@import规则时,浏览器才会去下载其他css文件,这会导致页面样式加载特别慢,从而容易出现页面闪的问题。

但是 sass中,使用 import则可以规避这个问题, 因为sass最终会生成一个CSS文件,在生成的时候,会把导入的CSS 给合并到CSS文件里面

在使用@import导入sass文件时,可以省略sass文件的后缀名.sass或.scss,例如:

//a.scss
body {
    background-color: #f00;
}
//style.scss
@import "a";
div {
    color: #333;
}

编译后的style.css文件内容如下:

body {
    background-color: #f00;
}
div {
    color: #333;
}

参考文章

  1. SASS用法指南
  2. sass入门指南

【20160904】【FEX】从输入 URL 到页面加载完成的过程中都发生了什么事情?

创建时间:2016-09-05 00:07:17
原文地址:http://fex.baidu.com/blog/2014/05/what-happen/

阅读请出门左转 原文地址

image

总结

这一篇文章写的知识基本都是很底层的东西,权当增长见识, 因为单纯的前端,这里的内容就需要花费很大的精力, 才有可能『搞懂』。
【这两天偷懒,没有自己自己去整理出文章,转载一些优秀的文章,放到这里】

目录:

背景

image

第一个问题:从输入 URL 到浏览器接收的过程中发生了什么事情?

  • 从触屏到 CPU
  • CPU 内部的处理
  • 从 CPU 到操作系统内核
  • 从操作系统 GUI 到浏览器
  • 扩展学习

第二个问题:浏览器如何向网卡发送数据?

  • 从浏览器到浏览器内核
  • HTTP 请求的发送
  • DNS 查询
  • 通过 Socket 发送数据
  • Socket 在内核中的实现
  • 底层网络协议的具体例子
  • 扩展学习

第三个问题:数据如何从本机网卡发送到服务器?

  • 从内核到网络适配器(Network Interface Card)
  • 连接 Wi-Fi 路由
  • 运营商网络内的路由
  • 主干网间的传输
  • IDC 内网
  • 服务器 CPU
  • 扩展学习

第四个问题:服务器接收到数据后会进行哪些处理?

  • 负载均衡
  • LVS
  • 反向代理
  • Web Server 中的处理
  • 进入后端语言
  • Web 框架(Framework)
  • 读取数据
  • 扩展学习

第五个问题:服务器返回数据后浏览器如何处理?

  • 从 01 到字符
  • 外链资源的加载
  • JavaScript 的执行
  • 从字符到图片
  • 跨平台 2D 绘制库
  • GPU 合成
  • 扩展学习

第六个问题:浏览器如何将页面展现出来?

  • Framebuffer
  • 从内存到 LCD
  • LCD 显示
  • 扩展学习

本文所忽略的内容

为了编写方便,前面的介绍中将很多底层细节实现忽略了,比如:

内存相关

  • 堆,这里的分配策略有很多,比如 malloc 的实现
  • 栈,函数调用,已经有很多优秀的文章或书籍介绍了
  • 内存映射,动态库加载等
  • 队列几乎无处不在,但这些细节和原理没太大关系

各种缓存

  • CPU 的缓存、操作系统的缓存、HTTP 缓存、后端缓存等等

各种监控

  • 很多日志会保存下来以便后续分析

【20160907】CSS3动画

CSS3动画

CreateTime: 2016-09-07 11:14:32
Author: zhongxia

CSS3的动画效果是一个很有用的功能,可以很方便的实现了早期只能用JS来实现的动画效果。这里主要讲解CSS3的动画

CSS3动画 transition 和 animation

一、transition (过度)

在没有出现transition之前,CSS是没有时间轴的,状态变化是即时完成的。

最简单的使用方法

/*==================最基本用法=====================*/
img{
    width:20px;
    height:20px;
    transition: 1s;  /*设置CSS属性变化过度的时间*/
}
img:hover{
    width:200px;
    height:200px;
}

/*==================完整例子=====================*/
img{
    transition: 2s 1s height ease;  
}

img{
    transition-property: height;        /*CSS状态值需要过度的属性*/
    transition-duration: 2s;            /*过度时间*/
    transition-delay: 1s;               /*延迟时间*/

    transition-timing-function: ease;   
    /*状态变化速度(ease 逐渐放慢、linear 匀速、ease-in 加速、ease-out 减速、cubic-bezier函数:自定义速度模式)*/
}


cubic-bezier 可以使用工具网站来实现 工具网站

transition的使用注意

  • 各大浏览器(IE10+)支持不加前缀的 transition。
  • 不是所有的CSS属性都只是 transition。 完整列表
  • transition需要明确知道,开始状态和结束状态的具体数值,才能计算出中间状态。比如,height从0px变化到100px,transition可以算出中间状态。但是,transition没法算出0px到auto的中间状态,也就是说,如果开始或结束的设置是height: auto,那么就不会产生动画效果。类似的情况还有,display: none到block,background: url(foo.jpg)到url(bar.jpg)等等。

transition的局限

transition的优点在于简单易用,但是它有几个很大的局限。

  • transition需要事件触发,所以没法在网页加载时自动发生。
  • transition是一次性的,不能重复发生,除非一再触发。
  • transition只能定义开始状态和结束状态,不能定义中间状态,也就是说只有两个状态。
  • 一条transition规则,只能定义一个属性的变化,不能涉及多个属性。
    CSS Animation就是为了解决这些问题而提出的。

二、animation (动画)

/*定义一个动画效果*/
@-webkit-keyframes rainbow {
  0% { background: #c00; }
  50% { background: orange; }
  100% { background: yellowgreen; }
}

@keyframes rainbow {
  0% { background: #c00; }
  50% { background: orange; }
  100% { background: yellowgreen; }
}

div {
    width: 200px;
    height: 200px;
    border: 1px solid black;
}

/*hover 使用这个动画效果*/
div:hover{
    -webkit-animation: 1s rainbow; 
    animation: 1s rainbow;  /*默认播放一次*/
} 
/*==================animation简写======================*/
animation: 1s rainbow infinite; /*无限次播放*/
animation: 1s rainbow 10; /*播放10次*/

div:hover {
  animation: 2s 1s rainbow linear 3 forwards normal;
}

div:hover {
  animation-name: rainbow;
  animation-duration: 2s;
  animation-timing-function: linear;
  animation-delay: 1s;
  animation-fill-mode:forwards;
  animation-direction: normal; 
  animation-iteration-count: 3;
}

animation-fill-mode: 动画结束以后,会立即从结束状态跳回到起始状态。如果想让动画保持在结束状态,需要使用animation-fill-mode属性。

  • none:默认值,回到动画没开始时的状态。
  • backwards:让动画回到第一帧的状态。
  • both: 根据animation-direction(见后)轮流应用forwards和backwards规则。

animation-direction:动画循环播放后,每次播放完都是回到开始的状态,这个属性可以修改

简单说,animation-direction指定了动画播放的方向,最常用的值是normal和reverse。浏览器对其他值的支持情况不佳,应该慎用。

keyframes

chrome 不支持没有前缀的 @Keyframes ,因此需要加上 @-webkit-keyframes, IE10+ 和 Firefox16+ 支持不加前缀的@Keyframes

/*from=0%   to=100%*/
@keyframes rainbow {
  from { background: #c00 }
  50% { background: orange }
  to { background: yellowgreen }
}
/* 上面的 等于 下面这个写法*/
@keyframes rainbow {
  0% { background: #c00 }
  50% { background: orange }
  100% { background: yellowgreen }
}

@keyframes pound {
  from,to { transform: none; }
  50% { transform: scale(1.2); }
}

//另外一点需要注意的是,浏览器从一个状态向另一个状态过渡,是平滑过渡。steps函数可以实现分步过渡。
div:hover {
  animation: 1s rainbow infinite steps(10);
}

动画播放结束之后,默认回到初始状态,这个时候就需要使用到 animation-play-state

div {
    animation: spin 1s linear infinite;
    animation-play-state: paused;
}

div:hover {
  animation-play-state: running;
}

参考文章

  1. CSS in the 4th Dimension
  2. CSS3动画简介

【20161022】【ReactNative】【问题】IOS fetch Network request failed

一、RN 做 fetch 请求时,报以下错误

fetch(url, {method: 'GET', header: {'Content-Type': 'text/plain'}})
      .then(res=> res.json())
      .then(data=> {
        console.log("data", data)
        data = data || {}
        that.setState({articleList: data || []})
      })
      .catch(function (err) {
        console.log("err", err)
        that.setState({articleList: []})
      });
TypeError: Network request failed
    at XMLHttpRequest.xhr.onerror (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&hot=true:28193:8)
    at XMLHttpRequest.dispatchEvent (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&hot=true:14591:15)
    at XMLHttpRequest.setReadyState (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&hot=true:29573:6)
    at XMLHttpRequest.__didCompleteResponse (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&hot=true:29431:6)
    at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&hot=true:29506:52
    at RCTDeviceEventEmitter.emit (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&hot=true:13428:23)
    at MessageQueue.__callFunction (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&hot=true:11999:23)
    at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&hot=true:11906:8
    at guard (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&hot=true:11857:1)
    at MessageQueue.callFunctionReturnFlushedQueue (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&hot=true:11905:1)

解决方案

参考地址

  1. http://stackoverflow.com/questions/38077273/react-native-fetch-network-request-failed-not-using-localhost

【20161102】新公司代码提交感慨

时间:2016-11-02 21:01:33

背景

早期的公司,代码版本管理,都是使用 svn, 提交上的代码也没有 review 才能merge 到主干上做法。
新公司采用 gitlab 来保存代码, 修改呢, 先 fork 出来,然后进行修改,修改完自己先提交到本地仓库,然后推送到gitlab 上,然后上 gitlab 上 刷新页面, 最上角会有一个 Merge Request 的按钮,点击按照提示创建 Merge Request。

步骤

1. Fork 项目到自己帐号上

Fork 过来之后,在要修改某个问题时, 创建一个分支出来

2. 修改,提交本地仓库,push 到 gitlab

常规的 git 操作。
比如:

git clone 地址(fork过来后的地址)
touch test.txt
git add test.txt
git commit test.txt -m 'add test'
git push 

3. 进入GitLab地址, Create Meger Request

然后编写 Meger 说明, 和@ 相关人员 Review 代码。

【20160926】JS问题规避

JS规范

有一些JavaScript的写法必须要规避。 开发尽量使用严格模式。IE10 以下不支持严格模式

  • 使用严格模式,规避一些常规错误
"use strict";
  • 变量声明提升导致的问题

    两个 name 会被提升到 作用域的最前面 ,在严格模式下, 重复定义一个变量名会报错。

SCRIPT1046:严格模式下不允许一个属性有多个定义

var testObj = {
    prop1: 10,
    prop2: 15,
    prop1: 20
};

这里有两个 prop1 属性, 在严格模式下报错

参考

  1. MSDN严格模式 (JavaScript)

【20160930】Chrome 跨域 disable-web-security 关闭安全策略

为什么这样关闭Chrome安全策略跨域?

做前端的知道跨域这个问题,现在前后端开发分离了,然后开发联调的时候,我们本地的前端项目访问后端的接口时,就报跨域问题。 跨域问题 有多种解决方案,比如 CORS跨域,JSONP,HTML5 的 postMessage 等。

当遇到以下情况,则可以简单的使用 关闭Chrome 安全策略跨域

  1. 开发时跨域,上线后,部署在一个域名下没有跨域问题
  2. 开发时,临时解决跨域问题

只有开发时用这个,其他时候,就不要使用这种方式了

切记切记

切记切记,使用这个打开之前,判断下chrome是否都关闭掉了。
mac 下 , command+q 就退出了
window下,如果不确定是否全部退出,打开任务管理器, 找下 chrome 是否还有打开的。

有时候window下,明明感觉已经全部关闭了,可是打开之后,发现居然居然居然没有用。然后打开任务管理器一看,原来还有未关闭的。 只是图标没有在任务栏。
image

mac

直接用命令行打开,目前使用该命令打开还没有遇到啥问题,百试百灵。 safari 也一样

//chrome 浏览器
open -a "Google Chrome" --args --disable-web-security  --user-data-dir
//safari 浏览器 
open -a '/Applications/Safari.app' --args --disable-web-security --user-data-dir 

window下

这里的chrome.exe 地址根据自己安装路径来, 测试过 chrome45,48,53版本。
45版本 只需要 --disable-web-security
48,53版本需要 额外添加 --user-data-dir

一、命令行打开方式

"C:\Users\UserName\AppData\Local\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir

//不知道chrome.exe 地址的话
右键chrome图标-->属性-->如下图-->图中 目标 就是文件的位置了,直接复制出来即可

二、配置快捷方式打开【简单粗暴】

chrome53 版本,设置这样好像不起作用。【操作系统 window7,64位】,只能用命令行

  1. 新建桌面快捷方式

    注意:chrome48,版本需要添加上 --user-data-dir

//快捷方式后面  空一格,再加上
--disable-web-security --user-data-dir

image

Linux【未测试过】

chromium-browser --disable-web-security  

成功效果

各个平台下的浏览器,都是差不多这个样子。
image

【20161014】Nginx跨域配置

转载

原文地址:Nginx跨域配置,支持DELETE,PUT请求

自己解决跨域的几种简单方式

这里只描述一下,简单的跨域形式,不需要修改前后端代码,只需要做配置就行了。

一、Chrome浏览器关闭安全策略

开发时存在跨域,上线后部署在 一起,没有跨域问题
参照

28 Chrome关闭安全策略

背景描述

最近在研究RESTful API接口设计,使用的是Nginx,
要实现本地 http://127.0.0.1 跨域访问服务器端 http://api.zlzkj.com
并且要支持DELETE PUT等请求。

跨域配置

只需要在Nginx配置文件里加入以下配置,即可开启跨域

add_header Access-Control-Allow-Origin *;

*代表任何域都可以访问,可以改成只允许某个域访问,如Access-Control-Allow-Origin: http://www.zlzkj.com
这样的配置虽然开启了跨域请求,但只支持GET HEAD POST OPTIONS请求,使用DELETE发起跨域请求时,浏览器出于安全考虑会先发起OPTIONS请求,服务器端接收到的请求方式就变成了OPTIONS,所以引起了服务器的405 Method Not Allowed。

所以要对OPTIONS请求进行处理

if ($request_method = 'OPTIONS') { 
    add_header Access-Control-Allow-Origin *; 
    add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
    #其他头部信息配置,省略...
    return 204; 
}

当请求方式为OPTIONS时,设置Allow的响应头,重新处理这次请求。
配置好并重启Nginx,刷新页面重新发起请求,在控制台里你会发现,出现了二次请求,
第一次是OPTIONS请求,第二次才是DELETE请求,这就是对OPTIONS请求进行处理的结果,到这里总算完成了一次DELETE跨域请求了。

完整配置参考

add_header Access-Control-Allow-Origin *;
location / {
    if ($request_method = 'OPTIONS') { 
        add_header Access-Control-Allow-Origin *; 
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
        return 204; 
    }
    index index.php;
    try_files $uri @rewriteapp;
}

放到配置文件的server {}里

参考文章

总结

虽然最终配置代码没有几行,过程还是比较折腾的。
一开始不断地去翻墙,查阅相关文章,好不容易找到了跨域配置方法,却发现不支持DELETE等请求方式,于是又重新去翻墙,把原来的相关文章再次翻了一遍,才查到了些蛛丝马迹,又通过论坛提问,最终才找到了相应的解决方法,多折腾总有收获。

【20161010】webstrom 使用 技巧

webstrom 使用技巧

工欲善其事,必先利其器。

webstrom作为前端的神器,了解webstrom如何使用是很有必要的,有一些快捷键可以大大加快我们编码的效率,以及舒适度。

快捷键

常用的快捷键有

  • 复制一行 cmd+alt+down
  • 删除一行 cmd+d
  • 全局搜索 ctrl+shift+h
  • 替换 cmd+f
  • 点击跳转到方法定义处 cmd + 鼠标点击
  • 返回上一处编辑位置 cmd+[ (参考下图)

代码片段

有了快捷键,能使各种常用操作刷刷刷的快速完成。但是在一字一字的敲代码的时候,并没有起到什么很大的作用。
那么是否支持自定义一些常用的代码片段,我输入几个字母,就可以直接生成一大串代码呢?
事实告诉我,这个是有的。

自定义代码片段在这里:

至于要定义什么代码片段呢?可以自己考虑。
我个人呢, 因为主要用 react 进行开发, 当然要各种创建react类啦, 生命周期啦。
比如我想创建一个 react 组件,手写效率太低,而且懒人是不会去记代码的。
因此。

/***************************************************
 * 时间: $DATE$ $TIME$ 
 * 作者: $AUTHOR$
 * 说明:
 *
 ***************************************************/
import React, { PropTypes } from 'react'
import classnames from 'classnames'

class $NAME$ extends React.Component {
   constructor(prop){
     super(prop);
     this.state = {};
   }

   render(){
      return (
      <div>
      </div>
      );
   }
}

$NAME$.propTypes = {
  name: PropTypes.string
}
$NAME$.defaultProps = {
  name: '基本信息'
}

export default $NAME$

定义变量

这样我输入 rclass
就生成以下内容了

/***************************************************
 * 时间: 10/10/16 16:18 
 * 作者: zhongxia
 * 说明:
 *
 ***************************************************/
import React, { PropTypes } from 'react'
import classnames from 'classnames'

class index extends React.Component {
   constructor(prop){
     super(prop);
     this.state = {};
   }

   render(){
      return (
      <div>
      </div>
      );
   }
}

index.propTypes = {
  name: PropTypes.string
}
index.defaultProps = {
  name: '基本信息'
}

export default index

【20151008】【GITHUB】pull request

总结

pull request 是 开源协作是一个必须品, 是非常重要的。 要为开源库做贡献,就要需要使用该功能。 下面是从知乎上找到的一些资料,方便大家理解 pull request.

作者:beepony
链接:https://www.zhihu.com/question/21682976/answer/79489643
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

例子

我尝试用类比的方法来解释一下 pull reqeust。想想我们中学考试,老师改卷的场景吧。

  1. 你做的试卷就像仓库,你的试卷肯定会有很多错误,就相当于程序里的 bug。
  2. 老师把你的试卷拿过来,相当于先 fork。
  3. 在你的卷子上做一些修改批注,相当于 git commit。
  4. 最后把改好的试卷给你,相当于发 pull request,
  5. 你拿到试卷重新改正错误,相当于 merge。

流程

  1. 当你想更正别人仓库里的错误时,要走一个流程:
  2. 先 fork 别人的仓库,相当于拷贝一份,相信我,不会有人直接让你改修原仓库的
  3. clone 到本地分支,做一些 bug fix
  4. 发起 pull request 给原仓库,让他看到你修改的 bug
  5. 原仓库 review 这个 bug,如果是正确的话,就会 merge 到他自己的项目中
  6. 至此,整个 pull request 的过程就结束了。

具体操作例子

理解了 pull request 的含义和流程,具体操作也就简单了。以 Github 排名最高的 https://github.com/twbs/bootstrap 为例说明。

  1. 先点击 fork 仓库,项目现在就在你的账号下了
  2. 在你自己的机器上 git clone 这个仓库,切换分支(也可以在 master 下),做一些修改。
~  git clone https://github.com/beepony/bootstrap.git
~  cd bootstrap
~  git checkout -b test-pr
~  git add . && git commit -m "test-pr"
~  git push origin test-pr
  1. 完成修改之后,回到 test-pr 分支,点击旁边绿色的 Compare & pull request 按钮
  2. 添加一些注释信息,确认提交
  3. 仓库作者看到,你提的确实是对的,就会 merge,合并到他的项目中

以上就是 pull reqesut 的整个流程,希望对你有帮助~

参考文档:

  1. Fork A Repo - User Documentation
  2. Using pull requests
  3. Creating a pull request

【20161017】GET传参最大长度的理解误区

GET传参最大长度的理解误区

时间:2016-10-17 14:59:38
作者:zhongxia

零、总结

文章数据来源于网络,可能存在变动,但是原理是一样的。

  1. HTTP 协议 未规定 GET 和POST的长度限制
  2. GET的最大长度显示是因为 浏览器和 web服务器限制了 URI的长度
  3. 不同的浏览器和WEB服务器,限制的最大长度不一样
  4. 要支持IE,则最大长度为2083byte,若只支持Chrome,则最大长度 8182byte

一、误解

大家都知道http 中 存在 GET 和 POST 这两种最常用的请求方式。(PUT,DELETE不在本文讨论范围之内)

误解:HTTP 协议下的 Get 请求参数长度是有大小限制的,最大不能超过XX,而 Post 是无限制的。

1、首先即使有长度限制,也是限制的是整个 URI 长度而不仅仅是你的参数值数据长度

2、HTTP 协议从未规定 GET/POST 的请求长度限制是多少。

*以下内容摘自 《关于 HTTP GET/POST 请求参数长度最大值的一个理解误区》, 文章时间为 2013年的。可能以当前最新的浏览器有出入 *

The HTTP protocol does not place any a priori limit on the length of a URI. Servers MUST be able to handle the URI of any resource they serve, and SHOULD be able to handle URIs of unbounded length if they provide GET-based forms that could generate such URIs. A server SHOULD return 414 (Request-URI Too Long) status if a URI is longer than the server can handle (see section 10.4.15).
Note: Servers ought to be cautious about depending on URI lengths above 255 bytes, because some older client or proxy implementations might not properly support these lengths.

3、所谓的请求长度限制是由浏览器web 服务器决定和设置的,各种浏览器和 web 服务器的设定
均不一样,这依赖于各个浏览器厂家的规定或者可以根据 web 服务器的处理能力来设定。

The limit is in MSIE and Safari about 2KB, in Opera about 4KB and in Firefox about 8KB, (255 bytes if we count very old browsers) . We may thus assume that 8KB is the maximum possible length and that 2KB is a more affordable length to rely on at the server side and that 255 bytes is the safest length to assume that the entire URL will come in.
If the limit is exceeded in either the browser or the server, most will just truncate the characters outside the limit without any warning. Some servers however may send a HTTP 414 error. If you need to send large data, then better use POST instead of GET. Its limit is much higher, but more dependent on the server used than the client. Usually up to around 2GB is allowed by the average webserver. This is also configureable somewhere in the server settings. The average server will display a server-specific error/exception when the POST limit is exceeded, usually as HTTP 500 error.

IE 和 Safari 浏览器 限制 2k
Opera 限制4k
Firefox 限制 8k(非常老的版本 256byte)

如果超出了最大长度,大部分的服务器直接截断,也有一些服务器会报414错误。


HTTP 1.1 defines Status Code 414 Request-URI Too Long for the cases where a server-defined limit is reached. You can see further details on RFC 2616. For the case of client-defined limits, there is no sense on the server returning something, because the server won't receive the request at all.

详细可以看 RFC2616

The server is refusing to service the request because the Request-URI is longer than the server is willing to interpret. This rare condition is only likely to occur when a client has improperly converted a POST request to a GET request with long query information, when the client has descended into a URI "black hole" of redirection (e.g., a redirected URI prefix that points to a suffix of itself), or when the server is under attack by a client attempting to exploit security holes present in some servers using fixed-length buffers for reading or manipulating the Request-URI.


二、各个浏览器和web服务器的最大长度总结

** 以下内容摘自《GET请求中URL的最大长度限制总结》, 文章内容是 2016年9月,相对比较符合当前的最新现状。 **

在网上查询之后,浏览器和服务器对url长度都有限制,现总结如下。

浏览器

1、IE

IE浏览器(Microsoft Internet Explorer) 对url长度限制是2083(2K+53),超过这个限制,则自动截断(若是form提交则提交按钮不起作用)。

2、firefox

firefox(火狐浏览器)的url长度限制为 65 536字符,但实际上有效的URL最大长度不少于100,000个字符。

3、chrome

chrome(谷歌)的url长度限制超过8182个字符返回本文开头时列出的错误。

4、Safari

Safari的url长度限制至少为 80 000 字符。

5、Opera

Opera 浏览器的url长度限制为190 000 字符。Opera 9 地址栏中输入190 000字符时依然能正常编辑。

服务器

1、Apache

Apache能接受url长度限制为8 192 字符

2、IIS

Microsoft Internet Information Server(IIS)能接受url长度限制为16 384个字符。
这个是可以通过修改的(IIS7)
configuration/system.webServer/security/requestFiltering/requestLimits@maxQueryStringsetting.<requestLimits maxQueryString="length"/>

3、Perl HTTP::Daemon

Perl HTTP::Daemon 至少可以接受url长度限制为8000字符。Perl HTTP::Daemon中限制HTTP request headers的总长度不超过16 384字节(不包括post,file uploads等)。但当url超过8000字符时会返回413错误。
这个限制可以被修改,在Daemon.pm查找16×1024并更改成更大的值。

4、ngnix

可以通过修改配置来改变url请求串的url长度限制。

client_header_buffer_size 默认值:client_header_buffer_size 1k

large_client_header_buffers默认值 :large_client_header_buffers 4 4k/8k

由于jsonp跨域请求只能通过get请求,url长度根据浏览器及服务器的不同而有不同限制。
若要支持IE的话,url长度限制为2083字符,若是中文字符的话只有2083/9=231个字符。
若是Chrome浏览器支持的最大中文字符只有8182/9=909个。

三、参考文章

  1. GET请求中URL的最大长度限制总结
  2. 关于 HTTP GET/POST 请求参数长度最大值的一个理解误区

【20161102】整理一份react的脚手架

时间:2016-11-02 10:35:09

目前已经 有一份脚手架,不过由于babel 还是采用5.x 的, 想要替换成 6.x,并且要集成进 redux, 还有react 换成 15.x

TODO:待整理

【20160906】 浏览器输入URL,发生了什么?【HTTP篇】

浏览器输入URL,发生了什么?【HTTP篇】

CreateTime:2016-09-06 20:07:17
Author:zhongxia
浏览器输入URL之后,发生了什么? 针对前端来说,最重要的是 http 和 浏览器渲染。底层硬件,网络通讯,后端的相关知识,这里就大概一概而过了。 这一篇主要讲解一下http相关方面的。

1. 浏览器输入URL,解析URL

用户输入URL地址,浏览器会去解析URL地址,得到请求服务器地址,请求页面文件路径,以及请求参数

2. DNS解析

根据域名解析服务器的IP地址, ip地址是一串数据,不方便记忆,因此有了域名。

  1. 从浏览器DNS缓存,找域名相对应的IP
  2. 没有找到,则从系统缓存寻找
  3. 没有找到,从系统的host文件里面找
  4. 没有找到,从路由器上找
  5. DNS服务器找
  6. ...
  7. 找到域名对应的IP地址

3. 浏览器发送HTTP请求

浏览器发出一个 HTTP协议的请求,组织了一个请求的数据包(走OSI七层模型,从应用层 到 最低层的数据链路层 的数据包层层封装,然后传到服务器在 层层解开)

3.1 请求消息

  • 请求行
    • 请求方法【POST/GET/PUT/DELETE】
    • URI
    • 请求协议【FTP、HTTP、HTTPS、等】/版本
  • 请求报头
    • 参考最下面文章【待整理,可以先参考最下面的参考文章】
  • 请求正文(需要传到服务器的数据)

image

请求头 和 请求正文之间有 一个空行,空行是 HTTP规定的消息头和消息体的分界线

3.2 响应消息

  • 状态行
  • 响应报头
    • 【待整理,可以先参考最下面的参考文章】
  • 响应正文

1xx:信息响应类,表示接收到请求并且继续处理

2xx:处理成功响应类,表示动作被成功接收、理解和接受

3xx:重定向响应类,为了完成指定的动作,必须接受进一步处理

4xx:客户端错误,客户请求包含语法错误或者是不能正确执行

5xx:服务端错误,服务器不能正确执行一个正确的请求

3.3 HTTP相关知识:

  1. 三层架构(浏览器,web服务器,数据库),http 是用在 浏览器 和 web服务器之间通讯

  2. 两个核心(浏览器发出request请求, Web服务器response返回数据(text,xml,流等))

  3. 一个记住(HTTP是无状态的)

    无状态是指_协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态_。即我们给服务器发送 HTTP 请求之后,服务器根据请求,会给我们发送数据过来,但是,发送完,不会记录任何信息。
    keep-alive 也无法改变这个无状态

4. 以百度首页为例获取请求头和响应头内容:

1、请求头:

我们现在通过谷歌浏览器来查看一下请求头:

以打开百度首页为例,然后在谷歌浏览器中打开“工具-开发者工具”,切换到network标签, 然后刷新页面:
image

上图中,打开箭头处html格式的文件,显示如下:
image

上图中的Request Headers就是我们所需要的请求头。里面的内容全部是键值对。服务器拿到这些键值对后会对其进行分析。

我们再来重复一下常见请求头键值对的含义:

  • Host:www.baidu.com 本次请求访问的主机地址(虚拟主机名称)
  • Cache-control:no-cache 设置网页缓存的使用方法
  • Pragma:no-cache
  • Accept:text/html,xxxxxx…..客户端可以接收的数据类型(如果内容是:/,表示接收所有类型)
  • User-Agent:Mozilla/5.0xxxxx 主要表示客户端类型
  • Accept-Encoding:gzip,deflate,sdch 浏览器能够接收的数据压缩编码方式(表示浏览器能够接收什么格式的压缩的数据)
  • Accept-Language:zh-CN,zh;q=0.8 浏览器期望的接受的语言种类
  • Accept-Charset: ISO-8859-1 客户端所接收的字符集编码
  • If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT 和缓存机制相关的头
  • Referer: http://www.smyh.me/index.jsp 当前页面来自哪个页面(可能是由之前的页面通过超链接点进到这个页面来)
  • Cookie
  • Connection: close/Keep-Alive 请求完之后,是关闭此连接,还是继续保持连接
  • Date: Tue, 11 Jul 2013 18:23:51 GMT 当前请求的时间

注:上面的这些指的是get请求的请求头。

2、响应头:

我们再来看一下响应头的内容:
image

常见的响应头键值对的含义:

  • Location: http://www.smyh.me/index.jsp 重定向(302+Location实现重定向)
  • Server 服务器类型
  • Content-Encoding 服务器当前返回给客户端的数据压缩格式
  • Content-Length 返回给客户端的数据量的大小
  • Content-Language: zh-cn 语言种类
  • Content-Type: text/html; charset=GB2312 返回的数据的类型、字符集编码方式
  • Last-Modified 资源最后一次修改的时间(配合请求头中的If-Modified-Since+304/307实现缓存机制)
  • Refresh: 1;url=http://www.it315.org    隔多少秒以后,让当前页面去访问哪个地址(例如网页登陆成功后,跳回原来的界面,就是用的这个头)
  • Content-Disposition: attachment;filename=aaa.zip 和下载相关,通知浏览器以附件的形式下载服务器发送过去的数据
  • Transfer-Encoding: chunked 数据传输模式
  • Set-Cookie:SS=Q0=5Lb_nQ; path=/search 和cookie相关的头
  • ETag: W/"83794-1208174400000" 和cookie相关的头
  • Expires: -1 通知浏览器是否缓存当前资源:如果这个头的值是一个以毫秒为单位值,则通知浏览器缓存资源到指定的时间点;如果值是0或-1,则通知浏览器禁止缓存
  • Cache-Control: no-cache 通知浏览器是否缓存资源
  • Pragma: no-cache -- 通知浏览器是否缓存资源

注: 之所以三个头是一个功能,是因为历史原因。不同的浏览器对这三个头支持的不同,一般来说这三个头要同时使用,以确保不同的浏览器都能实现控制缓存的功能

  • Connection: close/Keep-Alive 是否继续保持连接
  • Date: Tue, 11 Jul 2000 18:23:51 GMT 当前响应的时间

参考文章

  1. Android系列之网络(二)----HTTP请求头与响应头
  2. 如何理解HTTP响应的状态码?
  3. 【i5ting】精解http

【20161101】safari 与 chrome 的小区别大BUG

safari 与 chrome 的小区别大BUG

时间:2016-11-01 17:33:19
作者:zhongxia
原文地址:#41

一、背景

故事是这样的,有一个auth 的认证接口, validate_auth 的接口。 后端使用 go语言写的。 正确的接口地址是 127.0.0.1:3000/api/auth/validate_token/ 【注意,完成的接口地址有 / 】,至于为什么要多一个 / 这个就是后端的疏忽的。

多一个 / 到底会引发什么问题呢?

chrome 和 safari 的表现

注意 http://localhost:3000/api/auth/validate_token 中的 validate_token 是一个目录, / 才是接口名称。

var authHeaders = JSON.parse(localStorage.authHeaders)

fetch("http://localhost:3000/api/auth/validate_token", {
  method: "GET",
  headers: {
    "authorization": "Bearer "+authHeaders.access_token,
  }
})
.then(function (res) {
  if (res.ok) {
    alert("Perfect! Your settings are saved.");
    console.log(res.json())
  } else if (res.status == 401) {
    alert("Oops! You are not authorized.");
  }

chrome 访问该接口的情况

safari 访问该接口的情况

区别就是, safari 不会 访问的时候,不会做一个跳转,但是 chrome 会做一次跳转

如果是 auth 认证, 在 chrome 认证就可以通过,但是在 safari 认证就通不过。

总结

后端接口需要写完善一点,否则引发一些这种坑爹的BUG, 很难定位。

【20160902】webpack分离css单独打包

webpack分离css单独打包

CreateTime:2016-05-17 11:55
UpdateTime:2016-09-02 16:35

由于这篇文章只写了如何把CSS打包成一个CSS文件,没有讲解如何打包成多个CSS文件,经简友提点,这里添加上了 打包成多个CSS文件的方法。

image

瞎扯

webpack 把所有的资源都当成了一个模块, CSS,Image, JS 字体文件 都是资源, 都可以打包到一个 bundle.js 文件中.
但是有时候需要把样式 单独的打包成一个文件, 然后放到 CND上, 然后缓存到浏览器客户端中


一、extract-text-webpack-plugin 使用方法

这个操作很简单的,只需要一个插件就好了,就是extract-text-webpack-plugin

1. 安装extract-text-webpack-plugin

npm install extract-text-webpack-plugin --save-dev

2. 配置文件添加对应配置

首先require一下

var ExtractTextPlugin = require("extract-text-webpack-plugin");

plugins里面添加

new ExtractTextPlugin("styles.css"),

实例:

plugins:  [
      new webpack.optimize.CommonsChunkPlugin('common.js'),
      new ExtractTextPlugin("styles.css"),  
],

modules里面对css的处理修改为

{
    test: /\.css$/,
     loader:  ExtractTextPlugin.extract("style-loader","css-loader")
},

千万不要重复了,不然会不起作用的

我这里如下:

module:  {
      loaders:  [
            {
            test: /\.css$/,
             loader:  ExtractTextPlugin.extract("style-loader","css-loader")
        },
            {
            test:  /\.scss$/,
             loader:  "style!css!sass"
        },
            {
            test:  /\.less$/,
             loader:  "style!css!less"
        },
    ]
},

3. 在引入文件里面添加需要的css,【举例如下】

require('../less/app.less');
require('./bower_components/bootstrap-select/dist/css/bootstrap-select.min.css');
require('./bower_components/fancybox/source/jquery.fancybox.css');

二、如何把CSS打包成一个文件, 和 把CSS打包成多个文件

打包一个文件,只需要常规的在入口的js文件引用 css文件即可, 打包成多个CSS文件,可以设置多个CSS入口,让webpack用 loader去打包。 和分割单独打包js文件一样。下面有两个例子。【例子来源】

//  使用webpack 打包单独的postcss语法的css文件
/*   webpack.config.js   */
var precss = require('precss');
var cssnext = require('cssnext');
var autoprefixer = require('autoprefixer');
var cssnano = require('cssnano');
var Ex = require('extract-text-webpack-plugin');
module.exports = {
    entry: './【path】/index.js',
    /*  index.js 里  require('./【name】.css');就好  我在看看文档是不是直接不用引入js文件 */
    output: {
      filename: 'index.js'
    },
    module: {
      loaders: [{
        test: /\.css$/,
        loader: Ex.extract('style-loader', 'css-loader!postcss-loader') /*这里的写法注意下 */
      }]
    },
    postcss: function() {
      return [autoprefixer, cssnext, precss, cssnano]
    },
    plugins: [
      new Ex("【name】.css")
    ]
  }
  //////////////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////////////
  //  使用webpack 打包单独的多个postcss语法的css文件
var precss = require('precss');
var cssnext = require('cssnext');
var autoprefixer = require('autoprefixer');
var cssnano = require('cssnano');
var Ex = require('extract-text-webpack-plugin');
var webpack = require('webpack');


module.exports = {
  entry: {
    ac1: './src/actother.css',
    ac2: './src/index.css'
  },
  output: {
    filename: "[name].css"
  },
  module: {
    loaders: [{
      test: /\.css$/,
      loader: Ex.extract('style-loader', 'css-loader!postcss-loader')
    }]
  },
  postcss: function() {
    return [autoprefixer, precss, cssnano, cssnext]
  },
  plugins: [
    new Ex('[name].css')
  ]
}

【20160928】【项目总结】大数据操作系统

【项目总结】大数据操作系统

createTime:2016-09-28 16:30:55
原文地址,欢迎star!
总结下项目的问题,收获,不足。

产品功能:可以查看 http://www.baifendian.com/pro/subject-67.html
简单的讲,该系统提供一整套的大数据解决方案。 客户拥有大量的数据,然后如何从这大量数据中,清洗出有价值的数据。

系统GIF图

如果上图看不到,点击这里

项目人员及耗时

5个前端,10个后端,1个运维, 开发调试用时3个月, 测试用时1.5个月。

应用技术

前端技术:React全家桶 + webpack + gulp + ES6 + babel + less (react0.14)
代码版本控制使用:SVN
后端技术:Java + 大数据相关 【略】

项目架构

大数据操作系统,由多个模块组成,每个模块可以理解成一个Project, 可以单独运行,不依赖其他模块。 然后由web桌面集成在一起。

项目目录结构

整体的目录结构

    - BFD-UI  公共组件库
    - CommonComponent  公共样式,Ajax处理,正则,针对产品定制组件部分
    - DataFactoryModel  项目应用的工作流框架
    - ConfigCenter 项目
    - DataFactory   项目
    - FilaManage   项目
    - SecurityCenter  项目
    - node_modules  

单个项目目录结构

- common  项目间公共代码
- container  项目布局
- modules    一级模块目录
  - ide   一级模块
    - components    页面
    - css         样式
    - enum      枚举
    - model     Ajax相关操作
    - util 工具
    - index.js   react-router 路由
  ...
  - workflow    一级模块

问题

项目中考虑的问题和遇到问题的解决思路

一、 团队协作之间如何减少冲突?

相对刚开始,前后端还搞在一起,前端开发还需要搭建后端环境,然后后端改配置,前端居然跑不起来了,要抱着电脑去请教后端,这个坑啊。模块化开发好很好,只需要关注自己的模块。

前后端分离, 项目采用模块化,每个人负责几个模块,模块内包含该模块的所有内容,除了公共的部分,保证直接删掉该代码,并去掉路由,直接可以去掉该模块,添加模块等同。
这样模块解耦,方便应对需求变动,权限控制

二、 如何管理组件?

这一块还好,没有遇到啥大问题。

组件需要分为:公共基础组件,公共定制组件,具体业务组件

公共基础组件建议采用第三方组件库,本项目使用公司的组件库,公司组件库刚开始研发,过程中各种BUG,版本迭代间,高版本用于与低版本用法不一样,很多坑爹的问题。

公共定制组件:在公共基础组件的基础上,封装成各个项目中,可以快速使用的方式,方便项目间统一维护,快速方便使用。 比如(表格数据处理,翻页处理,全选逻辑。。。)

具体业务组件:具体页面模块,但具体页面中,也有共用的部分。 最常见的就是编辑页面和创建页面可以共用。

三、如何管理整体样式?

覆盖组件样式是一个坑,因为公司组件也在研发中,作为第一个吃螃蟹的团队,就。。。。
组件库的样式,刚开始使用模块化+嵌套的方式, 后面组件库丰富了,发现有一些命名重复啦,重复啦。然后大改版,使用BEM命名方式。如果只修改命名方式也就还好,最主要还是修改了DOM结构,然后之间的覆盖样式都废了。
切记,切记,切记,使用稳定的组件库

组件库地址:https://github.com/baifendian/bfd-ui
已经提供第一个稳定版本,赞一个,一路过来不容易。

引用第三方的reset.css,比如(normalize.css),处理浏览器之间的小差异

公共基础组件已经有自带的样式,需要覆盖,换成UI设置的风格,覆盖公共组件的样式都放在一个文件中。比如 bfd-ui.less , 也可以放多个文件,然后放在同一个文件夹中。

整体布局的样式,单独抽离成 layout.less 文件

样式命名需要统一规范,否则容易造成样式名冲突。可以使用 BEM的命名方式,虽然命名长了点,但是为了命名冲突,也值了。

less 的变量也可以单独抽取出来,放在一个 文件中。 方便后期统一修改。比如:global.less

//其他使用变量的地方引入
@import "global.less";

注意less 、 sass 的 import 和 css 自带的区别。

四、Ajax请求跨域问题?错误处理问题?session过期问题?

刚开始coding,Ajax还没有封装,大家写到业务逻辑里面,这样代码很乱,一个JS中,有页面,业务逻辑,混在一起。
还好及时提出了解决方案, 抽离Ajax这一层,先封装Ajax操作,然后每个模块各自抽离出Ajax操作,模块中调用,就是一个方法的调用。

跨域: : 关闭浏览器安全策略
开发的时候,前后端是分离的,因此前端访问后端接口的时候是跨域的。考虑到最终上线的时候,是部署在一起。 因此,上线后是没有跨域问题的。 因此可以使用关闭浏览器安全策略来解决跨域问题。

Ajax接口地址: 可配置
开发的时候,可能要连接后端人员机子的IP地址,访问接口,调试完成可能要访问开发环境地址,上线需要访问上线部署的地址。 经常需要变动。 因此 接口的 基本路径 做成 配置。然后直需要改动配置,就替换了整个项目接口的访问地址。

Session过期,错误处理? 提供默认处理,并扩展接口自定义
项目开发,必须给Ajax封装一层,写统一的错误处理,错误提示,Loading效果,超时提示,Session过期等通用操作。

Ajax请求到一半,跳转页面,需要在 componentWillUnmount 中断Ajax请求。否则会报 组件已经卸载,不能使用 this.setState操作的错误。

五、团队协作开发,如何让别人看懂代码?

每个程序员都有自己的代码风格,但是,但是,但是团队开发就需要共同遵守一个代码规范。
这一块React生命周期,大家都按照顺序写,还行。其他方面由于赶时间,基本是 一个 格式化功能搞定。

JS代码规范只能口头上说说,因为实际上会不会执行,还得要比较大的Review力度。因此可以使用 eslint 来进行验证,在提交前要验证下。【验证的比较粗糙】

还有一些则需要团队之间遵守,比如使用React, 编写生命周期的时候,请按照顺序来。

constructor
componentDidMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUnmount
...
其他自定义方法
...
render

创建React组件,统一使用 ES6。加 autobind 方法

六、React组件之间如何通讯?

模块功能复杂的情况下,最好先理清整体流程,操作事件,然后在coding。
写IDE模块的时候,刚开始认为这个很简单,然后直接啪啪啪开始coding了,后面发现都是坑,非常多的细节问题。各种事件,各种交互。导致后面Review做了很大改动,切记切记,理清需求,不要看起来简单。

小模块内部,使用 prop或者 context 传递方法进行通讯, 模块之间使用 事件派发。

七、减少修改公共组件和公共样式,对项目的整体影响

这一块,公共样式,和布局方面做还行,但是公共组件方面有很大的问题,有时候更新组件忘记通知大家,导致跑起来报错。还有必须注意的是,进入测试阶段就不要更新整个组件库了,有BUG自己打补丁修复。因为更新组件引入新的BUG,被测试一直说。

公共样式在整个项目中,各个页面都用到,因此修改公共样式需要慎重。尽量不要使用一些奇淫技巧,写一些稳妥的。

八、正则验证

后台类型的管理系统,需要有很多的表单,有很多表单就有很多表单验证。
可以抽离出正则表达式统一放在一个文件中,其他各个地方都使用该文件里面的正则,文件中没有,则添加上。
在项目中,除了抽离正则,还封装了有验证功能的表单组件,然后直接配置正则,和错误信息(也可以动态生成错误信息),即可使用。

九、SVN提交规范

这一块在该项目中,做的还不错。

测试阶段,尽可能减少修改BUG而引发新的BUG。因此必须写清楚每次提交代码的作用。

研发阶段还好一点,做好一个就可以提交一个,并且稍微注明下 上传什么模块代码就行了。
测试阶段,修改BUG,就必须遵守SVN提交规范

  1. 修改好 一个BUG,提交一次。 【一个BUG,一次提交】
  2. 注明修改的BUG编号,出现原因,解决方案 【重要

十、权限控制

这一块分为两种,按钮控制,模块控制
在项目刚加载的时候,同步请求,权限数据,然后判断 data-code是否有权限,没有的话, 则 不 render 到页面上

按钮的权限控制,在最初的预想是,渲染到DOM后,在remove DOM 节点,后面发现这个想法是不可行的。

React 的 componentDidMount 回调里面, 不可以remove DOM节点,否则报错。

最终封装了一个组件,替换页面上所有需要控制按钮 , 图标按钮,超链接,下拉框选项,右键菜单。

renderType 属性执行渲染成什么类型组件(按钮,下拉。。。)
data-code 核心: 按钮标识,和后端匹配上

<AuthButton style={{marginLeft: 2,marginRight:20}}
                     data-code="1021002" renderType="icon" type="plus-square"
                     onClick={this.addScript.bind(this)}>新增</AuthButton>

模块控制,则控制导航菜单即可。 过滤掉没有权限导航选项,然后把有权限的渲染出来。
每个模块的代码,是按需加载的, 也就是刚进入项目页面的时候,没有加载 模块的JS代码,这样减少了进入系统的时间很长。

遇到的技术难题

1、关闭脚本选项卡的时候,错位了。

【关掉第二个选项卡,可接口是关闭第三个选项卡】
主要问题是:对 React 的 key 和 render原理 的相关知识支持了解不够。

tabs 的内容是 存放在 数组中,循环渲染出来的,新增一个 tab,会往数组中添加一个tab,
然后react就会 重新 render,渲染出 tabs 组件。

修改前使用 index 做为key

    <TabList>
          {this.renderTool()}
          {this.state.tabs.map((tab,index) => {
            return (
              <Tab key={index} activeKey={index}>
                {this.renderTabTitle(tab)}
              </Tab>)
          })}
    </TabList>

修改前使用一个唯一标识作为key,就搞定了。

<Tab key={tab.uuid} activeKey={tab.uuid}> 

一句话就是:想要更新组件内容,请保证当前组件的key与上一状态组件的key不同。
具体可以看《ReactJS 组件的key作用》


收获与不足

一、收获

  1. 负责从0到1的项目架构设计,技术选型。
  2. 项目中越到各种问题,然后解决各种问题。项目中遇到的问题,在架构设计前能考虑到一部分,但是还有很多需要遇到在解决。
  3. 熟练掌握 React的开发模式

二、不足

  1. 技术选型, 低估了组件库升级可能带来的影响。
  2. 在coding前,评估时间 和 实际开发时间存在一点差距。
  3. webpack优化方面,有看过相关文档,不过没有具体实践在项目中。【后期忙着封版】

代考量

虽然没有使用redux进行state管理,但是整体开发过程中,没有体会到状态难管理。

  1. 可能因为模块化开发之后,各个Ajax抽离。
  2. 可能因为各个页面关联性不大

【20161102】Vue脚手架与组件库收藏

时间:2016-11-02 15:06:18

在目前的时间节点上, 前端主流的框架有 React, Angular, Vue 这三个。 个人主要使用 React, 但是也需要理解下 Vue的使用 。 这里收藏一个通用的脚手架,以及常见的类库。

一、脚手架

二、组件库

  1. 【饿了吗Vue组件库 element】,外观简洁大方,包含大部分常用组件

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.