nodeJS基础

| nodeJS
|
| buffer: 处理二进制, 对字符串与二进制进行转换 (done)
| fs: 文件系统操作 (done)
| http: 处理http请求, 创建服务器, 和处理客户端与服务器之间的数据传递request、response (done)
| stream: 文件流
| path: 文件路径的处理 (done)
| URL: 网络地址解析 (done)
| querystring: URL查询字符串 (done)
| Cookie、Session、Token (done)
| event: 事件机制
|
| DNS: 域名解析
| net: TCP网络
| dgram: UDP网络
| crypto: 数据加密
| process: 进程
| childe_process: 子进程
| cluster: 集群
| global: 全局
|
| Express
| Template 模板 jade、
| Mysql (done)
| MongoDB
| redis
| RESTful 架构
|

安装

优点:
    前端的局限性,可以对文件、进程、数据库等进操作,是一门纯后端
    处理高并发  程序异步执行不会阻塞

缺点: nodejs是单线程

1、nodeJS安装,mac或windows系统需要到官网下载安装包,自带npm包管理器

2、安装express框架:npm install -g express

        $ express       // 执行命令

3、更新node版本

    node需要下载一个n模块,是用来专门管理nodejs的版本

    $ sudo npm install -g n     # 安装n模块

    $ sudo n stable        # 升级到稳定版,也可以指定版本号 n v0.10.26

        sudo n 8.9.4        # 升级到指定版本


4、其它命令

    npm -v                  # 显示版本,检查npm 是否正确安装。

    npm install express      # 安装express模块

    npm install -g express  # 全局安装express模块

    npm list                 # 列出已安装模块

    npm show express         # 显示模块详情

    npm update                # 升级当前目录下的项目的所有模块

    npm update express        # 升级当前目录下的项目的指定模块

    npm update -g express      # 升级全局安装的express模块

    npm uninstall express      # 删除指定的模块

NPM与包

NodeJS以CommonJS的包规范来制订,由包结构和包描述文件两部分组件

1、包结构

    npm 下载完包存储到 node_modules 目录中,包含:

    1)package.json: 包描述

    2)bin: 存放可执行的二进制文件

    3)lib: 存储javascript代码目录

    4)doc: 用于存放文档的目录

    5)test: 存放单元测试用例代码

NodeJS

Node采用了Google的V8引擎,作为javascript语言的解释器,Node是基于事件驱动和异步I/O的服务器环境

1、JS与node的区别

    1)JS中顶层对象是 window,nodeJS中的顶层对象是 global

    2)JS中 var a = 10; window.a; 可以访问到,但在node中global.a是访问不到的,因为node有模块的概念

        node中一个文件就是珍上模块,每个模块有自己的作用域

2、REPL环境

    在命令行输入node, 可以直接运行node命令

模块系统 require、exports

1、模块分为

    模块加载:require('2.js');

    1)内置模块:  var fs = require('fs');        // 加载Node的内置模块 fs文件系统

    2)文件模块: 自己定义的业务模块

        定义一个food.common.js

        var food = reuqire('./js/food.common');        // 加载业务模块

    3)加载第三方模块

        require('./2');        // 先按照加载的模块文件进行查找,如果没有找到会在文件名加上.js


2、绝对和相对路径

    var fs = require('fs');        // 绝对路径,是在Node通过内部的node_modules查找到的模块

    var moduleA = reuqire('./lib/moduleA');        // 相对路径


2、npm 全局安装和局部安装

    1)全局安装会安装到Node目录中,各项目都可以使用 npm install -g gulp

    2)局部安装,将一个模块安装到node_modules中,只在当前和子目录中使用


3、模块化

    module和exports两个全局变量

    1)module:每个模块下都包括module对象

        Module {
            id: '.',
            exports: {},
            parent: null,
            filename: '/Users/apple/siguang.liu/nodeProject/server.js',
            loaded: false,
            children: [],
            paths: [
                '/Users/apple/siguang.liu/nodeProject/node_modules',
                '/Users/apple/siguang.liu/node_modules',
                '/Users/apple/node_modules',
                '/Users/node_modules',
                '/node_modules'
            ]
         }

     2)exports外部接口,通过require就可以调用这个接口

         其实exports就是module.exports的引用

        exports.name = 'siguang';
        exports.getPrivate = function(){
            return 'haha';
        }

事件 EventEmitter

var EventEmitter = require('events').EventEmitter,
    a = new EventEmitter;

a.on('event', function(){
    console.log('event called');
})
a.emit('event');

—————————- Node API 文档 —————————-

process 进程对象

1、pid:进程id,也就是进程名

2、kill(pid):杀掉进程

3、nextTick(callback): 会在第一次事件环中最末尾执行,setTimeout和setImmediate属于第二事件环

    console.log('开始');

    setImmediate(function(){
        console.log('setImmediate')
    });

    setTimeout(function(){
        console.log('setTimeout');
    }, 0);

    process.nextTick(function(){
        console.log('nextTick');
    })

    console.log('结束');


    output:

        ---------------  第一次 ----------------
        开始
        结束
        nextTick

        ---------------  第二次 ----------------
        setTimeout
        setImmediate

TCP

传输控制协议TCP是一个面向连接的协议,保证两台计算机之间数据传输的可靠性和顺序

它可以将数据从一台计算机完整有序的传到另一台计算机,http模块就是继承了net(TCP)模块

var net = require('net');        // 引用TCP模块

telnet系统嵌套的客户端,端口23, 用来连接服务器

退出TCP连接 alt+[, 退出telnet quit命令

connect

基于HTTP服务器的工具, 提供新的组织代码的方式来与请求响应对象进行交互,称为中间件

引用模块 var connect = require('connect');

connect作用: 

    1、托管静态文件

    2、处理错误及不存在的url

    3、处理不同类型的请求

utils 工具

var utils = reuqire('utils');

Events 事件

EventEmitter 类

var EventEmitter = require('events');
var emitter = new EventEmitter();

1、addListener(event, listener): 创建事件,客户端通过事件来调用,而服务端通过代码来调用事件侦听

       on(event, listener):

       //  addListener 事件
    var EventEmitter = require('events').EventEmitter;
    var emitter = new EventEmitter();

    emitter.addListener('some_events', function(foo, bar){
        console.log(foo, bar);
    })

    emitter.emit('some_events', 'helloA', 'world');         // helloA world
    emitter.emit('some_events', 'helloB', 'world');         // helloB world


    // on 可以
    emitter.on('message', function(mes, name, age){
        console.log(mes +" name:"+ name +" age:"+ age);
    })

    emitter.emit('message', '消息1', 'siguang', '32');       // 消息1 name:siguang age:32
    emitter.emit('message', '消息2', 'lulu', '30');          // 消息2 name:lulu age:30


2、once():只执行一次

    emitter.once('onceEvent', function(age){
        console.log(age);
    })

    emitter.emit('onceEvent', '1');        // 只执行此次事件
    emitter.emit('onceEvent', '2');
    emitter.emit('onceEvent', '3');


3、removeListener(): 删除listener

4、removeAllListeners(): 删除所有

5、setMaxListeners(num): 正常事件的个数为10个, 如果超出通过此方法来改变限制的个数

6、setMaxListeners(): 每个emitter实例的最大监听数

7、listeners(event): 返回指琮事件的数组

8、emit(事件名, 参数): 执行事件

9、listenerCount(emitter, event): 返回事件个数
https://cnodejs.org/topic/55f8d70a20d84f3d377582a3

1、cookie和session的区别

    cookie存放在客户端 session存放到服务器上

    cookie不安全,客户端可以修改, session不会被修改

    session会保存在一定时间内保存在服务器端, 当访问增多, 会影响性能


2、cookie

    存储到客户端的信息

3、session

    # npm install express-session --save       // 安装

    session原理

        1)服务器端有一个对象专门存session的对象或库 如sessions={};

        2)通过req.session.sign来检查是否为已登录状态

        3)如果没有登录,第一次访问会生成一个sid,Date.now()+Math.random(); 将sid存储到sessions中

        4)把这个sid发送到浏览器端, 通过请求头中会有一个set-cookie, 将session中存到cookie中

            set-cookie:connect.sid=s%3AjDb0ns6Ekas3I7ll3tm9Bxg_wd4WjBJY.wL8VyIWdHQNFWt%2ByE%2BjAV30r4M7ZQdVIXgeKBOzx5iY; Path=/; Expires=Fri, 25 Nov 2016 03:27:38 GMT; HttpOnly

            HttpOnly 不能读不能写


    session(options): 选项内容

        1)name: session名称,设置cookie中,默认为connect.sid

        2)stroe: session存储方式,默认存在内存中,也可以存储到redis、mongodb

        3)secret: 通过设置secret字符串,来计算hash值并放在cookie产生的signedCookie防篡改

        4) cookie: 存放session id 的cookie

        5) genid: 产生一个新的session_id时,所使用的函数,默认使用uid2这个npm包

        6)rolling: 每个请求都重新设置一个cookie

        7)resave: 即使session没有被修改也保存session值

        8)saveUnintialized: 保存新创建但未修改的session


    示例:

        router.get('/', function (req, res) {

            if (req.session.sign) { // 检查用户是否已经登录
                console.log(req.session);//打印session的值
                res.send('welecome <strong>' + req.session.name + '</strong>, 欢迎你再次登录');
            }
            else {      // 否则展示index页面
                req.session.sign = true;
                req.session.name = 'haha';
                res.end('欢迎登陆!');
            }

        });

webSocket

轮循: 隔多长时间ajax发一次请求, 不间隔的去发

长轮循: 隔多长时间ajax发一次请求,接到结果后在发出下一次请求


webScoket: 长连接,浏览器和服务器只需要一次握手,浏览器就和服务器形成一个快速通道,两者之间相互传送数据

    1、节省资源: Header只有2 Bytes,1字节8位   1kb = 1024 bytes

    2、推送消息: 不需要客户端发请求


1、安装

    # npm install ws

2、socket.io库

    Socket.IO是websocket库,包括客户端的js和服务器端的nodejs,目标是构建可以在不同浏览器和移动设备上使用实时应用.

    # npm install socket.io


    https://www.zhihu.com/question/20831000         // scoketIO最大连接数和并发数

错误处理

1、同步方法 try catch

2、异步 判断回调函数error对象

3、流里判断错误,监听error事件

    rs.on('error', function(error){
        console.log(error);
    })

http协议

content-type 的一些参数值: http://blog.csdn.net/blueheart20/article/details/45174399

request请求头: 客户端请求服务器的请求头

    1、host: 主机地址

    2、connection: 客户端与服务器的连接选项

    3、accept: 服务器处理内容的优先级, q是权重 0-1之间范围

    4、user-agent: 用户代理,发送浏览器的硬件、系统等信息, 可以通过些选择来收集用户的pc端还是moblie端访问的多少

    5、accept-encoding: 告诉服务器所支持的编码

    6、accept-language: 告诉服务器所使用的语言, 用于判断中文站还是英文站


response响应: 服务器向客户端响应

    1、statusCode: 状态码

    2、resonPhrase: 状态码描述

    3、headers: 响应头信息

        1) content-Type: 内容类型

        2) location: 重定向url

        3) content-disposition: 下载文件名

        4) content-length: 响应内容的字节数

        5) set-cookie: 写入客户端cookie

        6) content-encoding: 响应内容编码

        7) cache-Control: 缓存

        8) Expires: 指定缓存过期时间

        9) Etag: 服务器响应内容没有变化重新下载数据

        10) connection: 默认keep-alive 保持连接,断开使用close

参考资料

https://thinkjs.org/
https://chyingp.gitbooks.io/nodejs/content/%E8%BF%9B%E9%98%B6/%E5%9B%BE%E7%89%87%E5%9C%B0%E5%9D%80%E8%BD%AC%E6%88%90datauri.html ***
http://nodeapi.ucdok.com/api/ // API中文文档
https://github.com/wangxueliang/node-api/blob/master/doc/fs.md API中文部分
https://nodejs.xiangfa.org/documentation/ // API中文文档
https://cnodejs.org/getstart // node入门
http://nqdeng.github.io/7-days-nodejs/
http://cnodejs.org/topic/581b0c4ebb9452c9052e7acb
http://nqdeng.github.io/7-days-nodejs/ // 7天会Node
https://www.gitbook.com/@chyingp
http://cnodejs.org/topic/581b0c4ebb9452c9052e7acb
https://cnodejs.org/topic/56ef3edd532839c33a99d00e
https://github.com/leizongmin/node123 // 资料导航

Express框架

http://www.expressjs.com.cn/starter/hello-world.html
https://github.com/expressjs?page=2 express下的插件
https://github.com/nodejs nodeJS插件

插件:

http://node.zhufengpeixun.cn/
https://github.com/node-modules?page=1

https://github.com/keepfool/node-lessons

1、cookie: https://github.com/expressjs/cookie-parser // cookie-parser

http://www.cnblogs.com/coolicer/p/4191548.html

2、express-session: session的处理

3、cookie、sesssion加密的包 cookie-signature: https://github.com/visionmedia/node-cookie-signature

https://segmentfault.com/q/1010000000392851

4、token: express-jwt https://www.npmjs.com/package/express-jwt

http://ninghao.net/blog/2834

5、socket.io: npm install socket.io https://github.com/socketio/socket.io

2、mysql: https://www.npmjs.com/package/mysql // 连接和处理mysql

3、ws安装socket/IO服务包: npm install ws

4、mime: https://github.com/broofa/node-mime // 响应css、js文件的请求

http://blog.csdn.net/zgljl2012/article/details/44700953

5、body-parser: https://github.com/expressjs/body-parser // json

https://segmentfault.com/a/1190000003061925

6、superagent: http://visionmedia.github.io/superagent/

http://www.codesec.net/view/183926.html

7、node-images: https://github.com/zhangyuanwei/node-images // 图片转换

8、node-xlsx: https://github.com/mgcrea/node-xlsx // 处理xlsx文件

9、multer: https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md // 处理文件上传

req.body存储表单内容

req.file存储上传控制的内容

multer({dest: './public/upfile'});    设置图片文件存储的路径

upload.single('sendUpfile');        // 上传单个文件 file的name="sendUpfile"

11、multiparty 文件上传: https://github.com/expressjs/node-multiparty

10、formidable: https://cnodejs.org/topic/4f5c62932373009b5c0b027b // 文件上传

11、up工具用于重启服务器, 每次代码修改不需要重启服务器,通过up来完成

安装 sudo npm install up -g

运行 到项目目录 up -watch -port 8080 server.js

模板:

1、handlebars http://www.cnblogs.com/iyangyuan/archive/2013/12/12/3471227.html

http://www.ghostchina.com/introducing-the-handlebars-js-templating-engine/
hbs:  http://www.cnblogs.com/chyingp/p/hbs-getting-started.html

1、Jade

2、ejs

3、Haml

4、CoffeeKup

MD5 JS https://github.com/blueimp/JavaScript-MD5

HTML5 new FormData() http://www.cnblogs.com/lhb25/p/html5-formdata-tutorials.html

Sass

| 知识点
| 变量 - $声明 !default默认值 全局和局部变量
| 嵌套 - 选择器嵌套、属性嵌套、伪类嵌套
| 宏 - @mixin声明宏、@include调用宏、宏可以加参数
| 继承 - @extend来承继一个class
| 占位符 - %mt5定义,@extend来调用
| 插值 - #{}
| 函数
| Sass规则 - @imponrt,@media
| 自定义函数 - @function 函数名
| Sass语句 - @if、@else,@for,@while
| 运算 - +、-、*、/

关于SASS

Sass是CSS预处理器定义了一种新的语言

sass的扩展名为 .sass 老版本 控制缩进不需要使用 {} 或 ;     // 类似jade

sass的扩展名为 .scss 新版本 与正常css写法相同

其它预处理:

    Sass(SCSS)
    LESS
    Stylus
    Turbine
    Swithch CSS
    CSS Cacheer
    DT CSS

变量声明

一、$ 声明变量

    1、作为值使用
        $color: '#ccc';
        .test{
            background-color: $color;        // 调用
        }

    2、作为属性名使用
        $side : left;
        .rounded {
            border-#{$side}-radius: 5px;    // 输出 border-left-radius: 5px
        }

二、!default 默认变量使用

    默认值在组件中很有作用

    $baseLineHeight: 2;
    $baseLineHeight: 1.5 !default;            // 在没有定义baseLineHeight值时,执行1.5的默认值
    body{
        line-height: $baseLineHeight;    // line-hgiht: 2;
    }

三、全局变量和局布变量

    // 全局变量定义
    $color: orange !default;        
    .block {
        color: $color;
    }

    // 局部变量定义
    em {
        $color: red;
        a {
            color: $color;
        }
    }

嵌套

一、选择器嵌套

    nav {
        a {
            color: red;

            header & {
                color:green;
            }
        }  
    }
    输出:
        nav a { color: red; }
        header nav a { color: green; }

    nav {
        a {
            color: red;

            header & {
                color:green;
            }
        }  
    }
    输出:
        .nav a { color: red }
        .header .nav a { color:green }


二、属性嵌套

    .box {
        border: {
            top: 1px solid red;
            bottom: 1px solid green;
        }
    }
    输出: .box {  border-top: 1px solid red; border-bottom: 1px solid green; }


三、伪类嵌套

    .clearfix{
        &:before,
        &:after {
            content:"";
            display: table;
        }
        &:after {
            clear:both;
            overflow: hidden;
        }
    }

    输出
    clearfix:before, .clearfix:after {
        content: "";
        display: table;
    }
    .clearfix:after {
        clear: both;
        overflow: hidden;
    }

混合宏和声明混合宏

宏相当将一些属性封装到一个宏中,类似函数可重复利用

一、使用“@mixin”声明一个混合宏

    @mixin border-radius {
        -webkit-border-radius: 5px;
        border-radius: 5px;
    }

    .text { 
        @include border-radius            /* 调用宏 */
    }


二、定义带参数的宏

    @mixin border-radius($radius:5px){        // 定义一个默认值为5px
        -webkit-border-radius: $radius;
        border-radius: $radius;
    }

    .text { 
        @include border-radius(10px)         // 调用
    }


带逻辑运算符

    @mixin box-shadow($shadow...) {
        @if length($shadow) >= 1 {
            @include prefixer(box-shadow, $shadow);
        } 
        @else{
            $shadow:0 0 4px rgba(0,0,0,.3);
            @include prefixer(box-shadow, $shadow);
        }
    }

扩展和继承

继承是可以直接继承一个class类下所有的属性,

@extend .className;

.btn {
    border: 1px solid #ccc;
    padding: 6px 10px;
    font-size: 14px;
}

.btn-primary {
    background-color: #f36;
    color: #fff;
    @extend .btn;
}

.btn-primary-2 {
    background-color: #f36;
    color: #fff;
    font-size: 16px;
    @extend .btn;
}


结果:
.btn, .btn-primary, .btn-primary-2 {
    border: 1px solid #ccc;
    padding: 6px 10px;
    font-size: 14px; 
}

.btn-primary {
    background-color: #f36;
    color: #fff; 
}

.btn-primary-2 {
    background-color: #f36;
    color: #fff;
    font-size: 16px; 
}

占位符

定义占位符 %名称 , 调用使用@extend

%mt5 {
    margin-top: 5px;
}
%pt5{
    padding-top: 5px;
}

.btn {
    @extend %mt5;
    @extend %pt5;
}
.block {
    @extend %mt5;

    span {
        @extend %pt5;
    }
}

结果
.btn, .block {
    margin-top: 5px; 
}
.btn, .block span {
    padding-top: 5px; 
}

插值#{}

可以将变量与属性结合

$properties: (margin, padding);
@mixin set-value($side, $value) {
    @each $prop in $properties {
        #{$prop}-#{$side}: $value;
    }
}
.login-box {
    @include set-value(top, 14px);
}

结果:
.login-box {
    margin-top: 14px;
    padding-top: 14px;
}

注释

// 不会被显示到代码中

/* */  显示到代码中

数据类型

1、数字: 如,1、 2、 13、 10px

2、字符串:有引号字符串或无引号字符串,如,"foo"、 'bar'、 baz

3、颜色:如,blue、 #04a3f9、 rgba(255,0,0,0.5)

4、布尔型:如,true、 false

5、空值:如,null

6、值列表:用空格或者逗号分开,如,1.5em 1em 0 2em 、 Helvetica, Arial, sans-serif

函数

一、字符串函数

    1、unquote(str): 删除字符串中的引号

    2、quote(str): 给字符添加引号

        .test1 {
            content:  unquote('Hello Sass!') ;        // 输出 content: Hello Sass
        }

        .test3 {
            content: quote(ImWebDesigner);        // 输出 content: 'ImWebDesigner';
        }

    3、to-upper-case(): 转大写

    4、to-lower-case(): 转小写


二、数字函数

    1、percentage($value):将一个不带单位的数转换成百分比值;

        .footer{  width : percentage(5px / 10px)  }      // width: 50%

    2、round($value):将数值四舍五入,转换成一个最接近的整数;

    3、ceil($value):将大于自己的小数转换成下一位整数;

    4、floor($value):将一个数去除他的小数部分;

    5、abs($value):返回一个数的绝对值;

    6、min($numbers…):找出几个数值之间的最小值;

    7、max($numbers…):找出几个数值之间的最大值;

    8、random(): 获取随机数

三、列表函数

    1、nth函数(nth function) 可以直接访问值列表中的某一项;

    2、join函数(join function) 可以将多个值列表连结在一起;

    3、append函数(append function) 可以在值列表中添加值; 

    4、@each规则(@each rule) 则能够给值列表中的每个项目添加样式。

四、判断函数类型

    1、type-of($value):返回一个值的类型

    2、unit($number):返回一个值的单位

    3、unitless($number):判断一个值是否带有单位

    4、comparable($number-1, $number-2):判断两个值是否可以做加、减和合并

五、unitless(): 用来判断一个值是否带有单位,如果不带单位返回的值为 true,带单位返回的值为 false

    @mixin adjust-location($x, $y) {
        @if unitless($x) {    
            $x: 1px * $x;
        }
        @if unitless($y) {    
            $y: 1px * $y;
        }
        position: relative; 
        left: $x; 
        top: $y;
    }

    .botton{
        @include adjust-location(20px, 30);
    }

六、comparable(): 用来判断两个数是否可以进行“加,减”以及“合并”, 返回true/false

     comparable(2px,1rem)


七、三元函数: if(true,8em,20em);        // 第一个参数为


八、map 在Sass中,maps代表一种数据类型,可以包含若干键值对的对象类型

    创建一个map数据:

        $color: (
            default: #fff,
            primary: #222,
            negative: #333
        );        // 注意必须加 “;” 号 

        .box {
            color: map-get($color, default);
        }


    获取map数据的函数:

    1、map-get($map,$key):根据给定的 key 值,返回 map 中相关的值。

    2、map-merge($map1,$map2):将两个 map 合并成一个新的 map。

    3、map-remove($map,$key):从 map 中删除一个 key,返回一个新 map。

    4、map-keys($map):返回 map 中所有的 key。

    5、map-values($map):返回 map 中所有的 value。

    6、map-has-key($map,$key):根据给定的 key 值判断 map 是否有对应的 value 值,如果有返回 true,否则返回 false。

        @function colors($color){
            @if not map-has-key($social-colors,$color){
                @warn "No color found for `#{$color}` in $social-colors map. Property omitted.";
            }
            @return map-get($social-colors,$color);
        }

    7、keywords($args):返回一个函数的参数,这个参数可以动态的设置 key 和 value。


九、REG

    rgb($red,$green,$blue):根据红、绿、蓝三个值创建一个颜色;

    rgba($red,$green,$blue,$alpha):根据红、绿、蓝和透明度值创建一个颜色;

    red($color):从一个颜色中获取其中红色值;

    green($color):从一个颜色中获取其中绿色值;

    blue($color):从一个颜色中获取其中蓝色值;

    mix($color-1,$color-2,[$weight]):把两种颜色混合在一起。

Sass规则

一、@import: 用于引用scss或sass文件

二、@media: 媒体查询功能

    .sidebar {
        width: 300px;
        @media screen and (orientation: landscape) {
            width: 500px;
        }
    }

    输出:
    .sidebar {
        width: 300px; 
    }
    @media screen and (orientation: landscape) {
        .sidebar {
            width: 500px; 
        }
    }

自定义函数

SASS允许用户编写自己的函数。

// 定义函数

  @function double($n) {
    @return $n * 2;
  }

// 调用函数

  #sidebar {
    width: double(5px);
  }

高级语句

一、条件语句

    @if lightness($color) > 30% {
    background-color: #000;
  } 
    @else {
    background-color: #fff;
  }


二、循环语句

    @for $i from 1 to 10 {
    .border-#{$i} {
      border: #{$i}px solid blue;
    }
  }


  $i: 6;
  @while $i > 0 {
    .item-#{$i} { width: 2em * $i; }
    $i: $i - 2;
  }


    $list: adam john wynn mason kuroir;        //$list 就是一个列表
    @mixin author-images {
        @each $author in $list {
            .photo-#{$author} {
                background: url("/images/avatars/#{$author}.png") no-repeat;
            }
        }
    }

运算

+、-、*、/

$container: 960px;
$sidebar-width: 220px;
$gap-width: 20px;
.content{
    width: $container - $sidebar-width;
    float: left;
}

结果:
.content {
    width: 740px;
    float: left; 
}

颜色计算
p {
    color: #010203 + #040506;
}

Sass的目录结构

sass/
|
|– base/
| |– reset.scss # Reset/normalize
| |– typography.scss # Typography rules
| … # Etc…
|
|– components/
| |– buttons.scss # Buttons
| |– carousel.scss # Carousel
| |– cover.scss # Cover
| |– dropdown.scss # Dropdown
| |– navigation.scss # Navigation
| … # Etc…
|
|– helpers/
| |– functions.scss # Sass Functions
| |– mixins.scss # Sass Mixins
| |– helpers.scss # Class & placeholders helpers
| … # Etc…
|
|– layout/
| |– grid.scss # Grid system
| |– header.scss # Header
| |– footer.scss # Footer
| |– sidebar.scss # Sidebar
| |– forms.scss # Forms
| … # Etc…
|
|– pages/
| |– home.scss # Home specific styles
| |– contact.scss # Contact specific styles
| … # Etc…
|
|– themes/
| |– theme.scss # Default theme
| |– admin.scss # Admin theme
| … # Etc…
|
|– vendors/
| |– bootstrap.scss # Bootstrap
| |– jquery-ui.scss # jQuery UI
| … # Etc…
|
|- variables.scss # 存储Sass变量文件
|
`– main.scss # primary Sass file

| http://www.w3cplus.com/preprocessor/organize-that-sass.html # 组织Sass文件
| http://www.w3cplus.com/preprocessor/architecture-sass-project.html # SASS的目录结构
| http://www.w3cplus.com/blog/tags/302.html

Hanlebars.js 模板引擎

| 涉及知识点
|
|

headlebars介绍

Handlebars 是 JavaScript 一个语义模板库,通过对view和data的分离来快速构建Web模板。它采用"Logic-less template"(无逻辑模版)的思路,在加载时被预编译,而不是到了客户端执行到代码时再去编译, 这样可以保证模板加载和运行的速度。Handlebars兼容Mustache,你可以在Handlebars中导入Mustache模板。

下载与安装

1、下载handlebars.js文件在页面中直接引用

2、通过npm下载,require('handlebars')直接引用

使用Handlebars

<!-- 编译模板后输出的位置 -->    
  <div id="tableList"></div>

<!-- 定义的模板 -->
<script id="table-template" type="text/x-handlebars-template">
    {{date.year}} 年 {{date.month}} 月 {{date.day}} 日 <br>
    <table>
      {{#each person}}
           <tr>
          <td>姓名:{{name}}, 年龄:{{age}}</td>
        </tr> 
      {{/each}}
      </table>
</script>

<!--插件引用-->
<script src="js/lib/zepto.js"></script>
<script src="js/lib/handlebars.min.js"></script>
<script type="text/javascript">
  $(document).ready(function() {

    // 模拟的json对象
    var data = {
        date: {
            year: '2016',
            month: '12',
            day: '26'
        },
        person: [
            {name: 'siguang', age: 20},
            {name: 'lulu', age: 20},
            {name: 'haha', age: 20},
            {name: 'heihei', age: 20}
        ]
    }

     // 预编译模板
    var myTemplate = Handlebars.compile($("#table-template").html());

    //将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
    $('#tableList').html(myTemplate(data));

  });
</script>

handlebars语句

1、{{#each 对象 }}  循环数据

<script id="table-template" type="text/x-handlebars-template">
  {{#each student}}
    <tr>
      <td>{{name}}</td>
      <td>{{sex}}</td>
      <td>{{age}}</td>
    </tr> 
  {{/each}}
</script>


2、{{#each }} 嵌套

    {{#each this}} each中的this

    <!-- 定义的模板 -->
    <script id="table-template" type="text/x-handlebars-template">
        {{#each this}}
            {{#each info}}
                <!-- 这里取name 使用../到上一层来取, info数组内容使用this来输出 -->
                {{../name}}的{{this}}<br>
            {{/each}}
        {{/each}}
    </script>


    <script src="js/lib/zepto.js"></script>
    <script src="js/lib/handlebars.min.js"></script>
    <script type="text/javascript">
    $(document).ready(function() {
        //模拟的json对象
        var data = [
             {
                "name":"张三",
                "info":[
                    "眼睛",
                    "耳朵",
                    "鼻子"
                ]
            },
            {
                "name":"李四",
                "info":[
                    "爸爸",
                    "妈妈",
                    "妻子"
                ]
            }
        ];

        var myTemplate = Handlebars.compile($("#table-template").html());
        $('#dataList').html(myTemplate(data));
      });
    </script>


3、@index 访问父级索引

    <script id="table-template" type="text/x-handlebars-template">
        <table>
        {{#each this}}
            <tr>
                <td>{{addOne @index}}.</td>
                <td>{{name}}</td>
                <td>{{sex}}</td>
                <td>{{age}}</td>
            </tr>
        {{/each}}
        </table>
    </script>

    <!--进行数据处理、html构造-->
    <script type="text/javascript">
        var data = [
            {
                name: "张三",
                sex: "男",
                age: 35
            },{
                name: "李四",
                sex: "男",
                age: 23
            },{
                name: "甜妞",
                sex: "女",
                age: 18
            }
        ];

        // 注册索引+1的helper
        var handleHelper = Handlebars.registerHelper("addOne",function(index){
            //返回+1之后的结果
            return index+1;
        });

        //解析模版
        var handle = Handlebars.compile($("#table-template").html());
        //生成html
        var html = handle(data);
        //插入到页面
        $("#dataList").append(html);
    </script>


4、#with 循环时进行到某一个上下文

    <script id="table-template" type="text/x-handlebars-template">
    <table>
        {{#each this}}
        <tr>
            <td>{{name}}</td>
            <td>{{sex}}</td>
            <td>{{age}}</td>
            <td>
                <!-- 这里通过 #with 直接找到favorite数组 -->
                {{#with favorite}}
                {{#each this}}
                <p>{{name}}</p>
                {{/each}}
                {{/with}}
            </td>
        </tr> 
        {{/each}}
    </table>

    </script>

    <!--进行数据处理、html构造-->
    <script type="text/javascript">
    $(document).ready(function() {
        //模拟的json对象
        var data = [
                {
                    "name": "张三",
                    "sex": "0",
                    "age": 18,
                    "favorite":
                    [
                      {
                        "name":"唱歌"
                      },{
                        "name":"篮球"
                      }
                    ]
                },
                {
                    "name": "李四",
                    "sex": "0",
                    "age": 22,
                    "favorite":
                    [
                      {
                        "name":"上网"
                      },{
                        "name":"足球"
                      }
                    ]
                },
                {
                    "name": "妞妞",
                    "sex": "1",
                    "age": 18,
                    "favorite":
                    [
                      {
                        "name":"电影"
                      },{
                        "name":"旅游"
                      }
                    ]
                }
            ];

        // 注册一个Handlebars模版,通过id找到某一个模版,获取模版的html框架
        var myTemplate = Handlebars.compile($("#table-template").html());

        // 将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
        $('#dataList').html(myTemplate(data));
    });
    </script>

5、{{#if }} 判断

     <script id="table-template" type="text/x-handlebars-template">
        {{#each student}}
            {{#if name}}
                <tr>
                    <td>{{name}}</td>
                    <td>{{sex}}</td>
                    <td>{{age}}</td>
                </tr>
            {{/if}}
        {{/each}}
    </script>


6、registerHelper() 注册handlebars

    需要用到js处理并返回数据需要用到注册,类似过滤器

    <script id="table-template" type="text/x-handlebars-template">
    {{#each student}}
        {{#if name}}

            <!-- compare 注册名, age 20 为参数 -->
            {{#compare age 20}}
                <tr>
                    <td>{{name}}</td>
                    <td>{{sex}}</td>
                    <td>{{age}}</td>
                </tr>
            {{else}}
                <tr>
                    <td>?</td>
                    <td>?</td>
                    <td>?</td>
                </tr>
            {{/compare}}
        {{/if}}
    {{/each}}
    </script>

    //注册一个比较大小的Helper,判断v1是否大于v2
    Handlebars.registerHelper("compare",function(v1,v2,options){
        if(v1>v2){
            //满足添加继续执行
            return options.fn(this);
        }
        else{
            //不满足条件执行{{else}}部分
            return options.inverse(this);
        }
    });

| 参考资料
| http://www.cnblogs.com/iyangyuan/archive/2013/12/12/3471227.html

ES6

| let块级作用域、 const常量
| 解构赋值
| 箭头函数、default、rest、spread
| 模板字符串
| class: extends、super、constructor、静态属性和方法、实例属性
| Promise、Generator、async/await
| 模块化: import、export、as、*、default export
| 数据结构: Set不重复值的集合、Map
| Proxy 对象的拦截器
| Symbol
| symbol 独一无二的值
| Set、Map数据结构

let和const

一、let 声明变量

    let完全可以取代var, 特性: 1、let不允许重复声明        2、没有预解析功能        3、块级作用域

    1、预解析功能

        console.log(a);        // 报错, 如果是原来的var声明这里会是undeined, 所以let没有预解析功能
        let a = 20;

    2、块级作用域 在{ }中声明的变量只能在括号里使用

        var name = 'lulu';
        function prsone(){
            let name = 'siguang';
        }

        prsone();
        console.log(name);            // 'lulu'

        // 输出的都是10
        for(var i=0; i<10; i++){
            setTimeout(function(){
                console.log(i);        // 使用var声明的i都会打印出9,如果使用let输出的就是0到10
            })
        }

二、const常量

    1、常量只允许赋一次值不能被修改        2、常量声明都为大写        3、与let相当只在块级作用域有效

    const NAME = 'siguang';        // 不能变化的值
    NAME = 'lulu';                // 报错

    if (true) {
        const MAX = 5;
    }
    MAX            // 报错,const与let相同都是在块内使用

解构赋值

允许从数组和对象中提取的值,对变量进行赋值,被称为解构赋值

一、数组解构使用[]

    let [a, b, c] = [1, 2, 3];    // a=1, b=2, c=3

    // 默认值
    let [x, y = 'b'] = ['a'];     // x='a', y='b'


二、对象解构使用{}

    // 对象是按名字来解析赋值
    let obj = {
        getName: function(){}, 
        foo: 'aaa', 
        bar: 'bbb'
    };
    let {foo, bar} = obj        // foo='aaa', bar='bbb'

    // 对象的解构赋值,先找到同名,在将值赋给对应的变量
    let { foo: val, bar } = { foo: "aaa", bar: "bbb" };  
    console.log(val, bar)        // foo='undefined', val='aaa', bar='bbb'


三、字符串的解构赋值

    const [a, b, c, d, e] = 'hello';    // a=h, b=e, c=l, d=l, e=o
    const [...tail] = 'hello';            // ['h', 'e', 'l', 'l', 'o']

    # length属性
    let {length: len} = 'hello';        // length = 5


四、默认参数 default

    # 参数作为数组
    function add([x, y]){
        return x * y
    }
    add([3,2]);        // 6

    # 参数作为对象,对x、y的默认初始值
    function move({x = 0, y = 0}) {
        return [x, y];
    }
    move({x: 3, y: 8}); // [3, 8] 


五、不定参数 Rest

    function f(x, ...y) {
        // y是一个数组
        return x * y.length;
    }
    f(3, "hello", true) == 6


六、扩展运算符 Spread

    function f(x, y, z) {
        return x + y + z;
    }
    // 将数组中的每个元素展开为函数参数
    f(...[1,2,3])            // 6

模板字符串

一、写到`...`之间,值的输出使用 ${...} 

二、可以写多行字符串,只写到`...`之间就可以

三、${...}可以解析变量、对象的值、表达式、函数返回

    let name = 'siguang';
    let obj = {
        age: 33
    }
    console.log(`你的名字是: ${ name } 你的年龄是:  ${ obj.age }`)

四、标签模板

    let a=10, b=20;
    dialog`Hello ${a+b} world ${a*b}`;        // 等同于 dialog()

函数扩展

一、箭头函数

    1、箭头函数的注意问题: 

        * 箭头函数里的this不是指向调用者,而指向对象
        * 不能当构造函数来用, 不能使用new
        * 函数内不存在arguments对象
        * 不可以使用yield命令,箭头函数不能用作Generator函数

        arr.sort(function(){  ...  }) 相当于 arr.sort((a, b) => a-b);

        // 箭头函数的this,不是指向调用者
        const Template = {
            test(){
                console.log(this);        // this指向Template

                document.querySelector("#showThis").onclick = () =>{
                    /* 如果非箭头函数this应该指向 #showThis */
                    /* 这里箭头函数不是指向调用者,所以指向了 Template */
                    console.log(this);    
                }
            }
        }
        Template.test();

    2、var f = function(v){ return v; }

        // ES6写法
        var f = v => v;

    3、var sum = function(num1, num2){
            return num1 + num2;
        }

        // ES6写法
        var sum = (num1, num2) => {
            return num1 + num2;
        }

    4、对象中方法的简写

        var obj = {
            name: 'haha',
            getName(){                // 是getName: function(){}的简写
                console.log(this.name);
            },
            setName(name){
                this.name = name;
                console.log(this.name);
            }
        }


二、函数参数默认值

    function fn(a, b = 2){
        // b如果不传相当于2,等同于 var b = arguments.length > 1 && arguments[1] == undefined ? arguments[1] : 2;
        return {a, b}
    }
    console.log(fn(10));        // 返回{a: 10, b: 2}

    // 如果没有参数默认值时还需要在函数体内做兼容
    function fn(name){
        var getName = name || 20;
    }
    fn();


三、参数的解构赋值

        const full = ({ first, last }) => first + ' ' + last;    
        full({first: 20, last: 30})

        // 等同于
        // function full(person) {
        //      return person.first + ' ' + person.last;
        // }


四、rest 获取多余参数

    以'...变量名' 来获取多余的参数,返回一个数组,这样就不需要arguments对象了

    function person(...rest){
        console.log(rest);        // [1,2,3,4,5]
    }
    person(1,2,3,4,5);

    function person(a, ...rest){
        console.log(a);            // 1
        console.log(rest);        // [2,3,4,5]
    }
    person(1,2,3,4,5);


五、spread 扩展操作符 ...  与rest相反

    function add(x, y) {
        return x + y;        // 4+38
    }
    var numbers = [4, 38];            // 只能为数组不能为对象
    add(...numbers)         // 42

    # 可以将字符串转成数组
    let arr = [...'hello'];        // ['h', 'e', 'l', 'l', 'o']


六、name属性

    funciton foo(){ ... }
    foo.name;        // 'foo' 返回函数名


七、::运算符

    箭头函数可以绑定this对象,减少显式this对象的写法(call、apply、bind)

    ES7提出了函数绑定来取代"call、apply、bind"调用,使用两个"::"

    foo::bar;        // 等同于 bar.bind(foo);
    foo::bar(...arguments);        // 等同于 bar.apply(foo, arguments);

类、继承

一、类的一些特性

    1、对象方法的简写方法
        class Cat{
            getName(){        // 老写法 getName: function(){}
                ...
            }
        }

    2、通过__proto__属性可以直接调用父类
        var parent = {
            getParentName(){
                console.log('parent')
            }
        }

        var childer = {
            __proto__: parent,            // 通过__proto__指向parent, 就可以直接调用parent类中的方法
            getChildeName(){
                console.log('childer');
            }
        }

        childer.getChildeName();    // childer
        childer.getParentName();    // parent


二、创建类

    class Cat {
        // ES6中新型构造器, 用来初始化时这里接收参数
        constructor(name){ 
            this.name = name;
        }

        getName(){        // 公有方法
            console.log(this.name);
        }

        static bar(baz){        // 私有方法
            debugger;
            return this.name = baz;
        }

        * gen(){
            let arg = 10;
            yield arg;
        }
    }

    Cat.userName = 'siguang';

    var oCat = new Cat('哈哈');
    oCat.getName();
    oCat.bar('lulu');                // 报错静态方法调用不到,并且不会被继承
    oCat.gen().next()


三、继承 extends

    // 创建一个类
    class Person {
        constructor(name){
            this.name = name;
        }

        getName(){
            console.log(this.name);
        }
    }

    // 继承这个类
    class Children extends Person {
        constructor(name, color){
            super(name);                // super指向继承的构造函数Person的constructor
            this.color = color;
        }

        getColor(){
            console.log(this.name, this.color);
        }
    }

    // 实例化
    var op = new Person('siguang');
    op.getName();            // 'siguang'

    var oc = new Children('lulu', 'red');        
    oc.getColor();        // 'red'
    oc.getName();            // 'lulu'


四、static 静态属性和方法

    类似构造函数,直接挂载到函数下的叫对象的属性和方法,而写到构造函数内部的叫构造函数的属性和方法

    1、静态方法前面需要加上'static'关键字,相当于只是函数下的方法而不是prototype的方法,静态方法可以被子类继承,

        class Foo{
            static methodName(){
                return 'hello'
            }
        }
        Foo.methodName();    // hello

        var foo = new Foo();
        foo.methodName();    // 报错

    2、静态属性

        ES6中没有静态属性,只能声明静态方法,ES7中可以直接写到类内在进行转码

        class Foo {
            constructor(...arg){
                this.args = args;
            } 
            outputUserName(){
                console.log(this.username);    // 这里username未定义,除非在constructor中定义 this.username
            }
        }
        Foo.username = 'siguang';       // 类的静态属性

        var foo = new Foo();
        console.log(foo.personName);  // undefined
        foo.outputUserName();               // undefined 


五、实例属性

    注意: 一定要将实例属性和静态属性区分,实例属性写到constructor中this.username, new后的实例时候可以被实例方法调用,而静态属性只挂到了类下直接通过类来调取,Foo.username

    class Foo{
        constructor(){
            this.username = 'siguang';
        }
        showName(){
            console.log(this.username);     // siguang
            console.log(Foo.username);      // lulu
        }
    }
    Foo.username = 'lulu';

    var foo = new Foo();
    foo.showName();

    ****** ES7 中静态属性和实例属性的定义 ******
    class MyClass{
        usernameA = 'siguang';        // 实例属性

        showName(){
            console.log(this.usernameA);
        }
    }


六、super()方法

    继承时必须调用一次super方法,否则constructor中的this为undefined,调用父类的构造器进行初始化, 子类调用父类的构造函数

    class BaseModel {
        constructor(options, data) { // class constructor,node.js 5.6暂时不支持options = {}, data = []这样传参
            this.name = 'Base';
            this.url = 'http://azat.co/api';
            this.data = data;
            this.options = options;
        }
        getName() { // class method
            console.log(`Class name: ${this.name}`);
        }
    }

    class AccountModel extends BaseModel {
        constructor(options, data) {
            super({private: true}, ['3333', '4444']); 
            this.name = 'Account Model';
            this.url +='/accounts/';
        }
        getAccountsData() {
            return this.data;
        }
    }

    let accounts = new AccountModel(5);
    accounts.getName();         // Account Model
    console.log('Data is %s', accounts.getAccountsData);        // {private: true}

    let base = new BaseModel({public: true}, ['111', '2222']);
    console.log(base.getName());        // Base


七、class中的Generator方法

    方法前面加" * " 号表示该方法是Generator函数

    class MyClass = {
        constructor(){
            ...
        }

        * getName(){
            ...
        }
    }

Module 模块

一、import: 模块加载

    // 取整个对象
    import $ from 'jquery';

    // 通过解构取对象
    import {name1, name2, nam3} from './user.js';

    // 通过逗号分两整体和解构分别来取
    import React, { Component, PropTypes } from 'react';

    // 重命名
    import * as React from 'react';        // * 对整体模块加载,并通过as转换一个名

    // 按需加载
    button.addEventListener('click', event => {
        imoprt('dialog.js')
            .then(dialog => {
                dialog.show();
            }).
            catch(err =>{
                // error
            })
    }, false)


    不同写法

        1、普通写法

            meat.js
                export function beef(){
                    return '牛肉';
                }
                export function pork(){
                    return '猪肉';
                }

            main.js

                import { beef, pork } from 'meat.js';
                console.log(beef());        // 牛肉
                console.log(pork());        // 猪肉


        2、key的简写

            var fn1 = function(){
                console.log('fn1');
            }
            var fn2 = function(){
                console.log('fn2');
            }

            export {fn1, fn2}         // 对象名与key相同可以写成一个


二、export: 模块输出

    1、使用对象简写方式

        var name1 = 'aaa';
        var name2 = 'bbb';
        var name3 = 'ccc';
        export {name1, name2, name3} 

        // 也可以写成    
        export var name1 = 'aaa';
        export var name2 = 'bbb';
        export var name3 = 'ccc';


    2、可以直接输出变量、函数或类

        export function person(){ ... }

        // 不能直接输出变量名
        var name = 'siguang';
        export name;            // 报错

        写成: export var name = 'siguang';        
        写成: var name = 'siguang';   export {name};    


    3、跨模块常量

        const常量只能在当前代码下使用,通过export可以进行跨模块常量,多个文件都可以使用

        export const name = 'siguang';
        export const age = 33;

        import * as info from 'userinfo';        // 或 import { name, age } from 'userinfo'


三、as 关键字来修改名字

    meat.js

        export function beef(){
            return '牛肉';
        }

        export function pork(){
            return '猪肉';
        }

    main.js

        // * 代表meat.js下所有的对外接口,转换成meat对象下,这样就可以通过meat来调用meat下的
        import * as meat from './meat.js';        
        console.log(meat.beef());        // 牛肉
        console.log(meat.pork());        // 猪肉


四、* 将somModule内的所有导出接口

    import * as newSome from './someModule'        // 将someModule类的所有接口更改到newSome下


五、export default指定匿名

    不使用default在import加载定义名与导出名必须相同,否则无法加载,如果指定默认输出使用export default,在import导入的时候不用在关心命名的问题

    1、meat.js

        // 倒出匿名函数
        export default function() {
            console.log('foo');
        }

        简写
        export default(){        // export default {}  写成默认对象

        }

    main.js

        // 导入时可以任意起名
        import beef from './meat.js'


    2、default与不写default输出的区别

        // 使用default来输出,import不需要使用{}
        export default function crc32() {
            // ...
        }
        import crc32 from 'crc32';

        // 不使用default来输出,import需要使用 {}
        export function crc32() { // 输出
            // ...
        };
        import {crc32} from 'crc32'; // 输入

Set、Map数据结构

一、Set(): 类似数组的一种新结构,成员都是唯一的值没有重复值,相当于数组去重

    # 数组去重的新方法
    let setValue = new Set([1,2,33,1,22,2,2,4,2,1,2])
    console.log(setValue, Object.prototype.toString.call(setValue));        // {size: 5, [1, 2, 33, 22, 4]}, '[Object Set]'
    let arr = [...setValue];        // [1, 2, 33, 22, 4] 需要进行解构

    特性: 
        1、不允许数组里有重复数据

    方法: 
        1、set.size: 获取数据的长度

        2、set.add(value): 添加值

        3、set.delete(value): 删除set的实例值

        4、set.has(value): 传入的参数是否为set的成员

        5、set.clear(): 删除set的所有成员


二、Map(): 将二维数组转成对象

    var map = new Map([['username', 'siguang'], ['password', 'ssssss']]);
    map.get('username');        // siguang

    /* new Map([['usernmae', 'aaa', 'password', 'ssssss'], ['aaaa', 1111]]);  注意一个数组中只有两个下标的值,这里只能get到username, password不会取到 */

    特性: 不允许有重复的key值

    方法: 
        1、map.size: 成员总数

        2、map.set('key', 'value'): 添加成员

        3、map.get(): 获取

        4、map.clear(): 清除所有

对象扩展 Object

一、简写

    1、对象属性和值相同可以写成一个

        var foo = { name: 'siguang'};
        var baz = {
            foo            // foo: foo 相同
        };
        console.log(baz.foo.name);    // siguang

    2、对象中函数简写

        var o = {
            name: 'momo',
            getName(){            // 等同于 getName: function(){}
                retrun this.name;
            }
        }

    3、参数作为对象返回

        function f(x, y) { return {x, y}; }

        // 等同于
        function f(x, y) {
            return {x: x, y: y};
        }
        f(1, 2)     // Object {x: 1, y: 2}

        // 2、CommonJS模块输出变量
        const getItem = function(){ ... }
        const setItem = function(){ ... }
        const clear = function(){ ... }
        module.exports = { getItem, setItem, clear };

        // 等同于
        // module.exports = {
        //   getItem: getItem,
        //   setItem: setItem,
        //   clear: clear
        // };


二、[] 属性名表达式

    // 对象的属性名可以用'[]'字符串拼接
    var sex = '男';
    var obj = {
        name: 'momo',
        [sex]: false,
        ['get'+'Name'](){
            console.log(this.name, this['男']);        // 返回 momo false
        }
    }
    obj.getName();


三、getter 赋值器、setter 取值器

    let cat = { 
        name: '喵喵', 
        get name(){ return this.name },   
        set name(value){
            if(Object.prototype.toString.call('xxx') == '[object String]'){
                this.name += value
            }
        }
    }


四、Object.is(): 用于对比两个数字或字符串是否相等,相当于 === ,可以正确比较 -0和0,NaN和

    '=='与'==='的缺点:

        相等运算符(==)缺点: 自动转换数据类型
        和严格相等运算符(===)缺点: NaN不等于自身,以及+0等于-0

    Objetc.is(0, -0);        // false
    Object.is(NaN, NaN);    // true


五、Object.assign(目标对象, 被合并对象B, 被合并对象C): 合并对象

    /* 注意: 被合并对象与合并目标对象的属性相同会赋盖掉前面的对象的值 */
    var objA = {a: 1, b:2}, objB = {b: 3, c: 4}; 
    let req = Object.assign(objA, objB);         // {a:1, b:3, c:4}

    添加对象的方法: 
        Object.assign(SomeClass.prototype, {
            someMethod(arg1, arg2){
                // ...
            },
            anotherMethod(){
                // ...
            }
        })

        相当于
        SomeClass.prototype.someMethod = function(arg1, arg2){ // ... }
        SomeClass.prototype.anotherMethod = function(){ // ... }

    克隆对象: 
        function clone(obj){
            return Object.assign({}, obj);
        }

    注意点: 

        1、assign 是浅拷贝

        2、同名属性替换


六、getPrototypeOf(object)、setPrototype(object, 谁的prototype): 获取、设置对象的prototype

    var Cat = function(name){
        this.name = name;
    }

    Cat.prototype.showName = function(){
        return this.name;
    }

    var c1 = new Cat('momo');
    c1.showName();

    console.log(Object.getPrototypeOf(c1))

    // 设置prototype
    var Person = function(nationality){
        this.nationality = nationality;
    }
    Person.prototype = {
        showNationality: function(){
            return this.nationality;
        }
    }
    Object.setPrototypeOf(c1, Person.prototype);
    console.log(Object.getPrototypeOf(c1));


七、keys()、values()

    获取对象的所有keys或所有值, 并返回一个数组

    var obj = {name: 'siguang', age: 33};
    console.log(Object.keys(obj));        // [name, age]
    console.log(Object.values(obj));    // ['siguang', 33]


八、__proto__属性

    用来读取或设置当前对象的prototype对象

    var Person = function(name){
        this.name = name;
    }
    Person.prototype = {
        constructor: Person,
        getName(){
            console.log(this.name);
        }
    }
    var op = new Person('lulu');

    // 继承
    var PersonChilder = function(){}; 
    PersonChilder.__proto__ = op;
    var opc = new PersonChilder(); 
    console.log(opc.getName())

    增强的对象字面量

    // 通过对象字面量创建对象
    var human = {
        breathe() {
            console.log('breathing...');
        }
    };

    var worker = {
        __proto__: human, //设置此对象的原型为human,相当于继承human
        company: 'freelancer',
        work() {
            console.log('working...');
        }
    };

    human.breathe();        // 输出 ‘breathing...’

    // 调用继承来的breathe方法
    worker.breathe();        // 输出 ‘breathing...’


九、遍历属性的方法

    1、for...in 循环

    2、Object.keys(obj): 返回obj对象的所有key, 返回是一个数组

字符串对象扩展

1、repeat(): 复制字符串 

    var str = '哈哈哈!'.repeat(3);        // str输出 '哈哈哈!哈哈哈!哈哈哈!'

2、includes()、startsWith()、endsWith(): 查找三个方法

    var str = 'siguang 1983';
    str.includes('o');        // 查找字符串中是否包含值,包含返回true否则返回false
    str.startsWith('s');    // 第一个字符是不是s,如果是返回true
    str.endsWith('d');        // 最后一个字符是不是 d,返回布尔值

3、padStart(): 补全长度从开头, 'x'.padStart(4, 'ab') // 'abax'

4、padEnd(): 补全长度从结尾, 'x'.padEnd(4, 'ab') // 'xaba'

Number、Math对象扩展

一、Math扩展

    1、trunc(): 去除小数部分 Math.trunc(123.123123);    // 123

    2、sign(): 判断是正数还是负数,如果是正数返回1,负数返回-1,0返回0

    3、Math.sign(-234);    // -1

    4、hypot(): 返回所有参数的平方和的平方根,Math.hypot(3,4);    // 5 勾股定理

二、Number对象扩展

    1、isFinite(): 是否是无穷数

    2、Number.isNaN(): 是否是NaN

    3、parseInt('12.34'): es5的写法   Number.parseInt('12.34'): es6的写法,为了减少全局方法

    4、Number.isInteger(num): 判断是否是一个整数

数组扩展 Array

一、form(): 将对象转成数组

    var obj = {'0': 'a', '1': 'b', '2': 'c'};
    var arr =  Array.form(obj); console.log(arr);        // [a, b, c]


二、of(): 将一组值转成数组

    var arrA = new Array(1, 2, 3);    // 生成一个[1,2,3]
    var arrB = new Array(3);                // arrB.length  等于3 如果传一个参数这样会生成一个3个空值
    var arrC = Array.of(3);                    // [3] 解决了new Array的问题


三、find(): 找出第一个符合条件的数据元素

    // 找出数组中值大于3的第一个数
    var arr = [1,2,3,4,5,6];
    var n = arr.find(function(value, index){
        return value > 3;
    })
    console.log(n);        // 4


四、findIndex(): 找出第一个符合条件的位置,也就是所引值

五、fill(填充内容, 填充开始的位置, 填充结束的位置): 填充数组

    var arr = [1,2,3,4,5,6];
    arr.fill(7);        // 数组里全部为7
    arr.fill(7, 1, 3);    // 数组下标从1-3的值为7
    console.log(arr);


六、for...of: 遍历数组、字符串的值,但不能遍历对象

    // var arr = 'sdfsfdasdfasdf';
    var arr = [1,2,3,4,5,6];
    for(var value of arr){
        console.log(value);        // 1,2,3,4,5,6 只能将遍历出数组的值
    }


七、keys()和values(): 返回数组的Key或value

    // var arr = 'sdfsfdasdfasdf';
    var arr = [1,2,3,4,5,6];
    for(var value of arr.key()){
        console.log(value);
    }


八、entries(): 将数组的key和value一块输出

    var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
    for(var [key, value] of arr.entries()){
        console.log(key, value);
    }

    返回: 
        0 "a"
        1 "b"
        2 "c"
        3 "d"
        4 "e"
        5 "f"


九、includes(): 查看数组中是否包含指定的值

    var arr = [1, 2, 3, 4, 5];
    arr.includes(3);        // true

二进制数组 ArrayBuffer对象

二进制数组由三类对象组成: 

    ArrayBuffer对象: 代表原始的二进制数据。

    TypedArray视图: 用来读写简单类型的二进制数据。

    DataView视图: 用来读写复杂类型的二进制数据。


一、ArrayBuffer 对象

    它不能直接读写,只能通过(TypedArray和DataView)来读写。

    ArrayBuffer也是一个构造函数,可以分配一段可以存放数据的连续内存区域。

    var buf = new ArrayBuffer(32);        // 生成一段32字节的内存区域,每个字节默认为0


    属性和方法: 

    1、byteLength: 返回分配内存的字节长度

        var buffer = new ArrayBuffer(32);

        buffer.byteLength;        // 32


    2、slice(): 拷贝字节

        var buffer = new ArrayBuffer(8);

        var newBuffer = buffer.slice(0, 3);     //拷贝`buffer`对象的前三个字节(从0到3前结束),生成一个新的ArrayBuffer对象: newBuffer


    3、isView(): 返回一个布尔值,表示参数是否为ArrayBuffer的视图实例

        var buffer = new ArrayBuffer(8);
        ArrayBuffer.isView(buffer) // false

        var v = new Int32Array(buffer);
        ArrayBuffer.isView(v) // true


二、TypedArray 视图

    TypedArray数组只提供9种固定的构造函数

Symbol

JS新的数据类型,独一无二的值,凡是属性名属于Symbol类型,就是独一无二的

# 没有参数的情况
var s1 = Symbol();
var s2 = Symbol();

s1 === s2         // false

# 有参数的情况
var s1 = Symbol('foo');
var s2 = Symbol('foo');

s1 === s2         // false

一、不能与其它值进行运算

    var sym = Symbol('My symbol');
    console.log("your symbol is " + sym);        // 报错


二、toString()转成字符串

    let sym = Symbol('my symbol');
    sym.toString()    // "Symbol(my symbol)"

Proxy对象拦截器

可以监听对象身上发生变化,对操作对象属性读取时做一个拦截器

<script>
    let obj = {
        a: 1,
        b: 2
    }

    // 相当于操作对象属性时的一个拦截器
    let oProxy = new Proxy(obj, {
        get(obj, key) {
            return obj[key];
        },
        set(obj, key, value) {
            // 这里来做拦截,如果修改的key=a 并且 value值小于10不会就将值修改
            if (key == 'a' && value < 10) {
                obj[key] = value;
            }
        }
    })

    // 设置属性
    oProxy.a = 9; // {a: 9, b: 2}
    oProxy.a = 20; // {a: 9, b: 2}
    oProxy.b = 10; // {a: 9, b: 20}

    // 获取属性值
    console.log(oProxy.a, oProxy.b);    
</script>

Promise异步

// resolve: 成功、reject: 失败
var pro = new Promise(function(resolve, reject){        // resolve成功, reject失败
    // 将一个耗时长的任务放到执行器里
    setTimeout(function(){
        resolve();            // 4毫秒后执行成功
    }, 400)
})

pro.then(
    function(){                        // reslove回调
        console.log('成功执行');
    },
    function(){                        // reject回调
        console.log('失败执行');
    }
)
.catch(function(e){            // 捕获异常,如果then中的两个方法成功失败有报错就会走catch
    console.log(e)
})

// 如果不需要reslove的回调可以设置为null
por.then(null, functino(){
    console.log('失败执行')
})


方法: 
一、Promise.all([实例1,实例2,实例3]): 用于多个promise实例,当三个实例都为真的时候all这个结果为真

    var p1 = new Promise(function(resolve, reject){
        setTimeout(function(){
            resolve();
            console.log("p1完成");
        }, 400);
    })

    var p2 = new Promise(function(resolve, reject){
        setTimeout(function(){
            resolve();
            console.log("p2完成");
        }, 1000);
    })

    var p3 = new Promise(function(resolve, reject){
        setTimeout(function(){
            resolve();
            console.log("p3完成");
        }, 4000);
    })

    var p4 = Promise.all([p1, p2, p3]);
    p4.then(function(){
        console.log('三个全部执行成功')
    }, function(){
        console.log('失败')
    })

二、Promise.race([实例1,实例2,实例3]): 只要有一个为成功,p4为成功,与all()方法正反

https://www.jianshu.com/p/c98eb98bd00c

Generator

Generator是一个状态机,封装了多个内部状态, 也是一个遍历对象生成函数,返回遍历器对象

Example: 

    function* ouputGenerator() {
        yield 'hello';            // 调用后不会马上执行,只有调用next()才会返回
        yield 'world';
        return 'ending';
    }
    let gen = ouputGenerator();

    console.log(gen.next());     // {value: "hello", done: false}  value就是返回值
    console.log(gen.next());     // {value: "world", done: false}
    console.log(gen.next());     // {value: "ending", done: true}  done为true就是后面没有yeild的定义


一、Generator的特征:

    1、function 关键字与函数名之间有一个"*"号

    2、函数体内有 yield 语句

    3、可以执行暂停

    4、generator也可以不用yield, 但需要执行一次next()


二、属性和方法

    1、next() 可以带一个参数,参数可以是上一个yield的返回值

        done为true 表示结束  Object {value: "ending", done: true}

    2、value: 就是next返回的值,done为false表示已经结束

    3、yield: 定义表达式


三、Generator与Promise的区别

    promise如果写多个嵌套会很麻烦:

        getArticleList()
            .then(articles => getArticle(articles[0].id))
            .then(article => getAuthor(article.authorId))
            .then(author => {
                alert(author.email);
            });

        function getAuthor(id){
            return new Promise(function(resolve, reject){
                $.ajax("http://beta.json-generator.com/api/json/get/E105pDLh",{
                    author: id
                }).done(function(result){
                    resolve(result);
                })
            });
        }

        function getArticle(id){
            return new Promise(function(resolve, reject){
                $.ajax("http://beta.json-generator.com/api/json/get/EkI02vUn",{
                    id: id
                }).done(function(result){
                    resolve(result);
                })
            });
        }

        function getArticleList(){
            return new Promise(function(resolve, reject){
            $.ajax(
                "http://beta.json-generator.com/api/json/get/Ey8JqwIh")
                .done(function(result){
                    resolve(result);
                }); 
            });
        }


    Generator的写法:

        function* run(){
            var articles = yield getArticleList();
            var article = yield getArticle(articles[0].id);
            var author = yield getAuthor(article.authorId);
            console.log(author.email);  
        }

        var gen = run();
        gen.next().value
            .then(articles => {
                gen.next(articles).value.then(article => {
                    gen.next(article).value.then(author => {
                    gen.next(author)
                })
            })
        })

async、await

async 是ES7引入的函数,使的异步变得更加方便

await: 命令后面是一个Promise对象

Generator函数执行必须靠执行器,也就是需要调next(),async函数有自带的执行器,async返回的是Promise对象

一、async的多种声明

    // 函数声明
    async function foo() {}

    // 函数表达式
    const foo = async function () {};

    // 对象的方法
    let obj = { async foo() {} };
    obj.foo().then(...)

    // Class 的方法
    class Storage {
        constructor() {
            this.cachePromise = caches.open('avatars');
        }

        async getAvatar(name) {
            const cache = await this.cachePromise;
            return cache.match(`/avatars/${name}.jpg`);
        }
    }

    // 箭头函数
    const foo = async () => {};

二、async函数返回一个Promise对象,函数内部有return返回值,可以通过then方法来接收

    async function f(){
        return 'hello world'
    }

    f().then( v => {
        console.log(v);
    })

Example:

    async function getStockPriceByName(name) {
        var symbol = await getStockSymbol(name);
        var stockPrice = await getStockPrice(symbol);
        return stockPrice;
    }

    getStockPriceByName('goog').then(function (result) {
        console.log(result);
    });

| http://www.ruanyifeng.com/blog/2016/01/babel.html
| http://es6.ruanyifeng.com/#docs/style
| http://babeljs.cn/

React(之二)组件

| react-create-app 脚手架
| Router、Route
| Link、Links router的导航组件,用来切换路由
| browserHistory、hashHistory
| activeStyle、activeClassName 路由设置样式
| query、params 变量
| Redirect

react-create-app 脚手架

$ sudo npm i create-react-app -g            // 全局安装,以后在安装就直接使用create-react-app命令来创建就可以

$ create-react-app my-app            // 创建+创建项目目录名

$ cd my-app

$ yarn start

$ yarn start、yarn build             // 启动服务、打包

$ yarn add antd        // 安装Antd UI框架

    在index.js中引用ant公用样式
    import 'antd/dist/antd.css';

$ yarn add react-router-dom -D            // react-router是安装4.0之前版本,react-router-dom是4之后版本

$ yarn add redux react-router-redux -D

$ npm run eject            // 注意如果对构建工具和配置选择不满意可以使用eject运行, 这里是单项操作只能一次不能回去

一、create-react-app关闭eslint提醒

    需要先npm run eject 生成本地webpack配置文件,在修改package.json中的配置

    "eslintConfig": {
        "extends": "react-app",
        "rules": {
            "no-undef": "off",
            "no-restricted-globals": "off",
            "no-unused-vars": "off"
        }
    }

二、配置反向代理

    "proxy": {
        "/api/*": {
            "target": "http://goucai.diyicai.com",
            "pathRewrite": {
                "^/api/": "/"
            },
            "changeOrigin": true,
            "secure": false
        }
    }

三、使用.scss文件

    1、$ npm install file-loader sass-loader node-sass --save-dev            // 安装包

    2、node_modules/react-scripts/config/webpack.config.dev.js 和 webpack.config.prod.js文件中module中配置下面两项

        {
            exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/, /\.scss/],            // 这里加添加一个/\.scss/
            loader: require.resolve('file-loader'),
            options: {
                name: 'static/media/[name].[hash:8].[ext]',
            }
        },
        // 解析scss文件
        {
            test: /\.scss$/,
            loaders: ['style-loader', 'css-loader', 'sass-loader'],
        }


四、引入样式

    1、<div style={{width: "1000px"}}></div>

    2、import "./main.css"

        <div className="main"></div>

    3、import Styles from './main.css'

        <div className={Styles.main}></div>


五、常见问题

    1、<src>引用本地图片无效

        import JzkUrl from '../../assets/img/jzk.png'

        <img src={JzkUrl} />

六、build的打包的时候注意的地方

    在package.json中的有一个homePage: '.',这个在打包的时候图片会成为相对路径,如果改成 homePage: '/'


七、修改webpack配置加一个全局配置

    function resolve (dir) {
        return path.join(__dirname, '..', dir)
    }

    resolve: {
        alias: {
            'react-native': 'react-native-web',
            '@': resolve('src')
        }
    }

    在页面里可以直接引用@来找到src目录

        import User from '@/views/User/'

PropTypes验证

React.PropTypes 提供很多验证器来验证传入数据的有效性

当向 props 传入无效数据时,JavaScript 控制台会抛出警告。注意为了性能考虑,只在开发环境验证 propTypes。下面用例子来说明不同验证器的区别: 

Example:

    import PropTypes from 'prop-types';
    class Greeting extends React.Component {
        render() {
            return (
                <h1>Hello, {this.props.name}</h1>
            );
        }
    }
    Greeting.propTypes = {
        name: PropTypes.string
    };

propTypes类型: {

    // 可以声明 prop 为指定的 JS 基本类型。默认
    // 情况下,这些 prop 都是可传可不传的。
    optionalArray: React.PropTypes.array,
    optionalBool: React.PropTypes.bool,
    optionalFunc: React.PropTypes.func,
    optionalNumber: React.PropTypes.number,
    optionalObject: React.PropTypes.object,
    optionalString: React.PropTypes.string,

    // 所有可以被渲染的对象: 数字,
    // 字符串,DOM 元素或包含这些类型的数组。
    optionalNode: React.PropTypes.node,

    // React 元素
    optionalElement: React.PropTypes.element,

    // 用 JS 的 instanceof 操作符声明 prop 为类的实例。
    optionalMessage: React.PropTypes.instanceOf(Message),

    // 用 enum 来限制 prop 只接受指定的值。
    optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),

    // 指定的多个对象类型中的一个
    optionalUnion: React.PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
        React.PropTypes.instanceOf(Message)
    ]),

    // 指定类型组成的数组
    optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),

    // 指定类型的属性构成的对象
    optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),

    // 特定形状参数的对象
    optionalObjectWithShape: React.PropTypes.shape({
        color: React.PropTypes.string,
        fontSize: React.PropTypes.number
    }),

    // 以后任意类型加上 `isRequired` 来使 prop 不可空。
    requiredFunc: React.PropTypes.func.isRequired,

    // 不可空的任意类型
    requiredAny: React.PropTypes.any.isRequired,

    // 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接
    // 使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。
    customProp: function(props, propName, componentName) {
        if (!/matchme/.test(props[propName])) {
            return new Error('Validation failed!');
        }
    }
}

react-router 4.0

v3到v4版本的变化是静态路由到动态路由的变化,并且页面的嵌套路路由嵌套决定

react-router: 是浏览器和原生应用的通用部分, 核心文件

react-router-dom: 用于浏览器

react-router-native: 是用于原生(react-native)应用的    

react-router-redux: React Router 和 Redux 的集成

react-router-config: 静态路由配置的小助手

一、安装

    $ npm i react-router react-router-dom --save

    import { BrowserRouter as Router, Route, Switch, Link, Redirect, withRouter } from 'react-router-dom';


二、使用路由

    1、react-router和react-router-dom,不需要都引用,只是后者多<Link> <BrowserRouter> 这样的 DOM 类组件

    2、如果搭配 redux ,你还需要使用 react-router-redux

    index.js: 在入口文件加上路由配置

        import React from 'react'
        import { Router, Route, Link } from 'react-router'

        // render中加入路由配置
        React.render((
            <Router>
                <Route path="/" component={App}>
                    <Route path="about" component={About}/>
                    <Route path="users" component={Users}>
                        <Route path="/user/:userId" component={User}/>
                    </Route>
                    <Route path="*" component={NoMatch}/>
                </Route>
            </Router>
        ), document.body)


二、<BrowserRouter> HTML5 history路由组件

    1、basename - 为所有位置添加一个基准的url

        <BrowserRouter basename="/minooo" />
        <Link to="/react" /> // 最终渲染为 <a href="/minooo/react">

    2、getUserConfirmation() - 导航到此页执行的函数

        const getConfirmation = (message, callback) => {
            const allowTransition = window.confirm(message)
            callback(allowTransition)
        }
        <BrowserRouter getUserConfirmation={getConfirmation('Are you sure?', yourCallBack)} />

    3、forceRefresh - bool当浏览器不支持 HTML5 的 history API 时强制刷新页面

        const supportsHistory = 'pushState' in window.history
        <BrowserRouter forceRefresh={!supportsHistory} />    

    4、keyLength - 路由的长度

    5、children - 渲染唯一子元素


三、<HashRouter> 该技术只是用来支持旧版浏览器, Hash history 不支持 location.key 和 location.state


四、<Route> 最重要的组件,页面访问地址与Router的path进行匹配,渲染出对应的UI界面

    <Route path="/" component={Main}> - 渲染的组件

    <Route> 自带三个 render method 和三个 props

    1、render methods 分别是:

        <Route component> - 当访问地址和路由匹配时,一个组件才会被渲染,此时此组件接受match、location、history

            * <Route path="/home" component={Home} />

        <Route render> - 适用于内联渲染,不会产生重复装载问题

            * <Route path="/home" render={() => <h1>Home</h1} />

        <Route children> -

    2、props分别是: match、location、history

            <Route path="/:id" component={ListBasic}></Route>          // 参数传给子组件
            this.props.match.params.id            // 获取参数值

    3、path: 路由路径

         exact: true,表示独一无二的路由

            // 如果不加exact, "/" 时加载main, "/login" 会显示main和login两个组件,如果加了exact在"/"路由时只会显示main组件
            <div style={{ height: "500px", backgroundColor: "#ccc"}}>
                <Route path="/" exact component={Main} />
                <Route path="/login" component={Login} />
                <Route path="/todoList" component={TodoList} />
            </div>

         strict: true,如果path为'/one/'将不能匹配'/one',但可以匹配'/one/two'


五、路由跳转

    1、Link、NavLink

        <Link to="/course" />
        <Link to={{
				pathname: '/course',
				search: '?sort=name',
				state: { price: 18 }
			}} />

        // 给导航使用的
        <NavLink
            to="/about"
            activeStyle={{ color: 'green', fontWeight: 'bold' }}
        >MyBlog</NavLink>

    2、JS跳转

        export default class SelectCard extends Component {
            constructor(props){
                super(props);
            }
            goHomePage(){
                this.props.history.push('/main');            // 跳转
            }
            render(){
                return {
                    <div>
                        <button onClick={this.goHomePage.bind(this)}>跳转</button>
                    </div>
                }
            }
        }

        /** 注意如果使用redux子组件会取不到this.props.history **/
        解决方法: 在子组件中
        import PropTypes from 'prop-types'

        子组件名.contextTypes = {
            router: PropTypes.object.isRequired
        }

        console.log( this.context.router.history.push('/') );


六、<switch> 只渲染出第一个与当前访问地址匹配的 <Route> 或 <Redirect>

    // v3
    <Route path='/' component={App}>
        <IndexRoute component={Home} />
        <Route path='about' component={About} />
        <Route path='contact' component={Contact} />
    </Route>

    v4中使用<switch>来取代<IndexRouter>, 当react渲染时switch下第一个子<route>会被渲染
    // v4
    const App = () => (
        <Switch>
            <Route exact path='/' component={Home} />
            <Route path='/about' component={About} />
            <Route path='/contact' component={Contact} />
        </Switch>
    )


七、添加图像、字体和文件

    组件中加载图片
    import logo from './logo.png';        导入图片
    <img src={logo} alt="Logo" />;

    css中加载图片
    .logo{
        background-image: url('./logo.png');
    }


八、Redirect重定向 和 未匹配路由跳转到404

    // 跳404用法
    render() {
    return (
    <Router>
      <div className="main-container">
        <Route path="/main" component={Main} />
        <Route component={Page404}/>                // 没有定义path就是没有路径匹配时
      </div>
    </Router>
    )
    }

    // Redirect 用法不渲染组件直接重定到其它页面
    render() {
        if(!this.state.logined){
            return (
                <Redirect to="/todoList" />
            )
        }
        return (
            <div>
                这里是Login组件
            </div>
        )
    }


九、动态路由

    1、路由变量

        定义变量: <Route path="/:msg" component={Message} />
        获取变量: props.match.params.定义的名

        <Route path="/hello/:name">         // 匹配 /hello/michael 和 /hello/ryan
        <Route path="/hello(/:name)">       // 匹配 /hello, /hello/michael 和 /hello/ryan
        <Route path="/files/*.*">           // 匹配 /files/hello.jpg 和 /files/path/to/hello.jpg

        Example:

            class Message extends Component {
                render(props){
                    return (
                        <div>
                            // 这里this.props.params.msg 接收的是to的名字
                            <h1>{this.props.match.params.jumpUrl || 'hello'}</h1>
                            <Links />
                        </div>
                    )
                }
            }

            const Links = () =>{
                <nav>
                    <Link to="/">Hello</Link>
                    <Link to="/yong">Yong</Link>
                    <Link to="/feng">Feng</Link>
                </nav>
            }

            class ParamsRoute extends Component {
                render() {
                    return (
                        <Router history={hashHistory}>
                            <Route path="/(:msg)" component={Message} />
                        </Router>
                    );
                }
            }
            export default ParamsRoute;


    2、query: 获取URL中的参数

        1) 获取参数

            http://localhost:8080/#/?message=ssssss

            const Page = (props) =>
                <div>
                    <h1>{props.location.query.message || 'Hello'}</h1>            // props.location.query.message输出 ssssss
                </div>

        2) <Link>请求时带参数

            const Page = (props) =>
                <div>
                    <h1>{props.location.query.message || 'Hello'}</h1>
                </div>

            const Links = () =>
                <nav>
                    <Link to={{ pathname: "/", query: {message: "ssssss"} }} />         
                </nav>

        3) js中请求参数 

            goToMessage(){
                that.props.history.push({ 
                    pathname : '/success',
                    query : { messageTitle: '充值成功', messageContent: '请取您的充值单请取您的充值单请取您的充值单'} 
                })
            }


十、路嵌套和展示

    // v2/3版本 就是一个路由配置文件,在放子路由的地方使用
    <div>
        { this.props.childre }                // 加载子路由的位置
    </div>

    // v4版本
    // router.jsx
    export default class Index extends Component {
        render() {
            return (
                <Router>
                    <Switch>
                        <Layout />
                    </Switch>
                </Router>
            )
        }
    }

    // layout.jsx
    export default class Layout extends Component {
        render() {
            let menuHtml = () => {
                const menuItem = [];
                this.state.menuList.forEach(function(menu, idx, arr){
                    menuItem.push(
                        <li>
                            <Link to={menu.path}>{menu.title}</Link>
                        </li>
                    )
                })
                return menuItem
            }

            return (
                <div>
                    <header style={{height: "100px"}}>
                        菜单: { menuHtml() }
                    </header>
                    <main style={{ height: "500px", backgroundColor: "#ccc"}}>
                        // 这下面都是子路由的展示位置
                        <Route path="/" exact component={Main} />
                        <Route path="/login" component={Login} />
                        <Route path="/todoList" component={TodoList} />
                        <Route component={Page404}></Route>                        // 注: 如果没有匹配路由指到到404页面, 不需要使用Redirect
                    </main>
                </div>
            )
        }
    }

    // login.jsx
    export default class Login extends Component {
        constructor(props){
            super(props);
            this.state = {
                logined: true
            }
        }

        render() {
            /* 这里可以不渲染组件直接重定到其它页面 */
            if(!this.state.logined){
                return (
                    <Redirect to="/todoList" />
                )
            }
            return (
                <div>
                    这里是Login组件
                </div>
            )
        }
    }

https://www.jianshu.com/p/7bb4c1a0530d
https://www.jianshu.com/p/548674270455


十一、withRouter 

    withRouter是专门用来处理数据更新问题,否则可能会出现路由地址改变但页面没有相应改变的bug

    import React, { Component } from 'react'
    import { withRouter } from 'react-router'
    import { Route, Redirect } from 'react-router-dom'

    class AuthRouter extends Component {
        render() {  
            const { component: Component, ...rest } = this.props
            const isLogged = sessionStorage.getItem("isLogin") === "1" ? true : false;

            return (
                <Route {...rest} render={props => {
                    return isLogged
                        ? <Component {...props} />
                        : <Redirect to="/login" />
                }} />
            )
        }
    }
    export default withRouter(AuthRouter);

dva+react+Ant 蚂蚁金服脚手架

单独加载ant UI框架,也可以使用dva-cli蚂蚁提供的脚手架,支持IE9及以上版本

一、单独添加ant  

    $ cnpm i antd --save

    import 'antd/dist/antd.css';         // 引入样式
    import { DatePicker } from 'antd';    // 这种方法的引用必须要添加babel-plugin-import的按需加载组件
    ReactDOM.render(<DatePicker />, mountNode);            

二、按需加载插件 babel-plugin-import

    $ cnpm i babel-plugin-import --save

    .babelrc添加参数:
    {
        "plugins": [
            ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }] // `style: true` 会加载 less 文件
        ]
    }

三、dva-cli安装

    $ cnpm i dva-cli    

    $ dva new [项目名] && cd [项目名]        // 创建项目

    $ cnpm install antd babel-plugin-import --save        // 安装 ant 和 babel插件(用来按需加载 antd 的脚本和样式的)

        .webpackrc文件加参数
        {
            "extraBabelPlugins": [
                ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
            ]  
        }

四、运行

    $ npm start         // 生产环境运行

    $ npm run build        // 打包项目,发布线上环境在Dist目录下生成静态文件,js、css压缩

五、redux的使用

    有两个目录,models和components, model来定义state和action的,components来编写组件

    dva提供conect方法,将model和component串联起来

    import { connect } from 'dva';

    const Products = ({ dispatch, products }) => { ... }
    export default connect(({ products }) => ({
        products,
    }))(Products);

六、配置

    1、 .roadhogrc.mock.js  用于mock数据的配置

        export default {
            // 支持值为 Object 和 Array
            'GET /api/users': { users: [1,2] },

            // GET POST 可省略
            '/api/users/1': { id: 1 },

            // 支持自定义函数,API 参考 express@4
            'POST /api/users/create': (req, res) => { res.end('OK'); },
        };

    2、.webpackrc  

        {
            "extraBabelPlugins": [
                ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
            ],
            "entry": "src/index.js",        // 可以配置webpack的选项,参数见面下roadhog的文档连接
            "proxy": {                        // 设置代理
                "/api": {
                    "target": "http://jsonplaceholder.typicode.com/",
                    "changeOrigin": true,
                    "pathRewrite": { "^/api" : "" }
                }
            }
        }

    3、设置端口

        默认是8000,可以在package.json中设置
        "scripts": {
               "start": "PORT=3000 roadhog server",        // windowns设置 set PORT=3000&&roadhog dev
        }

    4、public目录会在build的copy到dist目录下,存放一些静态文件

https://github.com/sorrycc/blog/issues/18            // dva
https://github.com/sorrycc/roadhog/blob/master/README_zh-cn.md    // roadhog


七、fatch请求

    dva-cli中utils目录中request.js中定义了一个通过fatch来发ajax请求的方法

    业务中调用:
    function IndexPage() {
        var getUser = () => {
            Request('/api/posts', {method: 'GET'})
            .then((data)=>{
                debugger;
            })
        }
        getUser()

        return (
            <div className={styles.normal}>
                ...
            </div>
        );
    }
    exports default IndexPage;

收集组件

1、react-transition-group - 页面切换过渡效果

https://github.com/reactjs?page=2

| https://facebook.github.io/create-react-app/ // create-react-app 官网
| https://react-guide.github.io/react-router-cn/ // React-router 中文网
| https://reacttraining.com/react-router/web/example/basic // 官方示例**
| https://www.jianshu.com/p/25e9ba1ebafb // react源码分析
| https://github.com/YutHelloWorld/Blog/issues/4 // v2、3迁移v4
| https://www.jianshu.com/p/e0a0ed6c3b8a // 路由跳转登录验证
| https://www.jianshu.com/p/e3adc9b5f75c/
| https://segmentfault.com/a/1190000009349377 // router ^4
| https://github.com/reactjs/react-router-redux

React(之三)Redux

| createStroe - 创建一个store
| reducer - 用来改变state的值,结合了action的动作来分别处理
| action - 要执行的事件
| combineReducers - 将多个reducer合到一起,赋给createStroe
| replaceReducer - 替换reducer,改变state修改逻辑
| subscribe - 侦听Store的变化
| store.getState - 获取Store中的state值
| store.dispatch - 触发action,改变state的值
| provider - 将Store传递给内部组件
| connect - 将组件与redux的状态、事件关联起来
| applyMiddleware - 加载中间件
| bindActionCreators - 直接调用dispatch(action)()
| react-redux - react与redux结合

Redux

react是纯View层的框架,需要数据流进行支撑, 单一的状态树,主流数据流框架: Flux、Redux

UI -> action -> reducer -> store -> state -> UI

Redux是非异步的流程,如果需要使用异步操作使用 Redux-saga

一、Flux四部分

    1、Dispatcher - 处理动作分发,维持Store之间的依赖关系

    2、Store - 负责存储数据和处理数据相关逻辑

    3、Action - 驱动Dispatcher的JS对象

    4、View - 视图部分,负责显示用户界面

    Dispatcher相当于Controller,Stroe相当于Modle,View相当于View,Action相当于用户的行为


二、Redux三个基本原则

    1、唯一数据源 - 状态数据只存储在唯一的一个Store上

    2、保持状态只读 - 不能直接修改Store的状态,需要派发一个action对象完成

    3、数据改变只能通过纯函数完成

安装

Facebook官方提出了Flux思想管理数据流,同时也给出了自己的实现方案Flux来管理React应用

实现Flux思想的类库 Redux、Flux、reflux

$ npm i redux --save                    // 安装redux

$ npm i react-redux --save            // redux与react结合

$ npm i react-router-redux --save     // redux-router

$ npm i redux-devtools-extension --save        // 安装可视化工具

    引用:import { composeWithDevTools } from 'redux-devtools-extension'

    在chrome中下载redux-devtools插件

    https://github.com/zalmoxisus/redux-devtools-extension#usage

$ npm i redux-thunk --save

$ npm i redux-logger --save

引用redux: import { createStore } from 'redux'

一、Redux流程:

    1、view直接触发dispatch

    2、dispatch将action发送到reducer中后,根节点上会更新props,改变全局view

    3、redux将view和store的绑定从手动编码中提取出来,放在了统一规范放在了自己的体系中    

Action

action指令并不能直接改变state,action必须是json

let todoId = 0;
export const addTodo = (text) => {
    return {
        type: 'ADD_TODO',    // 处理的类型(必要)
        id: todoId++,            // 存储数据当前的id标识
        text                            // 传入的内容
    }
}

通过 store.dispatch(action) 来派发到reducer中, 在reducer中改变state的值

Reducer

接收一个action值,纯方法不能定义ajax定义时间等,需要传入一个旧的状态在返回一个新的状态给action, 根据定义的action名对应处理state,并改变state值

let todo = (state, action) => {

    // 这里通过action的type的值对应不同的事来处理
    switch(action.type){
        case 'ADD_TODO':
            return {
                state + 1;
            }
            break;

        /* 上面只是单个add_todo, 这里要写成多个add_todo
        case 'ADD_TODO':
            return [
                {
                    id: action.id,
                    text: action.text,
                    completed: false
                },
                ...state
            ]
            break;            
        */

        case 'SUB_TODO':
            return {
                state - 1;
            }
            break;

        default: state;
    }
}

1、combineReducers - 将多个的reducer合成一个

    // 目录 reducer/index.js
    import {combineReducers} from "redux";
    import reducerA from "./reducerA";
    import reducerB from "./reducerB";

    export default combineReducers({
        reducerA,
        reducerB,
    });

    // createStore调用reducer
    import reducers from './reducer/'
    let store = createStore(reducers)

Store

Store是来保存数据的容器,只有一个Store,可以根据不同业务拆分成多个reducer, createStroe(reducer, 初始化的)

import { createStore } from 'redux';
import reducer from './reducers'        // 获取定义的reducer

let stroe = createStroe(reducer);    // 使用createStore(reducer, initialState初始化state, 中间件传入)来创建一个数据仓库
store.dispatch();

方法:

    1、store.getState(): 获取State值

    2、store.dispatch(action): 触发action,修改state的值

    3、store.subscribe(listener),用来订阅状态的变化

        添加一个变化的监听器,每当dispatch action的时候就会执行

        // App组件
        class App extends Component {
            constructor(props){
                super(props);
                this.state = {
                    num: 0
                }
            }

            componentDidMount() {
                store.subscribe(this.handleChange.bind(this));
            }

            handleChange(){
                this.setState({num: store.getState()})
            }

            addClick(){
                store.dispatch({type: 'add'});
            }

            subClick(){
                store.dispatch({type: 'sub'});
            }

            showState(){
                debugger;
                console.log(store.getState())
            }

            render() {
                return (
                    <div className = "box" >
                        {this.state.num}
                        <input type="button" onClick={this.addClick} value="+" />
                        <input type="button" onClick={this.subClick} value="-" />
                        <input type="button" onClick={this.showState} value="查看state" />
                    </div>
                )
            }
        }

State

state用于存储数据,state是只读的,改变需要触发action

state树就是一个对象,所有的reducer的都会加到state中,取state值,store.getState().

react-redux

$ npm i react-reudx --save        // 安装

一、provider(store, children) - 将Store传到子组件中,一般用在入口文件

    import React from 'react';
    import ReactDOM from 'react-dom';
    import {Provider} from "react-redux";
    import Store from "src/store";
    import App from 'src/components/app';
    import Chat from 'src/pages/Chat/Index';

    // 1、使用Store让所有组件访问到
    ReactDOM.render(
        <Provider store={Store}>
            <App>
                <Chat />
            </App>
        </Provider>,
        document.getElementById('app')
    );

    // 2、如果使用路由
    ReactDOM.render(
        <Provider store={store}>
            <Router ref="router" history={hashHistory}>
                <Route path='/' component={Index}>
                    <IndexRoute  component={MainPage}></IndexRoute>
                </Route>
            </Router>
        </Provider>
    )


二、connect(mapStateToProps, mapDispatchToProps)(Component连接组件) - 连接react组件与redux store

    1、mapStateToProps(state, ownProps) - 侦听Store的变化

            state参数 - 如果Store中有变化此方法就会被调用,该回调函数返回一个纯对象,这个对象会与组件的props合并

            ownProps参数 - 该参数的值为会飞经到组件的props,

    2、mapDispatchToProps - 逻辑输出,相当于用store.dispatch(actionType) 来发出操作指令,来改变state值

    Example:

        // app.jsx
        <Provider store={store}>
            <Router ref="router" history={hashHistory}>
                <Route path='/' component={Index}>
                    <IndexRoute  component={MainPage}></IndexRoute>
                </Route>
            </Router>
        </Provider>

        // Index.jsx
        import React, { Component } from 'react';
        import ReactDOM from 'react-dom';
        import { bindActionCreators } from "redux";
        import { connect } from "react-redux";
        import actions from "src/actions";

        class wechat extends Component {
            constructor(props){
                super(props);
                this.state = {

                }
            }

            componentDidMount(){
                let { ACTIONS } = this.props;
                ACTIONS.chat_init();
            }

            render(
                // ...
            )
        }

        let mapStateToProps=(state)=>{
            let {sessions,user} = state.chatIndex;
            return {
                _sessions:sessions,
                _user:user
            };
        }; 

        let mapDispatchToProps=(dispatch)=>{
            return {
                ACTIONS: bindActionCreators(actions, dispatch)
            };
        };

        export default connect(mapStateToProps,mapDispatchToProps)(wechat);

container组件

引用Redux将组件分两类container和component

container - 组件中使用redux获取数据,状态更新,从Redux获取state

bindActionCreators()

是通过dispatch将action包裹起来,这样可以通过bindActionCreators创建的方法,直接调用dispatch(action)(隐式调用)

import * as oldActionCreator from './action.js'

let newAction = bindActionCreators(oldActionCreator,dispatch)

调试工具

两种方法 1、下载redux-devtools包      2、chrome or Firfix 下载 Redux DevTools插件

1、使用Redux DevTools插件 代码中需要加配置

    https://github.com/zalmoxisus/redux-devtools-extension

    /* eslint-disable no-underscore-dangle */        // +
    let store = createStore(
        comput,
        window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()        // +
    )
    /* eslint-enable */                                // +


2、redux-devtool 包的使用 https://github.com/gaearon/redux-devtools

项目目录

|- src
|-- reduxs     // redux
|------ actions
|------ reducers
|-- router    // 路由
|-- util    // 工具

react-router-redux路由

redux管理的是应用状态(state),router管理的是路由,react-router-redux是保持路由与应用状态(state)同步

$ npm install --save react-router-redux        // 安装

原理:允许使用react router库中的api,使用redux一样去管理应用状态state

https://www.jianshu.com/p/bccca5bb6338
http://blog.csdn.net/isaisai/article/details/78086913
https://segmentfault.com/a/1190000007862103

http://blog.csdn.net/sinat_17775997/article/details/69218382

| http://cn.redux.js.org/index.html // Redux中文文档
| http://www.liuyiqi.cn/2016/01/19/r2-counter/
| https://github.com/lewis617/react-redux-tutorial
| https://github.com/xgrommx/awesome-redux
| https://www.jianshu.com/p/bccca5bb6338 // react-router-redux 保持路由与应用状态(state)同步
| http://www.redux.org.cn/ // react-redux
| https://www.jianshu.com/p/1a2f3db4af61 // react-redux
| https://www.jianshu.com/p/9873d4ccb891 // connect 原理
| https://github.com/GuoYongfeng/redux-complete-sample
| https://github.com/gaearon/redux-devtools
| http://www.aliued.com/?p=3204
| http://blog.csdn.net/liwusen/article/details/54138854 // bindActionCreators
| http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html
| https://github.com/allan2coder/React-SPA/blob/master/src/store/configureStore.dev.js // 示例 router3.0

React(之一)基础

| 创建组件
| render
| props、propType、state、setState()、replaceState()
| 获取DOM this.refs.xxx 或 ReactDOM.findDOMNode(this.refs.xxx)
| React.Children 获取父组件传的DOM
| mixin

React

React包括几个概念: 1、组件       2、JSX     3、虚拟DOM     4、单向数据绑定        5、受控组件

1、核心是封装组件,只关注UI,状态变更重新渲染整个组件

2、JSX: HTML代码可以直接嵌到JS代码中,这就是React提出的叫JSX的语法,原来前端以表现和逻辑层分离为主,但HTML是组件的一部分所以不能分割,JSX 将动态值放到 { ... }

3、单向数据流: 当数据更新会渲染整个app

    React的渲染方式: 用户输入 ~> 从API获取数据 ~> 将数据传给顶层组件 ~> React将每个组件渲染出来, 不会象MVC一样的双向数据绑定、和数据模型的脏值检测、不会有确切的DOM操作

4、虚拟DOM树: React重建一个DOM树,找到与上一个版本的DOM的差异,计算出新的DOM更新操作,从操作队列中指执行DOM更新操作

    http://www.alloyteam.com/2015/04/%E5%89%8D%E6%B2%BF%E6%8A%80%E6%9C%AF%E8%A7%A3%E5%AF%86-virtualdom/      // 前沿技术解密——VirtualDOM

5、IE浏览器要在8.0版本以上

rrc 创建带redux组件
rcc 创建react组件
rca 创建action
reducer 创建reduer

react引用方式

// Component作为所有组件的基类,提供很多组件共有的功能
import React, { Component } from 'react';
import { reactDom } from 'react-dom';

// 定义组件
class SimpleComponent extends Component {
    render(){
        return <div> React,我们来了... </div>;
    }
}
export default SimpleComponent;

// 组件渲染
reactDom.render(<HelloMessage />, document.getElementById('app'));

生命周期

组件的生命周期三个过程

    装载过程(Mount) - 把组件第一次在DOM树中渲染的过程

    更新过程(Update) - 当组件被重新渲染的过程

    卸载过程(Unmount) - 组件从DOM中删除的过程


一、装载过程

    1、constructor - ES6每个类的构造函数,创建一个组件就会先调用对应的构造函数

    2、getInitialState() - 初始化this.state,(ES6不起作用)

    3、getDefaultProps - 设置默认的props (ES6不起作用)

    4、componentWillMount() - 组件挂载前(调用render方法之前触发, 没有任何渲染,就算调用了this.setState()也不会引发绘制)

    5、render() - 创建虚拟dom,进行diff算法,更新dom树,如果不需要渲染可以将render函数返回一个null或false

    6、componentDidMount() - 组件渲染后已经装载到DOM树中,这时候可以refs操作获取或操作DOM节点


二、更新过程(当props或state被修改时就会引发组件的更新过程)

    1、componentWillReceiveProps(nextProps) - 当父组件改变了传递给子组件props的值,这时候子组件此方法会被调用

    2、shouldComponentUpdate(nextProps, nextState) - react性能环节,父组件传给子组件的props值改变,子组件中的shouldComponentUpdata()方法会先调用,前后两个props相同返回false阻止更新,不需要在创建新的dom树在进行diff算法,默认为true

        shouldComponentUpdate(nextProps, nextState){
            return nextProps.name === nextState.name        // 如果返回false就算父组件传递的props值改变,也不会执行render
        }

    3、componentWillUpdate() - 与装载过程相同 

    4、render() - 与装载过程相同

    5、componentDidUpdate() - 与装载过程相同


三、卸载组件

    1、componentWillUnmount() - 卸载前调用

JSX语法

一、注释

    {/* 这里用于单多行注释 */}


二、根元素只能有一个

    class ComponentDemo extends Component {
        render(){
            // 以下写法直接报错
            return (
                <div>
                    hello
                </div>
            );
        }
    }


三、属性名不能和 js 关键字冲突

    1、class => className

    2、read => readOnly

    3、for => htmlFrom 不能直接使用for

        <div htmlFor='male'>Male</div>


四、JSX spread

    { ...spreadObj } 可以直接将spreadObj的对象传递过去

    import SpreadDemo from './components/spread';
    const spreadObj = {
        name: 'siguang',
        carType: '卡宴'
    }
    render(<SpreadDemo {...spreadObj} />, document.querySelector('#app'));


五、渲染HTML

    const elements = '<p>aaa</p><p>bbb</p><p>ccc</p>';
    <p dangerouslySetInnerHTML={{ __html: elements }}></p>

http://lib.csdn.net/article/react/22655

class和style

一、class

    方法1:
        import './admin.css'
        render() {
            return (
                <div className="container">            // 注意这里的值为字符串而不是{}
                    <div className="sild">xxxx</div>
                </div>
            );
        }

    方法2:
        import styles from './admin.css'
        render() {
            return (
                <div>
                    <div className={style.sild}>xxxx</div>
                </div>
            );
        }


二、style 行内样式

    方法1:
        const container = {
            display: flex;
            height: 100%;
        }

        render() {
            return (
                <div style={container}> xxx </div>
            );
        }

    方法2: <div style={{ width: '100px', float: 'left'}}>       // 注意这里属性值要使用引号

组件

一、组件创建

    1、类式组件

        import React, { Component } from 'react'
        import ReactDom, { render } from 'react-dom'

        // 所有创建的组件都继承于Component对象
        class ShowMessage extends Component{
            constructor(props){
                super(props);
            }
            render(){
                return <div>Hello name {this.props.name}</div>
            }
        }
        export default ShowMessage;


    2、函数式组件

        const Welcome = (props) => {
            return <h1>Hello, {props.name}</h1>;
        }
        <Welcome username="this.state.username" />


    函数组件与类式组件的区别:

        类组件有state, 函数组件没有state

        类组件有生命周期函数


二、组件注意的地方

    1、组件名首字母必须大写

    2、根元素只能有一个标签元素

        class ComponentDemo extends Component {
            render(){
                return (
                    <div class="boxA">            {/* 根元素只能有一个 */}
                        aaaaaaaa
                        <div class="boxB">
                            bbbbbb
                        </div>
                    </div>
                )
            }
        }
        export default ComponentDemo;

    3、可以使用es6的 spread 变量传递 {...obj}

        let person = <Person name={window.isLoggedIn ? window.name : ''} />

    4、refs属性获取真实的DOM节点

        组件并不是真实的DOM节点,而是在内存中的一种数据结构叫虚拟DOM,如果要从组件内获取真实的DOM节点,需要用到refs属性

组件嵌套

childList.jsx:

    class ChildrenA extends Component{
        constructor(props){
            super(props);
        }
        render(){
            return (<div>
                {/* 这里是子组件A   this.props.children获取组件的内容,相当前于vue中的solt */}
                {
                    React.Children.map(this.props.children, function(c){        // React.Children是获取组件中的元素
                        return <p>{c}</p>
                    })
                }
            </div>)
        }
    }

    class ParentComponent extends Component{
        render(){
            return <div>
                <ChildrenA>
                    <p>福特</p>
                    <p>丰田</p>
                    <p>本田</p>
                </ChildrenA>
            </div>
        }
    }
    export default ParentComponent;

index.js:

    import ParentComponent from './components/ParentComponent'
    render(<ParentComponent />, docuemnt.querySelector('#box'));

组件间通信

一、组件之间通信的几种情况

    1、父组件向子组件通信

    2、子组件向父组件通信

    3、跨级组件之间通信

    4、非嵌套组件间通信


二、父向子通信 通过props

    parent.jsx
        <child message={this.state.sayMessage} />

    child.jsx
        {this.props.message}        // 接收


三、子向父通信

    parent.jsx
        <child getMessage={this.getMessage.bind(this)} />
        getMessage(msg){
            this.setDate({message: msg})
        }

    child.jsx
        this.props.getMessage('这里告诉父组件消息')


四、跨级组件

    父组件向很深的几层子组件通信有两种方法: 1、props一层一层传   2、使用context对象


五、events非嵌套组件通信, 使用事件订阅

    $ npm i events --save

    1、创建一个ev.js

        import { EventEmitter } from 'events'
        export default new EventEmitter();

    2、brotherA.jsx

        // 在组件装载完成以后
        componentDidMount(){
            // 声明一个自定义事件        
            this.eventEmitter = emitter.addListener("callMe", (msg)=>{
                this.setState({
                    msg
                })
            });
        }

        // 组件销毁前移除事件监听
        componentWillUnmount(){
            emitter.removeListener(this.eventEmitter);
        }

        render(){
            return (
                <div>
                    {this.state.message}
                </div>
            )
        }

    3、brotherB.jsx

        sendBrotherMessage(){
            return emitter.emit("callMe", "Hello");     // callMe为自定义函数,hello为发的消息参数
        }
        <input type="button" value="向A子组件发消息" onClick={this.sendBrotherMessage.bind(this)} />


六、redux或其它状态管理库

Context对象

context对象来跨级传递

context与react版本分两种写法,以下为react v16.3版本的示例

一、React.crateContext() - 创建一个Context

二、初始化createContext下的方法

    1、provider - 父组件中传递的值

    2、consumeer - 子组件接收的值

三、示例:

    创建一个contextStor.js:
        import React, { Component } from 'react'
        export const { Provider, Consumer } = React.createContext("Light");        // 默认主题是Light

    parentPage.jsx:
        import Ca from './cA'
        import { Provider } from './ccontextStor';

        export default class ParnentPage extends Component {
            render () {
                return (
                    <Provider value={{contextVal: '这里是context的传递的内容'}}>
                        <h1>这里是Parent组件</h1>
                        <Ca />
                    </Provider>
                )
            }
        }

    cA.jsx:
        import Cb from './cB'
        export default class Ca extends Component {
            render () {
                return (
                    <div>
                        <h2>这里是CA</h2>
                        <Cb />
                    </div>
                )
            }
        } 

    cB.jsx:
        import { Consumer } from './ccontextStor';
        export default class Cb extends Component {
            render () {
                return (
                    <div>
                        <h3>这里子CB</h3>
                        <Consumer>
                            {
                                context => {
                                    return (
                                        <div>{context.contextVal}</div>
                                    )
                                }
                            }
                        </Consumer>
                    </div>     
                )
            }
        }

数据流

React是单向数据流,数据从父组件传到子组件,子组件通过props获取数据,顶层组件改变了props,React会遍历整个组件树,重新渲染整个组件

数据流包括: Props 和 State

props

{ this.props.name } 读取props的值

一、props API:

    this.props.children - 所有子组件的内容

        <ChildrenComponent>
            <p>aa</p>
            <p>bb</p>
            <p>cc</p>
        </ChildrenComponent>

    this.props.map

    this.props.filter 


二、设置一个默认的props

    /* 通过 defaultProps 来定义 */
    class PropsDemo extends Component {
        constructor(props) {
    super(props);        // 调用父类,如果不写会调不到
       }
        render(){
            return (
                <div class="box">
                    name: {this.props.name}, age: {this.props.age}
                </div>
            )
        }
    }

    // 初始化props
    PropsDemo.defaultProps = {
        name: '123123'        // 默认一个name值,如果父组件没有传值就会取默认值
    }


三、propsType 校验props类型

    $ npm install --save prop-types

    import React, { Component, PropTypes } from 'react';

    class PropTypesDemo extends Component {
        render(){
            return <b>{this.props.title}</b>
        }
    }

    // 静态属性定义propTypes, title只能为string
    PropTypesDemo.propTypes = {
        title: React.PropTypes.string.isRequired
    }

    export default PropTypesDemo;


四、Example

    PropsComponent组件:

        class PropsComponent extends Component {
            render(){
                return (
                    <div class="box">
                        name: {this.props.name}, age: {this.props.age}         {/* 这里接收props值 */}
                    </div>
                )
            }
        }

        // 输出组件接口
        export default PropsComponent;

    index.js:

        import PropsComponent from '../components/props';

        // 要传的值
        let obj = {
            name: 'haha',
            age: '300'
        }

        // 方法1、直接传给属性
        render(<PropsComponent name={obj.name} age={obj.age} />, document.querySelector('body'));

        // ...obj 来对多值进行解析赋值
        render(<PropsComponent {...obj} />, document.querySelector('body'));


五、this.props.children 访问自定义子节点

    // 将组件下的所有子节点通过map获取到,并重新包装
    import React, { Component } from 'react';

    class UseChildren extends Component {
        render(){
            return  <ul>
                {
                    // 会将UseChildren组件下所有的元素取出
                    React.Children.map(this.props.children, function(c){
                        return <li> {c} </li>
                    })
                }
            </ul>
        }
    }

    class ChildrenDemo extends Component {
        render(){
            return (
                <UseChildren>
                    <a href="#">Facebook</a>
                    <a href="#">Google</a>
                    <a href="#">Space</a>
                </UseChildren>
            )
        }
    }
    export default ChildrenDemo;


六、this.props.content 可以传任意结构的JSX结构

    // 父组件通过content传值
    <ContentChildrenComponent content={
        <div>
            <h2>React.js 小书</h2>
            <div>开源、免费、专业、简单</div>
            订阅:<input />
        </div>
    } />

    // 子组件调用
    render() {
        return (
            <div>
                { this.props.content }
            </div>
        );
    }


七、组件传值

    <ChildComponent propsData={this.state.username} />

    <LikeButton wordings={{likedText: '已赞', unlikedText: '赞'}} onClick={() => console.log('Click on like button!')}/>

state

每一个React组件都有一个自己的state对象,与props区别是state只能在当前组件内部使用,props可以将数据传递给子组件

一、初始化state

    class StateDemo extends Component {
        constructor(){
            super();            // 继承Component

            // 这里初始化state
            this.state = { 
                userName: 'siguang' 
            }
        }

        setUserName: function(){
            this.setState({userName: 'lulu'});        // 修改state值
        },

        render(){
            return (
                <div>
                    这里是props获取的值 {this.state.userName};        // 获取state的值
                    <input type="button" onClick={this.setUserName.bind(this)} value="点击修改state" />
                </div>
            )
        }
    }


二、setState中this的指向

    1、<Button type="primary" onClick={ this.addCar.bind(this) }>开始</Button>
         <Button type="primary" onClick={ (e) => this.addCar(e) }>开始</Button>        // 渲染中箭头函数

    2、<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>

    3、addCar = () => {
            this.setState(function(state, porps){
                return {
                    car: state.car + 1
                }
            })
        }
        <Button type="primary" onClick={ this.addCar }>开始</Button>


三、setState()异步的问题

    setState()是异步导致如果直接在下面在取state值还没变过来,所以第二个回调是当state值设置成功后在执行的函数

    this.setState(
        { username: uname }, 
        () => {  console.log(this.state.username); }        // 这里还是为之前的值而不是「sg」
    );

refs操作真实DOM

获取ref: this.refs.xxx

Example:

    class RefsDemo extends Component {
        componentDidMount(){
            // refs直接获取
            const contentB = this.refs.content;
            console.log( contentB.innerHTML );
        }

        render(){
            return(
                <div>
                    <h3>React操作DOM</h3>
                    <p ref="content">这里是DOM元素的内容</p>        // 这里定义ref访问的名
                </div>
            )
        }
    }

mixin

通过mixin可以将组件间共享代码,将两个组件共同的属性、方法存储到mixin对象中

mixin不支持ES6的声明组件方式

ES5写法

    import React from 'react';

    // 抽取出的公用方法
    var SetIntervalMixin = {
        componentWillMount: function() {
            this.intervals = [];
        },
        setInterval: function() {
            this.intervals.push(setInterval.apply(null, arguments));
        },
        componentWillUnmount: function() {
            this.intervals.forEach(clearInterval);
        }
    };

    var MixinDemo = React.createClass({

        // 这里加载mixin
        mixins: [SetIntervalMixin],

        getInitialState: function() {
            return {seconds: 0};
        },

        componentDidMount: function() {
            // Call a method on the mixin
            this.setInterval(this.tick, 1000);
        },

        tick: function() {
            this.setState({seconds: this.state.seconds + 1});
        },

        render: function() {
            return (
                <p>
                    计时器已经运行了:  {this.state.seconds} 秒.
                </p>
            );
        }
    });

    export default MixinDemo;

表单

一、defaultValue 与 value 的区别

    <input type="text" value={this.state.inputValue} />

    如果使用 value来绑定state的值,输入值时不会被改变,使用 defaultValue 值会被改变

    class App extends Component {
        constructor(props) {
            super(props);
            this.state = {
                username: ''
            }
        }
        handleUsername(e){
            const val = e.target.value;
            this.setState({username: val});
        }
        getName(){
            alert(this.state.username)
        }
        render() {
            return (
                <div className="App">
                    <input placeholder="Basic usage" defaultValue={this.state.username} onChange={this.handleUsername.bind(this)} />
                    <button type="primary" onClick={this.getName.bind(this)}>Primary</button>
                </div>
            );
        }
    }

二、react表单组件与html的不同

    1、value、checked: 属性设置值后,用户输入无效

    2、textarea: 的值要设置在value属性

        <textarea name="description" value="This is a description." />

    3、select: value属性可以是数据,不建使用option的selected属性

        <select multiple={true} value={['B', 'C']}>
            <option value="A">Apple</option>
            <option value="B">Banana</option>
            <option value="C">Cranberry</option>
        </select>

    4、radio/checkbox/option 点击后触发 onChange

受控组件

受控组件就是为某个form表单组件添加value属性;非受控组件就是没有添加value属性的组件

一、受控组件

    <input>,<textarea>以及<select>通常保持自己的状态和基于用户输入更新它

    handleChange(event) {
        this.setState({value: event.target.value});
    }
    <input type="text" value={this.state.value} onChange={this.handleChange} />


二、不受控制组件

    this.input = React.createRef();                    // 创建不受控组件
    <input type="text" ref={this.input} />    // 绑定
    this.input.current.value                                // 调用不受控组件

    class NameForm extends React.Component {
        constructor(props) {
            super(props);
            this.handleSubmit = this.handleSubmit.bind(this);

            // 创建不受控组件
            this.input = React.createRef();
        }

        handleSubmit(event) {
            alert('A name was submitted: ' + this.input.current.value);
            event.preventDefault();
        }

        render() {
            return (
                <form onSubmit={this.handleSubmit}>
                    <label>
                        Name:
                        <input type="text" ref={this.input} />
                    </label>
                    <input type="submit" value="Submit" />
                </form>
            );
        }
    }

碎片

render的时候需要有一个父的元素,如果组件嵌套会多出来无用的元素,可以使用<React.Fragment> ... </React.Fragment>

class Columns extends React.Component {
    render() {
        return (
            <div>
                <td>Hello</td>
                <td>World</td>
            </div>
        );
    }
}
class Table extends React.Component {
    render() {
        return (
            <table>
                <tr>
                    <Columns />                    // 输出<div> ... </div>
                </tr>
            </table>
        );
    }
}

可以写成

class Columns extends React.Component {
    render() {
        return (
            <React.Fragment>
                <td>Hello</td>
                <td>World</td>
            </React.Fragment>
        );
    }
}

React脚手架搭建

一、可以使用官网的 create-react-app、ant或自己搭  https://github.com/facebook/create-react-app

二、使用的JSX和ES6所以需要转换,使用版本:

    react: "^15.4.2", react-dom: "^15.4.2", react-router: "^2.0.0"", webpack: "^3.10.0", webpack-dev-server: "^2.11.1"

    react 16以上版本和 react-router 4以上版本会有问题

三、搭建

    $ npm init

    $ npm i react react-dom react-router --save

    $ npm i webpack webpack-dev-server --save

    2、安装插件

    $ npm i babel babel-loader babel-core babel-preset-es2015 babel-preset-react --save

    $ npm i node-sass file-loader url-loader css-loader sass-loader style-loader --save

    $ npm i react-hot-loader prop-types events react-slot --save             // react组件,热更新、检测props类型、事件用来通信包、slot

    $ npm i html-webpack-plugin open-browser-webpack-plugin --save            // 自动引入静态资源到相应的html、自动打开浏览器

    $ touch .babelrc webpack.config.js

    $ mkdir src && cd src && touch index.html app.js

    $ .babelrc 加入

        {
            "presets": ["es2015", "react"]
        }

    $ webpack.config.js

        /**
        * User: siguang
        * Date: 2016/12/28
        * Time: 15:04
        */
        const webpack = require('webpack');
        const path = require('path');
        const HtmlWebpackPlugin = require('html-webpack-plugin');
        const openBrowserWebpackPlugin = require('open-browser-webpack-plugin');

        const basePath = __dirname;
        const appPath = path.resolve(basePath, 'src');
        const buildPath = path.resolve(basePath, 'build');

        module.exports = {
            entry: {
                app: path.resolve(appPath, 'app.js')
            },

            output: {
                path: buildPath,
                filename: '[name].min.js?[hash]',
                // chunkFilename: "[name].min.js?[hash]"
            },

            module: {
                loaders: [

                    // 处理require()引入的css文件,并将代码显示到页面的<style>中
                    { test: /\.css$/, loader: "style-loader!css-loader" },

                    // 将scss文件转成css文件
                    { test: /\.scss$/, loader: 'style!css!sass?sourceMap'},

                    // ?limit=8192  limit设置小于8k的图片转成64位编码,大小8于不会被转码
                    { test: /\.(png|jpg|woff|eot|ttf|svg|gif)$/, loader: 'url-loader?limit=8192'},

                    // ES6 转 ES5
                    {
                        test: /\.jsx?$/,
                        exclude: /node_modules/,
                        loader: 'babel-loader',
                        query: {
                            presets: ['es2015','react']
                        }
                    }
                ]
            },


            plugins: [

                // 压缩打包的文件
                new webpack.optimize.UglifyJsPlugin({
                    compress: {
                        //supresses warnings, usually from module minification
                        warnings: false
                    }
                }),

                // html
                new HtmlWebpackPlugin({
                    // 改变页面的<title>标签的内容
                    title: 'Hello World app',
                    // 模版地址
                    template: path.resolve(appPath, 'index.html'),
                    // 构建后的文件名和目录
                    filename: 'index.html',
                    //chunks这个参数告诉插件要引用entry里面的哪几个入口
                    // chunks:['app'],
                    //要把script插入标签里
                    inject:'body'
                }),

                // 热启动
                new webpack.HotModuleReplacementPlugin(),
                // 自动打开浏览器
                new openBrowserWebpackPlugin({ url: 'http://localhost:3000' })
            ],

            // 查找依赖
            resolve:{

                // require或alias时不需要写后缀
                extensions: [".js", ".jsx", ".css", ".json"],
            },

            // webpack-dev-server 配置
            devServer: {
                port: 3000,                 // 端口
                contentBase: 'build',       // 内容目录
                hot: true,                    // 热刷新
                inline: true
            }
        }`

$ package.json

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev": "webpack-dev-server --progress --profile --colors --hot --inline --history-api-fallback",
        "build": "webpack --progress --profile --colors --config webpack.production.config.js"
    },

$ 运行

    $ npm run dev     生产环境,并打开webpack服务器

    $ webpack        执行打包到build目录线上环境使用

https://segmentfault.com/a/1190000005969488

Diff算法

当组件更新时候,react会创建一个新的虚拟dom树并会和之前的dom树进行比较,这个过程就用到了diff算法

常用插件

https://github.com/enaqx/awesome-react#boilerplates

1、路由 - react-router

2、布局 - react-blocks     http://whoisandie.github.io/react-blocks/

3、拖拽 - react-dnd        https://github.com/react-dnd/react-dnd

4、代码编辑器 - react-codemirror        https://github.com/JedWatson/react-codemirror

5、富文本编辑器 - react-quill react-draft-wysiwyg        https://github.com/jpuri/react-draft-wysiwyg

6、拾色器 - rc-color-picker、react-color        https://github.com/react-component/color-picker        http://casesandberg.github.io/react-color/

7、响应式 - react-responsive、react-media    https://github.com/contra/react-responsive        https://github.com/ReactTraining/react-media

8、复制到剪贴板 - react-copy-to-clipboard       https://github.com/nkbt/react-copy-to-clipboard

9、管理 document head - react-helmet          https://github.com/nfl/react-helmet

10、Font Awesome 图标 - react-fa        https://github.com/andreypopp/react-fa

11、二维码 -  qrcode.react         https://ant.design/docs/react/recommendation-cn

12、不在使用className - styled-components

    http://www.alloyteam.com/2017/05/guide-styled-components/
    https://github.com/styled-components/styled-components

13、react写动画效果 - css3transform-react

    $ npm install css3transform-react
    http://www.alloyteam.com/2016/12/react-animations-difficult-to-write-try-react-transformjs/

react-slot - react中写solt    http://npm.taobao.org/package/react-slot

积累问题

1、jsx中for循环出标签并插入到render中, 或使用map

    class SideBar extends Component {
        constructor(props) {
            super(props);
            this.state ={
                menu: [
                    {
                        path: '/home',
                        name: '主页'
                    },
                    {
                        path: '/parentToChild',
                        name: '将父向子组件传数据'
                    },
                ]
            }
        }

        render() {
            // 定义一个返回菜单html内容的方法
            let renderMenuHtml = () => {
                let homeHtml = [];
                this.state.menu.forEach(function(item, idx, arr){
                    homeHtml.push(<li>
                        <Link to={item.path}>{item.name}</Link>
                    </li>)
                })
                return homeHtml
            }

            // 另一种写法map推荐
            {/*
                var renderMenuHtml = this.state.menu.map(function(c){
                    return(
                        <li>
                            <Link to={item.path}>{item.name}</Link>
                        </li>
                    );
                });
            */}

            return (
                <div className="side-box">
                    <ul>
                        {renderMenuHtml()}        {/* 插入内容 */}
                    </ul>
                </div>
            );
        }
    }


2、使用redux子组件会取不到 this.props.history

    因为redux会将值传给props,所以就需要通过context来获取

    解决方法: 在子组件中
    import PropTypes from 'prop-types'

    子组件名.contextTypes = {
        router: PropTypes.object.isRequired
    }

    console.log( this.context.router.history.push('/') );


3、子组件调用父组件中的方法

    class ComponentClider extends Component {
        constructor(props){
            super(props);
        }

        render(){
            return(
                <div>{ this.props.add(111,555) }</div>
            )
        }
    }

    export default ComponentParent extends Component {
        add(a, b){
            return a + b;
        }

        sub(a, b) {
            return a - b;
        }

        render(){
            return (
                <div>
                    {/* 这里可以父组件中自己的方法直接调用 */}
                    { this.add(100, 200) }
                    { this.sub(200, 10) }

                    <ComponentClider add={(a, b) => this.add(a, b)} sub={(a, b) => this.sub(a, b)}></ComponentClider>
                </div>
            )
        }
    } 

    <!-- 父组件也可以写成 -->
    export default ComponentParent extends Component {
        multiplicative(a, b) {
            return a * b
        }

        add = (a, b) => {
            return a + b;
        }

        sub = (a, b)  =>  {
            return a - b;
        }

        render(){
            const propsFun = {
                add: this.add,
                sub: this.sub
            }

            return (
                <div>
                    {/* 这里可以父组件中自己的方法直接调用 */}
                    { this.multiplicative(100, 200) }

                    <ComponentClider {...propsFun}></ComponentClider>
                </div>
            )
        }
    } 


4、react原生动态添加多个className会报错

    // 下面的引用会报错
    import style from './style.css'
    <div className={style.class1 style.class2}</div>

    // 解决 使用classnames
    $ npm install classnames --save

    import classnames from 'classnames'
    import styles from './index.less';

    const clsString = classNames(styles.submit, className);
    <div className={clsString}></div>

常用插件

1、react-document-title    根据不同的路由改变文档的title
    https://www.jianshu.com/p/07ed93350483

2、react-container-query   媒体查询 响应式组件

3、classnames      react引用多个className会报错问题

Antd UI组件问题收集

1、Table的每页条数  通过pagination属性来控制分页的内容

    <Table pagination={{ pageSize: this.state.queryInfo.pageSize }} rowSelection={rowSelection} columns={columns} dataSource={data}  />

    https://www.cnblogs.com/jenifurs-blog/p/6020737.html

| https://react.docschina.org/docs/hello-world.html
| http://www.css88.com/react/docs/try-react.html
| https://juejin.im/post/5a9410c25188257a61325eda // react 新老context
| https://www.jianshu.com/p/fb915d9c99c4 // 组件通信
| http://huziketang.com/books/react/
| http://blog.csdn.net/liwusen/article/category/6522963
| http://react-china.org/ 中文社区
| https://github.com/BruceCham/react-cli // 全家桶
| http://www.alloyteam.com/2015/04/%E5%89%8D%E6%B2%BF%E6%8A%80%E6%9C%AF%E8%A7%A3%E5%AF%86-virtualdom/ // virturalDOM 虚拟DOM
| https://github.com/gaearon/redux-devtools // redux-devtools
| https://guoyongfeng.github.io/book/
| http://uprogrammer.cn/react-tutorial-cn/
| http://huziketang.com/books/react/lesson1
| https://github.com/hyy1115/react-redux-webpack2
| https://github.com/zhbhun/react-learning/tree/master/boilerplate
| http://blog.csdn.net/u013063153/article/details/52497271 // 事件
| https://github.com/gaearon/babel-plugin-react-transform#transforms // babel-plugin-react-transform 相关插件
| http://www.alloyteam.com/2016/03/using-react-to-write-a-simple-activity-pages-design-of-operating-system-article/
| https://juejin.im/post/5a84682ef265da4e83266cc4 // 源码解析
| https://www.jianshu.com/p/ec7c2bab16cc?utm_campaign=maleskine&utm_content=note&utm_medium=pc_all_hots&utm_source=recommendation // vscode 调试react 通过debugger for chrome

Babel

| babel安装
| ES6转ES5 babel-preset-es2015
| jsx文件的转换 npm i babel-preset-react
| .babelrc 文件配置 presets来解析
| 加UMD模块,可以自带模块代码

插件

$ npm install babel-cli         // babel的命令行cli

$ npm install --save-dev babel-preset-react        // 转换JSX语法并去掉注释

    .babelre配置  { "presets": ["env", "react", "stage-2"] }


$ npm install --save-dev babel-preset-env        // 转义器将JS的 ES6、7转成ES5,官方废弃了ES2015/ES2016/ES2017使用babel-preset-env 来代替

    .babelre配置  { "presets": ["env"] }

$ npm install --save-dev babel-loader            // webpack的使用babel的加载器

$ npm install -save-dev babel-polyfill        // babel默认只转新的javascript语法,不会转新的API, 如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,需要使用babel-polyfill

Babel

babel支持的使用场景非常多,可以在浏览器中使用(browser)也可以在命令行(cli),还可以是我们常见的gulp和webpack中

一、安装:

    $ npm install babel-cli  babel-preset-env                    // 包括了: babel、babel-node、babel-core、babel-register

    // PolyFill 用于语法转换(如箭头函数)
    $ npm install --save-dev babel-polyfill                

    // babel-preset-react用于JSX语法转换Flow
    $ npm install --save-dev babel-preset-react                // .babelrc中需要加react

    $ touch .babelrc

        { "presets": ["env", "react"] }


        1、babel-register模块改写require命令,为它加上一个钩子。require加载.js、.jsx、.es和.es6后缀名的文件,就会先用Babel进行转码。

            npm install --save-dev babel-register

            // 先加载babel-register,这样就会不在对index.js进行转码了
            require("babel-register");
            require("./index.js");

        2、浏览器环境

            下载babel-core: npm install babel-core@5

            <!-- 引用browser.js -->
            <script src="node_modules/babel-core/browser.js"></script>
            <!-- type值为text/babel -->
            <script type="text/babel">
                // 这里写es6的代码
            </script>


二、babel用处

    1、将ES6转成ES5代码 babel-preset-es2015

        npm i babel-preset-es2015 --save-dev

        需要创建一个 .babelrc 文件
        {
              "presets": ["es2015"]
        }

    2、babel-polyfill: 可以在在浏览器直接解析    npm i babel-polyfill --save-dev

    3、React的JSX代码: npm i babel-preset-react --save-dev

        对.babelrc文件配置
        {
              "presets": ["es2015", "react"]
        }


三、执行编译

    # babel main.js     // 将文件直接编译

    # babel main.js --out-file  main-component.js     // 编译文件 - 将main.js编译成一个main-component.js, 缩定--out-file 写成 -o

    # babel src --out-dir build   // 编译目录 - 将src目录下的所有文件编译到build目录下,--out-dir简写 -d

    # babel --watch main.js --out-file main-component.js  --source-maps  // --watch 侦听文件的变化,--source-maps 会在文件打出文件的目录, 简写 -w

    # babel src --out-dir lib  // 编译目录,src目录下的所有文件进行编辑并放到lib文件夹中


四、浏览器上直接编译 browser.js

    可以直接转换,不需要执行编译命令

    1、加载需要文件
        babel-core/browser.js 
        babel-core/browser-polyfill.js     // 修补浏览器工具的,浏览器不支持的时候需要它

    2、<script>调用
        type中必须写成 'text/babel'
        <script src="main.js" type="text/babel"></script>

babel-cli

Babel 附带一个内置的 CLI,可用于从命令行编译文件, 用于执行命令

// 安装
$ npm install --save-dev babel-cli

// 执行
package.json中配置

    "scripts": {
        "build": "babel src -d build",        // 通过babel将src目录下的文件全部转译到build目录
    },

plugins

将运行代码分三个阶段:解析、转换、生成

.babelrc文件

    {
        "presets": [
            "es2015",            // es2015、es2016、es2017
            "react",
            "stage-2"            // stage-0...stage-4
        ]
    }

Stage-X 阶段

$ npm install --save-dev babel-preset-stage-0        // 安装

.babelrc
{
    "presets": ["stage-0"] 
}

Stage 0 - 稻草人: 只是一个想法,可能是 babel 插件

Stage 1 - 提案: 初步尝试

Stage 2 - 初稿: 完成初步规范

Stage 3 - 候选: 完成规范和浏览器初步实现

Stage 4 - 完成: 将被添加到下一年度发布

Balel 与 Gulp结合

// 安装gulp 和 gulp-bable包
$ npm i gulp gulp-babel --save

gulpFile:

    var gulp = require('gulp');
    var babel = require('gulp-babel');

    gulp.task('babelTask', function(){
        return gulp.src('./src/*.js')
            .pipe(babel())
            .pipe(gulp.dest('babelTask'))
    })

    gulp.task('default',['babelTask']);

Babel 与 Webpack结合

// 安装webpack和babel需要的包
$ npm install babel-loader babel-core babel-preset-es2015 webpack --save-dev

webpack.config.js:

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

    module.exports = {

        /* 页面入口 - 单入口文件 */
        entry: {
                index : './src/js/webpackPackMain.js'          // 单入口文件
        },

        output: {
                path: './dist/js/',
                filename: '[name].min.js?[hash]'            // [hash] 将文件输出后加一个hash值
        },

        //加载器配置
        module: {
                loaders: [
                    <!-- { test: /\.css$/, loader: 'style-loader!css-loader'},
                    { test: /\.js$/, loader: 'jsx-loader?harmony'},
                    { test: /\.scss$/, loader: 'style!css!sass?sourceMap'},

                    // ?limit=8192  limit设置小于8k的图片转成64位编码,大小8于不会被转码
                    { test: /\.(png|jpg|woff|eot|ttf|svg|gif)$/, loader: 'url-loader?limit=8192'}, -->

                    // es6转es5
                    {
                        test: /\.js$/,
                        exclude: /(node_modules|bower_components)/,
                        loader: 'babel-loader',
                        query: {
                            presets: ['es2015']
                        }
                    }
                ]
        }
    };

| https://babel.docschina.org/ // 官网

HTML、CSS深入理解

—————– CSS —————–

CSS规则

1、@charset 'utf-8' : 指定CSS的字符编码

2、@import 'test.css': 引用一个CSS文件

3、@media: media query使用的规则,对设备类型进行一些判断

4、@key-frames: 定义动画关键帧

    @keyframes diagonal-slide {
        from {
            left: 0;
            top: 0;
        }
        to {
            left: 100px;
            top: 100px;
        }
    }

5、@fontface: 定义一种字体

    @font-face {
        font-family: Gentium;
        src: url(http://example.com/fonts/Gentium.woff);
    }

    p { font-family: Gentium, serif; }

布局

一、内联元素与块元素的区别

    内联元素: 

        1、与其它内联元素都在并列同一行     

        2、不能设置宽、高

        3、不能设置上下外边距、内边距 margin-top、margin-bottom 和  padding-top、padding-bottom ,设置内边距也不会撑起父级高度

    块元素: 

        1、不指定宽度,会继承父元素的宽度,每个块元素都是独立一行

        2、元素的宽高都可以设置,如果不设置宽度就为100%;


二、display属性: 

    1、inline: 内联元素        2、block: 块元素

    3、inline-block: 具有block的宽高特性,又具有inline的同行元素特性

    4、table-cell: 文字的垂直居中,类似表格的单元格

    5、box: 弹性盒模型的过渡版本,现在用flex替换

    6、flex: flex是一个弹性布局的最新版本,老版本使用的box

        flex布局,子元素的float、clear、vertical-align属性将失效

        主要属性有两大类: 容器属性和项目属性


三、visibility 隐藏时可以保留元素的空间, display不会保留

    visible: 可视        hidden: 对象隐藏


四、overflow 

    overflow-x、overflow-y: 分别处理水平或垂直

    1、hidden: 隐藏溢出的内容

    2、scroll: 溢出的内容以滚动条显示

BFC浮动

BFC概念: Block Formatting context(块级格式化上下文) 页面中一块渲染区域,并且有一套渲染规则,决定子元素如何定位,以及他们之间的关系和相互作用

触发BFC - 只要元素满足下面任一条件即可触发 BFC 特性:

    body 根元素

    浮动元素:float 除 none 以外的值

    绝对定位元素:position (absolute、fixed)

    display 为 inline-block、table-cells、flex

    overflow 除了 visible 以外的值 (hidden、auto、scroll)

如果子元素设置了浮动 float:left; 那么浮动的元素就会脱离普通文档流, 不会撑起父元素的高度, 容器只剩下2px的边距高度

    <div style="border: 1px slid #000">        // 添加overflow: hidden
        <div style="width: 100px; height: 100px; background: #eee; float: left"></div>
    </div>


一、float 浮动

    left、right 左右浮动  浮动问题: 会使父级的高度失效,使用清除浮动来解决


二、clear 清除浮动

    both: 不允许有浮动对象     left: 不允许左边有浮动        right: 不允许有右边浮动

    /* 万能清除浮动 */
    .clear:after { content:''; display:block; clear:both; height:0; overflow:hidden; visibility:hidden; }
    .clear { zoom:1; }

    after伪类: 元素内部末尾添加内容;
        :after{content"添加的内容";} IE6,7下不兼容

    zoom 缩放 
        a、触发 IE下 haslayout,使元素根据自身内容计算宽高。
        b、FF 不支持;

盒模型

一、padding: 内边距 padding不支持负值

二、margin: 外边距 支持负值

    margin存在的问题: 

    1、适用于block元素,不起作用的absolute、fixed、inline、table-cell元素

    2、margin-top和margin-bottom 兄弟之间的会重叠

        解决方法:
            1、给当前元素加浮动 float: left
            2、给当前元素加 

    3、margin-top: 会影响到父元素(标准浏览器会影响,IE正常)

        解决方法: 给父元素加一个padding、border或overflow:hidden 即上面代码里的注释部分

三、border: 边框线

position 定位

一、absolute: 绝对定位,查找父子以上的元素是否定义了position,如果没有就以window为定位基准

二、relative: 相对定位

三、fixed: 始终以window为定位,固定到屏幕的某个位置,浏览器滚动也跟随

四、static: 

五、z-index: 层级堆叠顺序,值越高越在最上面,最小值为0,最大值为2147483647

background 背景

1、background-attachment: 背景图是随着滚动还是固定

    fixed: 相对窗体固定

    scroll: 背景图以元素固定,元素内容滚动时图像不会跟随滚动

2、transparent: 背景透明

background-color: 背景颜色 
background-image: 背景图片
background-repeat: 背景重复
background-position: 背景位置

文本

1、word-spacing: 单词与单词之间的间隔

2、letter-spacing: 字母与字母之间的间隔

3、word-wrap: 属性允许长单词或 URL 地址换行到下一行    @ break-word 在需要换行时才换

    如果不加些属于英文不会换行

4、word-break: 断字点进行换行

    break-all: 让英文象中文一样可以在行内做任意字间换行

    keep-all: 让中文向英文的换行方式接近,只在空格或英文标点符号才换行

5、white-space: 指定超出父级盒子宽度,文本进行换行(中、英文),white-space: nowrap;

6、text-overflow: 文本的溢出时隐藏,test-overflow: ellipsis;  溢出用省略号来修剪

    p {width: 100px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;}

7、text-indent: 文本的首行缩进

8、vertical-align: 文本的对齐方式

    * 只应用于inline水平以及table-cell元素  别把他放到div或p的块元素内

    1、线类

        baseline: 默认,元素的基线与父元素的基线对齐

        top、bottom、middle: 居上、下、中

    2、文本

        text-top、text-bottom: 

    3、上标下标类

        super: 上标   sub: 下标   不过位置都不太兼容,需要重写

    4、数值百分比

        vertical-align: 20px;

9、color: 文本颜色

10、text-align: 文本对齐 left right center justify

11、text-decoration: 文本装饰 overline 上划线  underline 下划线  line-through 从中间穿过的线

12、direction: 文字方向 rtl 从右向左    ltr 从左向右

13、line-height: 行高

表格

table: margin可以使用,除非设置 display: inline-table

1、border-collape: 表格或单元格边框合并到一起

    separate: 边框独立        collapse: 相邻合并

2、border-spacing: 表格或单元格之间的距离

表格单线条:

    .tab { border-spacing: 0;  border-collapse: collapse;}
    .tab td, .tab th { border-collapse: collapse; border: 1px #ccc solid; border-spacing: 0; padding: 10px 20px; }

长度

rem: 是相对于根元素(html)的font-size值为基准,em是相对父级元素变化,px是物理像素

vw/vh: 根据屏幕不同变化的

em: 相对长度,相对于父元素

语法与规则

1、!important 提升优先级

2、@import url("global.css"); 导入外部样式表

3、@charset 'uft-8' 编码

选择器

p{...} 元素选择器

.className{...} 类选择器

#idName{...} id选择器

.user[id='username']{...} 属性选择器

.claA .claB{...} 后代选择器

.clsA > .clsB {...} 子选择器

.clsA + .clsB {...} 相邻选择器

.clsA, .clsB{...} 选择器分组

伪类、伪元素

伪类 用于向某些选择器添加特殊效果

    a:link: 未被访问过
    a:visited: 已经被访问的链接
    a:hover: 鼠标指针移动到的链接
    a:active: 被点击的链接

    :first-childe: 向元素的第一个子元素添加样式

伪类元素 用于向某些选择器添加特殊效果

    :first-letter: 设置第一个字符的样式属性  ::first-letter

    :first-line: 设置第一行的样式    ::first-line

    :before 和 :after: 用于在元素前和元素后配置content属性添加内容    ::before   ::after

        .box::before { content: '这里是在box元素之前显示'}
        .box::after { content: '这里是在box元素之后显示' }

css3规则伪类使用一个":", 伪元素使用两个"::"

    : 用于css2的伪类,:: 用于css3的伪类

css基础属性

字体

    font-size: 字体大小

    font-family: 使用的字体

    font-style: 字体风格  @ italic 斜体

    font-weight: 字体重量

    font: 简写 

        按顺序 也可以设置第六个值为line-hgith
        font-style
        font-variant
        font-weight
        font-size/line-height
        font-family

链接

    a:link: 未被访问过

    a:visited: 已经被访问的链接

    a:hover: 鼠标指针移动到的链接

    a:active: 被点击的链接

列表

    list-style-image: 将图像设置为列表标志

    list-style-position: 标志的位置

    list-style-type: 标志类型  @circle 圆  @square 方块

    list-style: 简写属性

尺寸

    width、height: 宽高

    max-width、max-height: 最大宽高

    min-width、min-height: 最小宽高

透明度

    opacity: 0.4;

    filter: alpha(opacity=40); /* 针对 IE8 以及更早的版本 */

技巧

1、body高度为100%,html继承了浏览器的高度,body继承了html的高度,这样body就为100%了

    html{ height: 100%; }
    body { height: 100%; margin: 0;}
    .box { width: 100%; height: 100%; background-color: #ccc; }

2、浏览器hack

    .box { width: 100px\9; }

    浏览器(加粗表示支持)    CSS hack
    IE6        _background-color:#38DB24;
    IE6、7    *background-color:#38DB24;
    IE6、7    +background-color:#38DB24;
    IE6、7    #background-color:#38DB24;
    IE6、7    background-color:#38DB24 !ie;
    IE6、7、8、9、10    background-color:#38DB24\9;
    IE7、8、9、10&Firefox&Opera&Chrome&Safari        html>body .ie78910-all-hack { background-color: #38DB24 }
    IE8、9、10&Firefox&Opera&Chrome&Safari        html>/**/body .ie8910-all-hack { background-color: #38DB24 }
    IE8、9、10&Opera    background-color:#38DB24\0;
    IE9、10    :root .ie910-hack { background-color:#38DB24\9; }
    IE9、10    background-color:#38DB24\9\0;
    IE9、10&Firefox&Opera&Chrome&Safari    body:nth-of-type(1) .ie910-all-hack {background-color:#38DB24 ;}
    IE9、10&Firefox&Opera&Chrome&Safari    @media all and (min-width: 0px) { .ie910-all-2-hack{ background-color:#38DB24 ;} }
    IE9、10&Firefox&Opera&Chrome&Safari    @media all and (min-width: 0px) { .ie910-all-3-hack{background-color:#38DB24 ;} }
    IE9、10&Firefox&Opera&Chrome&Safari    :root *> .ie910-all-4-hack { background-color:#38DB24 }
    IE10    @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { .ie10-hack{background-color:#38DB24 ;} }
    Firefox    @-moz-document url-prefix() { .firefox-hack{background-color:#38DB24 ;} }
    Chrome&Safari    @media screen and (-webkit-min-device-pixel-ratio:0) {.chrome-safari-hack{background-color:#38DB24 ;} }

3、条件注释

    lt : 就是Less than的简写,也就是小于的意思。

    lte : 就是Less than or equal to的简写,也就是小于或等于的意思。

    gt : 就是Greater than的简写,也就是大于的意思。

    gte: 就是Greater than or equal to的简写,也就是大于或等于的意思。

    !: 就是不等于的意思,跟javascript里的不等于判断符相同。

    1、只有IE能识别
        <!--[if IE]>
            <link type="text/css" rel="stylesheet" href="my.css" />
        <![endif]-->

    2、指定版本
        <!--[if IE 8]> 
            <link type="text/css" rel="stylesheet" href="my.css" />   
        <![endif]-->

    3、低于指定版本才能识别
        <!--[if lt IE 7]> 
            <link type="text/css" rel="stylesheet" href="my.css" />   
        <![endif]-->


4、layout: IE的私有概念

5、zoom: 用于处发layout

    zoom: 1;

CSS Sprites

http://alloyteam.github.io/gopng

http://fis.baidu.com

http://gruntjs.com

—————– HTML —————–

文档

<!DOCTYPE html>
<!--[if IE 6]><html class="ie lt-ie8"><![endif]-->                // 如果浏览器是IE6显示当前html标签
<!--[if IE 7]><html class="ie lt-ie8"><![endif]-->
<!--[if IE 8]><html class="ie ie8"><![endif]-->
<!--[if IE 9]><html class="ie ie9"><![endif]-->
<!--[if !IE]><!--> <html lang="zh-CN"> <!--<![endif]-->
<head>
    <meta charset="UTF-8">                    // 文档字符集
    <title>京东(JD.COM)-正品低价、品质保障、配送及时、轻松购物!</title>
    <meta name="description" content="京东JD.COM-专业的综合网上购物商城" />            // 描述
    <meta name="Keywords" content="网上购物,网上商城,家电,手机,电脑,服装,居家,母婴,美妆,个护,食品,生鲜,京东" />            // 关键字
    <!--[if lte IE 7]>
        <script src="//misc.360buyimg.com/mtd/pc/index/home/ie6tip.min.js"></script>
    <![endif]-->
    <!--[if IE 8]>
        <script src="//storage.360buyimg.com/fragments/polyfill.js"></script>
    <![endif]-->
    <link rel="dns-prefetch" href="//static.360buyimg.com" />                // DNS预解析
    <link rel="icon" href="//www.jd.com/favicon.ico" mce_href="//www.jd.com/favicon.ico" type="image/x-icon" sizes="32x32" />            // 浏览器上显示图标和大小
    <link rel="icon" href="//www.jd.com/favicon.ico" mce_href="//www.jd.com/favicon.ico" type="image/x-icon" sizes="16x16" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="renderer" content="webkit" />
    <meta name="google-site-verification" content="4vmYcfLX0KWi82fvht-HAux15inXSVGVQ0tnUZqsdqE" />
    <base href="http://www.jd.com" target="_blank" />            // 定义页面全局链接的默认址地
</head>
<body>
    ...
</body>
</html>

可跨域的元素

<img>下的src

<script>的scr

<a>下的href

<iframe>下的src

HTML元素

1、<!DOCTYPE html> 声明文档解析类型,指定浏览器用哪个版本来解析页面

    解析类型有两种模式:

    1)怪异模式: 浏览器使用自己的怪异模式解析渲染页面(如果不声明doctype就是怪异模式)

    2)标准模式: 使用严格模式,以W3C的标准解析渲染页面

    HTML 4.01 规定了三种文档类型: Strict、Transitional 以及 Frameset

2、<html> 定义文档 <body> <head> 定义文档信息

3、<title>、<style>: 

4、<meta>: 文档元信息

5、<link>: 加载文档与外部资源

6、<script>: 定义脚本

7、<div>: 

8、<iframe>: 内联框架

9、<img>: 定义图像

10、<style>: 内联样式

11、<base>: 元素定义了基本的链接地址,该标签作为文档中所有链接的默认目标

文本元素

1、<p>: 段落, 有默认的上下外边距

2、<span>: 文档中的行内小块或区域

3、<a>: 定义锚,属性 href、title

4、<b>: 字体加粗

5、<i>: 斜体

6、<em>: 着重文字

7、<strong>: 加重语气

8、<u>: 下划线文字

9、<big>、<small> 大字体和小字体

    <h2>标准属性<small>id, class, title, style, dir, lang</small></h2>

10、<sub>、<sup>: 上、下标文本

11、<br>: 换行

12、<del>: 被删除的文本

13、<ins>: 定义被插入文本

14、<hr>: 定义水平线

15、<bdo> 定义字体显示的方法 ltr、rtl

    文字翻转显示 <bdo dir="rtl">Here is some text</bdo> 

代码元素

1、<samp>: 计算机输出

2、<var>: 文本的变量部分

3、<code>: 代码文本

4、<pre>: 预格式化文本, 不需要浏览器对标签内的内容进行排版

    <pre>
        <samp>
            <code>
                GET /home.html HTTP/1.1
                Host: www.example.org
            </code>
        </samp>
    </pre>

标题元素

1、<h1>...<h6>

列表元素

1、<ul>: 无序列表

2、<ol>: 有序列表

        <ol> <li>aaa</li> </ol>

3、<li>: 列表的项目

4、<dl>、<dt>、<dd>: 定义列表

表单元素

1、<form>

2、<fieldset>、<legend>: 定义围绕表单中元素的边框。

    <fieldset>
        <legend>健康信息</legend>
        身高: <input type="text" />
    </fieldset>

3、<input>

4、<label>: input元素的标注

5、<select>: 下拉菜单 <option>菜单内容

6、<button>: 按钮

7、<textarea>: 多行文本

表格元素

1、<table>

2、<tr>、<td>: 行、列

3、<caption>: 定义表格标题

4、<th>: 表格头单元

5、<thead>、<tbody>、<tfoot>: 表格页眉、主体、页脚

窗口框架

1、<frame>: 定义框架集窗口或框架

2、<frameset>: 定义框架集

3、<object>、<param>

| http://www.css88.com/book/css/
| http://www.w3cplus.com/
| https://www.nihaoshijie.com.cn/index.php/page/3
| http://jixianqianduan.com/page6/
| http://www.css88.com/archives/category/js-and-ria
| http://www.w3cplus.com/solution/index/index.html
| https://github.com/csswizardry/inuit.css/tree/master/base
| https://github.com/GumbyFramework/Gumby
| http://www.shejidaren.com/css-written-specifications.html
| https://zhuanlan.zhihu.com/p/25321647 BFC

HTML5深入理解

| 文件API FileList对象上传文件信息、FileReader()文件读取对象、FormData()异步上传文件
| 拖放API
| 离线应用 manifest
| postMessage 跨文档消息传送
| webScoket
| 本地存储localStorage、sessionStorage
| 多线程 web workers
| 获取地理位置 geolocation
| video、audio
| canvas绘图
| History 历史管理

新增语义类标签

1、header: 用于头部

2、footer: 用于页尾

3、nav: 用于导航

4、aside: 侧边栏,放置导航性质的内容

5、section: 文档的区块

6、article: 文章的独立主体

7、hgroup: 标题元素进行组合

8、details: 展示和隐藏文档的细节

    <details>
        <summary>Copyright 2011.</summary>            // 标题,默认【详细信息】
        生成于比比1
    </details>

9、abbr: 标签用来表示缩写

10、blockquote: 

    <blockquote>
        Here is a long quotation here is a long quotation here is a long quotation 
        here is a long quotation here is a long quotation here is a long quotation 
        here is a long quotation here is a long quotation here is a long quotation.
    </blockquote>

11、time: 日期

12、figure, figcaption: 用于图表和标签的结合

        <figure>
            <img src="https://.....440px-NeXTcube_first_webserver.JPG"/>
            <figcaption>The NeXT Computer used by Tim Berners-Lee at CERN.</figcaption>
        </figure>

13、dfn: 

14、s: 用于电商商品的打折 <s>¥5000000</s>

如果老浏览器对新增HTML5元素不使用JS来创建元素:

document.createElement('article')

公用属性

1、draggable: 可拖拽 <section draggable='true'></section>

2、contenteditable: 可以直接编辑页面的内容

表单类

一、input元素新增类型

    1、search: 用于搜索关键词 <input type="search" vlaue="" > 

    2、email: 需要输入正确的电子邮件地址 <input type="email" vlaue="" > 

    3、number: 只能输入数字,配合min、max属性

    4、range: 数值范围

        <input type="range" name="points" min="-360" max="360" class="rang" id="lateZ" />

        事件: onchange: 触发后执行,只触发一次        oninput: 最真实触发,拖动就触发

    5、tel: 点击只提供数字键盘

    6、url: 输入url

    7、pattern: 正则表达式     <input type="email" pattern="[^ @]*@[^ @]*" value="">


二、input元素属性: 

    1、readonly 只读

    2、disabled 不可用

    3、autocomplete: 自动完成功能就是输入过的内容会被缓存,下次在触发这个文本框会有下拉菜单的提示之前的输入,值为on或off

    4、placeholder: 内容为空时的提示 <input type="text" placeholder="请输入用户名">

    5、autofocus: 指定控件自动获取焦点 <input type="text" autofocus >

    6、require: 如果该元素为空,则无法提交表单 <input type="text" required />


邮件链接: <a href="mailto:cxz@126.com">发送邮件</a>
电话链接: <a href="tel:15012345678">打电话</a>

dataList数据列表

通过数据列表来实现自动补全的功能

<form action="/server" method="post">
    <input list="jslib" name="jslib">
    <datalist id="jslib">
        <option value="jQuery">
        <option value="Dojo">
        <option value="Prototype">
        <option value="Augular">
    </datalist>
    <input type="submit" value="完成" />
</form>

文件API

FileList、FileReader()、FormData() 对象

一、FileList对象、File对象: 读取本地文件

    HTML4: <file>控件内只允许放置一个文件,HTML5: 加入multipe属性,允许file添加多个文件

    Example:
        <input type="file" id="fileLoad" /> 
        <input type="file" id="fileLoad" multiple />          // mutiple 可以进行多个文件的选取
        <script>
            oUpFile.onclick = function(){
                var oFileLoad = document.querySelector('#fileLoad').files[0];        // 返回的是FileList对象列表
                for(var k in oFileLoad){
                    console.log(k, oFileLoad[k]);
                }
            }
        </script>

        FileList返回: 
        {
            name: f82f4a858d04d0a68f52.jpg,        // 文件名
            lastModified: 1462944176000,            // 最后修改日期
            lastModifiedDate: Wed May 11 2016 13:22:56 GMT+0800 (CST),// 最后修改日期
            webkitRelativePath,
            size: 554902,                                            // 文件大小
            type: image/jpeg                                    // 文件名型
        }

    https://segmentfault.com/a/1190000004084956


二、FileReader() 文件读取对象

    FileReader() 将文件读入内存,并且转成不同类型(二进制、DataURL、文本)

    方法:
        1、readAsBinaryString: 将文件读取为二进制码

        2、readAsDataURL: 将文件读取为DataURL,一段是以data:开头的 Base64位图片编码

        3、readAsText: 将文件读取为文本,第2个参数为编码类型,默认为UTF-8

        4、abort: 中断读取

    Example:
        let oFile = document.querySelector("oFile").files[0];        // 返回FileList对象

        let reader = new FileReader();    // 创建FileReader()对象读取文件
        reader.readAsDataURL(oFile);        // 将文件以什么格式读入页面
        reader.onload = function(e){
                $("#oimg").attr('src', e.target.result);    // e.target.result 来获取文件的格式
                $("#fileText").text(e.target.result);
        }


三、FormData() 对象

    FormData()可以异步上传二进制文件, 只能传文件、图片的二进制等

    <form>表单的enctype属性有三个值:

        1、application/x-www-form-urlencoded: 用来设置表单传输,默认也是这个值,所以form中不写enctype属性也是按这个默认去传的

        2、multipart/form-data: 用来传输图片或MP3等文件, 会以request payload提交数据

        3、text/plain: 用于传输文本,邮件用此编码        

    API:
        1、创建FormData , var formData = new FormData('表单名')

        2、get(key): 获取存储的字段的值

        3、append(key, value): 存储字段

        4、set(key, value): 修改值

        5、has(key): 判断是否存已经有了key

        6、delete(key): 删除数据

        7、formData.entries(): 遍历FormData

        8、next(): 遍历时所用下一个节点数据,如果没有返回undefined

        9、发送数据: 通过XHR

            var xhr = new XMLHttpRequest();
            xhr.open('post', 'login');
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.send(formData);

    Example:

        <form id="upFileForm" method="post" enctype=”multipart/form-data”>
            <input type="file" name="file" id="upFile">
            <input type="button" id="upFile" value="上传">
        </form>

        <script>                
            let from = document.querySelector('#upFileForm')[0];
            let uploadFile = document.querySelector("#upFile");
            let formData = new FormData(from);

            formData.append('file', uploadFile.files[0]);
            console.log(formData)

            $.ajax({
                url: '/remittanceDetail/import',
                type: "post",
                data: formData,
                processData: false,     // 告诉jQuery不要去处理发送的数据
                  contentType: false,     // 告诉jQuery不要去设置Content-Type请求头
                success: function(res) {
                    console.log('err', res)
                },
                error: function(res){
                    if(res == 0){
                        console.log('err', res) 
                    }
                    console.log('err', res)                      
                }
            });
        </script>

    https://segmentfault.com/a/1190000002680797
    https://segmentfault.com/a/1190000006716454
    http://www.cnblogs.com/lhb25/p/html5-formdata-tutorials.html

ArrayBuffer

ArrayBuffer是一段连续的长度固定的字节序列,如:通过实例化ArrayBuffer对象在内存中创建一段二进制存储空间(或叫二进制缓冲区),

// 创建一段字节长度为8的内存空间
var buffer = new ArrayBuffer(8);
// 获取字节长度
console.log(buffer.byteLength); // 8

Blob对象

处理对二进制的方法,通过Blob来操作二进制数据

var abc = new ArrayBuffer(80);        // ArrayBuffer ES6用来在内存中存一段二进制数据
var blob = new Blob([abc], {type: 'text/plain});

方法:

1、slice(): 将大文件分片,用于分片上传

https://www.cnblogs.com/hhhyaaon/p/5928152.html
https://github.com/eligrey/FileSaver.js

拖放API

拖放过程由两个部分构成:

    被拖拽的元素,之后简称为子项(item)
    放置被拖拽元素的元素,之后简称为容器(container)

1、draggable属性: 将想要拖放对象元素加入引属性设置为true

2、拖放事件: 

    子项事件: 
        1)dragstart - 拖拽开始

        2)drag - 拖拽过程中不断触发

        3)dragend - 拖拽结束,无论有没有拖进容器( 鼠标松开就触发 )

    容器事件:
        1)dragenter - 子项进入容器范围

        2)dragover - 子项在容器范围内不断触发

        3)dragleave - 子项离开容器范围

        4)drop - 拖拽结束,且子项成功拖进容器


    Example:
        <script>
            var oBox = document.querySelector('#box');            // 容器
            var oDragBlcok = document.querySelector('#dragBlcok');    // 拖拽块

            oDragBlcok.addEventListener('dragstart', function(e){
                e.dataTransfer.setData('name', 'siguang');
            })

            oDragBlcok.addEventListener('dragend', function(e){
                var name = e.dataTransfer.getData('name');
                console.log(name);
            })    
        </script>


3、拖拽事件对象

    e.dataTransfer: 拖拽文件的信息

        files: FileList对象,相当于input的type="file"的内容

            astModified:1494234931000
            lastModifiedDate:
            Mon May 08 2017 17:15:31 GMT+0800 (CST)
            name:"chongwutupianxiaotuxiaom.jpg"
            size:20926type:"image/jpeg"
            webkitRelativePath:""


4、DataTransfer对象: 拖拽时需要传递一些数据,DataTransfer就可以来对数据进行传输,绑定在拖放事件的Event中

    1)dataTransfer.items: 一个数据集合

    2)dataTransfer.setDragImage(element, x, y): 拖拽过程中定义一个元素替换原有的,可以看到拖拽元素跟随的效果。

    3)dataTransfer.setData(key, val): 添加自定义数据

    4)dataTransfer.getData(key): 获取自定义数据

    5)dataTransfer.clearData(): 清除自定义数据

    6)dataTransfer.getData(format): 播放文件列表

离线应用

在没有网络的情况下,可以使用本地缓存的离线数据也可以使web应用运行进来

1、离线与缓存的区别

    两都都是为了更好的缓存各种文件以提高读取速度,两者对网络环境有要求: 

    1、网页缓存依赖有网络的情况,离线应用在离线下仍然可用

    2、网页缓存主要缓存当前页面的内容,离线应用是缓存的指定文件,在离线状态下仍可以访问


2、manifest([ˈmænəˌfɛst]显示)文件

    通过manifest文件来管理哪些文件需要缓存

    设置完后所有本地缓存的文件存储到Application Cache中,如果段网时在Network中查看缓存的文件为(from cache)

    offline.manifest:
        CACHE MANIFEST // 必要,把文件的作用告诉给浏览器,让文件支持text/cache-manifest
        #Version 1.0
        CACHE:  // chche,指定需要被缓存的资源,浏览器会对这些设置的资源
            index.html  
            style.css
            images/2.jpg
            default.js

        NETWORK:    // 指定不进行缓存的资源,如果为“*”通配符,表示所有资源都不被缓存
            # 1.jpg
            images/1.jpg            

        FALLBACK:             // 每行指定两个资源,如果
            /js/test/index.html   /js/test/404.html


3、需要在html页面中的<html>标签加入manifest="offline.manifest"

    <html lang="en" manifest="offline.manifest">


4、applicationCache对象

    1)检测是否支持离线应用

        if(window.applicationCache){
            // 支持
        }

    2)属性: 

        applicationCache.status返回: 离线缓存状态
            0: 无缓存
            1: 闲置
            2: 检查中
            3: 下载中
            4: 更新完成
            5: 废弃

    3)事件: 
        checking: 检查缓存更新时;
        error: 检查更新或下载资源时发声错误
        noupdate: 描述文件无变化
        downloading: 开始下载应用缓存资源
        progress: 下载缓存资源过程中
        updateready: 下载完毕
        cached: 应用缓存完整可用时

        applicationCache.addEventListener('updateready', function(){  // 资源下载中  }, false)

    4)applicationCache.update(): 让离线缓存检查更新上面的事件


5、检测是否有网络 online 和 offline

    // navigator.onLine如果设置为true表示能上网
    if (navigator.onLine) {
        // statement if online
    } else {
        // statement if offline
    }

    // 侦听当网络变化的时候触发
    window.addEventListener('online', function(){
        console.log('在线');
    }, false);

    window.addEventListener('offline', function(){
        console.log('离线');
    }, false);

postMessage() 跨文档消息传输

HTML5来进行两个不同跨域的页面来消息传递(iframe不同域)

1、postMessage('发送数据', 要发送到的URL): 发送消息

2、message: 事件来接收消息,其中event对象

    evt.origin: 发送消息所在的域

    evt.data: 接收到的数据

    evt.source: 向来源可以在回执信息


Example:

    <iframe id="myframe" src="originPage.html"></iframe>
    <button id="sendBtn">发送消息</button>

    <script>

        // 接收originPage.html页面消息
        window.addEventListener('message', function(evt){

            // ev.origin 获取消息的URL,如果不是taobao就不执行
            if(ev.origin != "http://www.taobao.com"){
                return false;
            }

            // ev.data 传输的数据
            alert("那里传来的消息: " + ev.data)

        }, false);

        // 向originPage.html页面 发送消息
        var oSendBtn = document.querySelector('#sendBtn');
        oSendBtn.onclick = function(){
            var iframWindow = document.querySelector('#myframe');

            // postMessage()
            iframWindow.postMessage("A secret", "http://www.w3cmm.com");        // window.parent.postMessage(data,'*');
        }    

    </script>


iframe的父子窗口操作:

    iframe获取父窗体的元素: window.parent.xxxx

        如果iframe嵌套多层,直接获取最顶层的窗体 window.top.xxxx

    父窗体获取iframe内的元素: oIfr.contentWindow.document.body.offsetHeight

webSocket

webScoket提供了浏览器和服务器之间的长链接通信,只有一方提出断开socket才会断开,否则使终链接状态

传统使用Ajax轮询来定时获取服务器的数据,缺点是每隔一断时间就需要请求一次服务器,都需要创建一次TCP和断开一次TCP连接,HTTP请求,会对服务器有压力,
使用webScoket就可以省去连接的步聚,客户端可以一直侦听服务器端推送的数据来进行处理就可以了.

创建WebSocket对象 var oWebSocket = new WebSocket('ws://192.168.1.1:8005/socket');

属性: 
    1、readyState: 获取socket的状态 ["正在连接", "已建立连接", "正在关闭连接", "已关闭连接"]

方法: 
    1、send(data): 向服务器发送数据

    2、close(): 关闭socket连接


事件: 
    1、onmessage(): 接收服务器发送的消息

    2、onopen(): 侦听打开socket

    3、onclose(): 侦听关闭socket时

示例: 
    <script>
         var statusArr = ["正在连接", "已建立连接", "正在关闭连接", "已关闭连接"];

        var oSocket = new WebSocket("ws//www.baidu.com:8089");            // 必须使用ws或wss开头

        // 侦听socket打开事件
        oSocket.onopen = function(evt){
            console.log(statusArr[oSocket.readyState]);
        }

        // 侦听socket关闭
        oSocket.onclose = function(evt){
            console.log(statusArr[oSocket.readyState]);
        }

        // 侦听接收服务器端传来的数据
        oSocket.onmessage = function(evt){
            var data = evt.data;
            console.log(data);
        }

        // 向服务器发送数据
        $("#box").click(function(){
            oSocket.send("向服务器发送数据")
        })

        // 断开与服务器的socket连接
        $("#close").click(function(){
            oSocket.close();
        })
    </script>

本地存储 localStorage、sessionStorage

本地存储与cookie的区别

    cookie: 存储量比较少(浏览器不同,大致4k),有个数限制,会随请求发送到服务器

    localStorage: 永久存储,每个域存储(Chrome是2.6MB,IE是5MB),总体数量无限制

    sessionStorage: 只在session内有限,存储没有限制

方法: 
    1、setItem(key, value): 保存数据

    2、getItem(key): 获取数据

    3、clear(): 清空存储中的所有数据

    4、removeItem(key): 删除存储中的一项

    5、key(n): 返回存储中的第n个键名

    length: 返回存储数量

监听: 
    window.addEventListener('storage', showStorageEvent, false);

web Workers 多线程

js是单线程,页面有大量计算就很容易阻塞页面的执行,H5可以使用web workers来处理.

创建web workers对象:  new Worker('work.js');

方法: 
    1、postMessage(data): 向web workers传送数据

事件: 
    1、onmessage(): 监听处理完发送的数据

    2、onerror(): 错误时处理的事件

Example: 

    main.js: 
        var oWorker = new Worker('js/worker.js');
        oWorker.postMessage(1000000);    // 发送要处理的数据
        oWorker.onmessage = function(ev){
            var od = ev.data;            // 接收处理完的值
        }

    worker.js
        onmessage = function(ev){    // 侦听传来的数据
            var od = ev.data;
            var num = 20;
            for(var i=0; i<od; i++){
                num *= i;
            }
            postMessage(num);        // 多处理处理完返回的数据
        }


注意: 
    1、多线程必须要在服务环境下进行开发,否则会报错   
    2、处理线程的JS文件,没有window,document,DOM等对象。但是可以使用navigator,location,XMLHttpRequest等对象。
        这些限制导致了Web Worker一般用于有耗时较长的业务中,比如有大量计算的页面

Geoloation 地理位置

处于安全考虑,地理位置信息属于用户隐私,当浏览器获取设备信息需要得到用户的确认

检测是否可以使用:

    if(navigator.geoloation){
        // 支持地址位置信息
    }

一、Geoloation方法: 

    1、getCurrentPosition(      // 首次取得当前地理位置
            function(position){
                // 返回坐标回调 position对象
                pos.latitude
            },
            function(error){
                // 错误显示
            },
            {对象用来处理如何获取位置}
        }

    2、watchPosition(): 监听不断变化的移动设备,原理与steInterval差不多,用法与getCurrentPosition一样也是三个参数

    3、clearWatch(): 删除监听watchPosition()

    Example:
        navigator.geoloation.getCurrentPosition(function(pos){
            // pos.coords.latitude;        // 当前纬度
        })


二、position对象: 获取地理位置成功后返回position对象

    属性: 
        1、latitude: 纬度

        2、longitude: 经度

        3、altitude: 海拔

        4、accuracy: 纬度或纬度的精度(以米为单位)

        5、altitudeAccurancy: 获取到海拔高度的精度(以米为单位)

        6、heading: 设备前进方向,以旋转角度来表示

        7、speed: 设备前进的速度(以米/秒为单位)

        8、timestamp: 获取地理位置信息的时间

    错误返回三种值: 1 = 用户拒绝了位置服务、 2 = 获取不到位置信息、3 = 获取信息超时错误

    timeout: 几秒后获取不到返回失败

    maxmumAge: 对地理位置 进行缓存的有效时间(毫秒)

    Example:
        <script>
            var oBox = getId("box");
            var sHtml = [];

            function getId(id){
                return document.getElementById(id);
            }

            function successFun(position){
                console.log("地理位置是: " +position.coords.latitude+","+position.coords.longitude);
            }

            function errorFun(err){
                // console.log(err.message); // 错误信息
                // console.log(err.code);    // 错误码

                switch(err.code){
                    case 1:
                        alert("用户拒绝了位置服务");
                        break;
                    case 2:
                        alert("获取不到位置信息");
                        break;
                    case 3:
                        alert("获取信息超时错误");
                        break;
                }
            }

            // 创建geolocation对象
            function createGeolocation(){
                if(navigator.geolocation){  // 标准浏览器支持

                    // 获取坐标
                    navigator.geolocation.getCurrentPosition(successFun, errorFun, {
                        // 设置缓存有效时间为2分钟
                        maximumAge : 60*1000*2,

                        // 5秒内未获取到地理位置则返回错误
                        timeout : 10000
                    })
                }
                else{
                    alert("你使用的是非标准浏览器");
                }
            }

            createGeolocation();
        </script>

http://www.alloyteam.com/2015/08/mobile-phone-location-on-the-sensor/

Video 和 audio 多媒体

canvas绘图

History 历史管理

可以在添加一条记录到历史记录的列表中,或者在没有刷新时,可以更新地址栏的URL。单页面的的跳转就用到了这里

例Vue的路由有两种模式: hash和history, history就用到了历史管理,使url改变不会去请求http

一、JS对象

    1、length: 浏览器历史列表url的数量

    2、back(): 向后一个url

    3、forward(): 向前一个url

    4、go(-1): 指定跳转到哪个历史


二、HTML5提供两个新方法: 

    可以通过新增的方法做到页面跳转不重新请求页面

    1、history.state: 当前url下对应状态信息,如果当前url不是通过pushState或replaceState添加的, state 

    2、history.pushState(state, title, url): 在不刷新页面的情况下,添加历史记录,可以前进和后退

        state: 存储JSON字符串

        title: 浏览器不支持设置null

        url: 更新浏览器的地址

    3、history.replaceState(): 与pushState基本上同,不同的是不可以前进和后退

    4、popstate 事件: 侦听前进和后退

    Example:

        window.addEventListener('popstate', function(e){
            getContent(location.pathname, false);
        })

        var getContent=(url, addEnter) => {
            $.get(url, function(dat){
                history.pushState(null, null, url)
            })
        }

https://segmentfault.com/a/1190000002468274
http://www.zhangxinxu.com/wordpress/2013/06/html5-history-api-pushstate-replacestate-ajax/
http://www.cnblogs.com/flash3d/archive/2013/10/23/3384823.html