TypeScript

typeScript

typeScript由微软研发的编程语言,是 JavaScript 语言的超集,代码又最终会编译成 JavaScript 来执行

一、安装

$ npm install -g typescript

二、编译

$ tsc greeter.ts

基本类型

1、布尔

let createDone: boolean = false;    

2、数字

let createNumber: number = 10;

3、字符串

let createString: string = 'aaa';
let showString: stinrg = `hello ${createNumber}`

4、数组

let list: number[] = [1,2,3]
let listString: string[] = ['1','2','3']
let numandString: (number | string)[] = ['1',2,3]

5、元组 Tuple

允许一个已知的元素数量和类型的数据
let x: [string, number];
x = ['hello', 10]

6、枚举

enum Color { Red, Green, Blue }; 
let c: Color = Color.Green

7、任意类型 any

let notSure: any = 4;   // any 可以对不同类型的值
notSure = 'a string instead';

let list: any[] = [1, true, 'free'];
list[1] = 100

8、空值 void

void 表示没有任何类型,一个函数无返回值时返回类型是void;
function warnUser(): void(){
  console.log('...');
}

let unusable: void = undefined;

9、Object

function create(o: object | null):void;
create({ prop: 0});

10、Null 和 Undefined

let u: undefined = undefined;
let n: null = null;

11、Never 永不存在值的类型

function infiniteLoop(): never {
  while (true) {
  }
}

12、类型断言 <>、as

断言有两种写法<>和as,用来指定一个值的类型

let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
let strLength: number = (someValue as string).length;

解构

1、解构数组

let input = [1, 2];
function f([first, second]: [number, number]){
  console.log(first);
  console.log(second);
}
f(input);

接口

1、interface来做成定义的接口

interface SuperConfug { 
  color: string;  
  width: number;
}

function printLabel(super: SuperConfug) {
  console.log(super.color);
}
let myObj = {color: 'blud', width: 100};
printLabel(myObj);

2、readonly 表示只读,不能对其属性进行重新赋值

interface Point {  
  readonly x: number;  
  readonly y: number;
}

3、?表示属性是可选的

// [propName: string]: any 表示允许 obj[xxx] 这样的动态属性
interface SquareConfig {  
  color?: string;  
  width?: number;  
  [propName: string]: any;
}

4、函数接口

interface SearchFunc {  
  (source: string, subString: string): boolean;
}

函数

1、参数

function fn(source: string, subString: string){
  let result = source.search(subString);
  return result > -1;
}
fn('aaa', 'bbbbb');

2、为函数定义类型

function add(x: nubmer, y: number): number {
  return x + y;
}

2、索引类型

interface StringArray {
  [index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

泛型

泛型允许延迟编写类或方法中元素的数据类型

function identity<T>(arg: T): T{
  return arg;
}

function main() {
  const result = identity<number>(1);
}

1、创建类

class Greeter {
  greeting: string;
  constructor(message: string){     // 定义message为字符串类型
    this.greeting = message;
  }
  greet(){
    return `Hello, ${this.greeting}`;
  }
}

let oGreeter = new Greeter('111');

2、继承

class Animal {
  move(distance: number = 0) {
    console.log(`Animal moved ${distance}.`);
  }
}

class Dog extends Animal {
  bark() {
    console.log('Woof! Woof!');
  }
}

const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();

3、增加了public, private(不能被外部访问), protected(不能被外部访问,只能被内部和继承访问), readonly 等访问控制修饰符

class Person {  
  protected name: string;  
  constructor(name: string) {    
    this.name = name;  
  }
}
class Employee extends Person {  
  private department: string;  
  constructor(name: string, department: string) {    
    super(name);    
    this.department = department;  
  }  
  public getElevatorPitch() {    
    return `Hello, my name is ${this.name} and I work in ${this.department}.`;  
  }
}

readonly属性:
class Person {
  readonly name: string = 'john'; // 我只读
  constructor(theName: string) {
    this.name = theName; // 可以
  }

  setName() {
    this.name = 'lili'; // 报错
  }
}

4、静态属性static

static成了所有实例共有的成员

class Person {
  static globalPeopleCount: number = '7000000000';
}
const john = new Person();
john.globalPeopleCount += 1;

const lili = new Person();
lili.globalPeopleCount // 7000000001

5、抽象类

不能被实例化的类型,目的就是用来继承

abstract class Animal {
  abstract makeSound(): void;
  move(): void {
    console.log('roaming the earch...');
  }
}

配置

1、node

$ npm install -g ts-node  // 安装ts-node来执行ts文件

$ ts-node server.ts       // 执行

2、react配置

$ npm install @types/react

2、tsconfig.json

{  
  "compilerOptions": {   
    "module": "commonjs",          // 表示这是一个 Node.js 项目,使用 CommonJS 模块机制。
    "moduleResolution": "node", 
    "target": "es6",             // 指定将代码编译到 ES6
    "rootDir": "src",            // 指定源码输入目录和编译后的代码输出目录
    "outDir": "dist", 
    "sourceMap": true, 
    "noImplicitAny": true,       // 开头的几个选项指定一些更严格的检查
    "noImplicitReturns": true, 
    "noImplicitThis": true 
  }
}

3、TSlint

$ npm install tslint -g

根目录创建tslint.json:
{  
  "extends": [ "tslint:recommended" ],  
  "rules": {    
    "no-console": [ false],    
    "only-arrow-functions": [ false ] 
  }
}

$ tslint --fix src/**/*.ts      // 执行

4、webpack中使用

$ npm install ts-loader typescript --save-dev

webpack.config.js

module.exports = {
  entry: './app.ts',
    output: {
    filename: 'bundle.js'
    },
    resolve: {
      extensions: [ '.ts', '.tsx', '.js' ]
    },
    module: {
      loaders: [     
        {
          test: /.tsx?$/
          loader: 'ts-loader'
        }    
      ]
    },
  };

tsconfig.json中配置

{  
  "compilerOptions": {    
    "module": "commonjs",
    "moduleResolution": "node",
    "target": "es6",
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noImplicitThis": true  
  }
}

5、小程序

https://segmentfault.com/a/1190000008175944

| https://github.com/semlinker/awesome-typescript // 合集
| https://zhongsp.gitbooks.io/typescript-handbook/doc/handbook/Basic%20Types.html
| https://mp.weixin.qq.com/s/Oyawvb5BD-OKvMuF2tQ0pw?
| https://www.jianshu.com/p/f317a3c01b58

React(之四)其它框架状态管理及框架

| dva
| redux
| redux-saga
| redux-thunk
| Ant Design Pro

状态管理框架

https://cn.mobx.js.org/

// redux-saga 中间件
https://redux-saga-in-chinese.js.org/    

// dva
https://dvajs.com/guide/#%E7%89%B9%E6%80%A7        dva

redux-saga

redux-saga 是一个用于管理 Redux 应用异步操作的中间件(又称异步 action),Sagas是通过Generator函数来创建

Reducers 负责处理 action 的 state 更新
Sagas 负责协调那些复杂或异步的操作

一、安装

    $ npm install --save redux-saga


二、使用

    sagas.js   // 创建一saga.js文件

    main.js

        import { createStore, applyMiddleware } from 'redux'
        import createSagaMiddleware from 'redux-saga'

        import reducer from './reducers'
        import mySaga from './sagas'

        // 创建saga中间件
        const sagaMiddleware = createSagaMiddleware()

        // 加到createStore中
        const store = createStore(
            reducer,
            applyMiddleware(sagaMiddleware)
        )

        // 运行 saga
        sagaMiddleware.run(mySaga)


三、核心函数

    1、takeEveny('actionName', 执行的saga函数) - type的action触发,就执行goAge()函数

    2、takeLatest()

    3、createSagaMiddleware():创建一个Reudx中间件,将Sagas与Redux Store链接起来

    4、middleware.run():运行sagas,


四、Effect 

    import { call, put, takeEveny } from 'redux-saga/effects'

    1、take():监听未来的action

        function* watchFetchData() {
            while(true) {
                // 监听一个type为 'FETCH_REQUESTED' 的action的执行,直到等到这个Action被触发,才会接着执行下面的 yield fork(fetchData)  语句
                yield take('FETCH_REQUESTED');
                yield fork(fetchData);
            }
        }

    2、takeEveny(): 

        function* rootSaga() {     // 在store.js中,执行了 sagaMiddleware.run(rootSaga)
            yield takeEvery("ADD_SAGA", addSagas)   // 如果有对应type的action触发,就执行goAge()函数
        }

    3、put():发送action的effect,简单把它理解为dispatch

        export function* toggleItemFlow() {
            let list = []
            // 发送一个type为 'UPDATE_DATA' 的Action,用来更新数据,参数为 `data:list`
            yield put({
                type: actionTypes.UPDATE_DATA,
                data: list
            })
        }

    4、call():简单的理解为就是可以调用其他函数的函数

        export const delay = ms => new Promise(resolve => setTimeout(resolve, ms))

        export function* removeItem() {
            try {
                // 这里call 函数就调用了 delay 函数,delay 函数为一个返回promise 的函数
                return yield call(delay, 500)
            } catch (err) {
                yield put({type: actionTypes.ERROR})
            }
        }

    5、fork():用来调用其它函数,是一个非阻塞函数,

        export default function* rootSaga() {
            // 下面的四个 Generator 函数会一次执行,不会阻塞执行
            yield fork(addItemFlow)
            yield fork(removeItemFlow)
            yield fork(toggleItemFlow)
            yield fork(modifyItem)
        }

    6、select():获取Store中的state值

        let tempList = yield select(state => {
            debugger;
        })


https://www.jianshu.com/p/7cac18e8d870
https://github.com/redux-saga/redux-saga/ 官网
https://redux-saga-in-chinese.js.org/ 中文在线文档
https://segmentfault.com/a/1190000007248878 Redux异步方案选型
https://www.jianshu.com/p/f3c7594c4fb4 redux-saga 初级学习教程
https://github.com/Pines-Cheng/blog/issues/9 从redux-thunk到redux-saga实践
http://yanqiw.github.io/react/2017/03/05/redux-saga.html Redux Saga实践

dva.js

dva是redux和redux-saga的数据流文案,还内置了react-router和fetch的一个应用框架

一、安装

    $ sudo npm i dva-cli -g

    $ sudo dva new dva-quickstart


二、定义Model

    把一个领域的模型管理起来,包含同步更新state的reducers,处理异步逻辑

    export default {
        namespace: 'products',  // 表示在全局 state 上的 key,最好与组件名相同保持统一
        state: {},                            // 初始值
        reducers: {                            // 等同于 redux 里的 reducer,接收 action,同步更新 state
            save(state, action) {
                return {
                    ...state,
                    data: action.payload,
                };
            },
        }
    }


三、connect 起来

    通过connect将model和component联接起来

    class products extends Componet {
        ... 

        render {
            const { dispatch, products } = this.props

            return (
                <div></div>
            )
        }
    }

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


四、models

    dispatch

    Reducer(state, action): 

    effects: 异步操作,底层引入redux-sagas,采用了generator

    Subscription: 

    Router: 


五、整理

    1、调用同步和异步

        调用reducers内的方法是同步,直接改变指定state的值

        调用effects内的方法是异步的调用,调取成功后在调用reducers中的方法来改变state


安装后目录结构:
|- mock                        // mock
|- node_modules        // 包
|- package.json        
|- public
|- src
        |- asserts            // 静态资源,打包会经过webpack处理
        |- components        // 存放React组件,公用的无状态组件
        |- models                // 模型文件
        |- routes                // 存放需要connect model的路由组件
        |- services            // 存放服务文件,一般是网络请求
        |- utils                // 工具库
        |- router.js        // 路由文件
        |- index.js            // 项目入口
        |- index.css
|- .editorconfig        // 编辑器配置文件
|- .eslintrc
|- .gitignore
|- .roadhogrc.mock.js    // Mock配置文件
|- .webpackrc                //  自定义的webpack配置文件


https://dvajs.com/        // dva

Ant Design Pro

安装:
$ git clone --depth=1 https://github.com/ant-design/ant-design-pro.git my-project
$ cd my-project
$ npm install

启动服务:
$ npm start                            // mock数据
$ npm start:no-mock         // 不走mock数据
$ npm run prettier            // 格式化代码
$ npm run lint-staged        // 检测

构建:
$ npm run build


一、路由

    脚手架默认提供了两种布局模板:基础布局 - BasicLayout 以及 账户相关布局 - UserLayout

    router.config.js

    1、name、icon - 菜单项和图标

    2、hideChildrenInMenu - 菜单子路由是否展示

    3、hideInMenu - 菜单中不展示这个路由

    4、authority - 指写可以看当前菜单的用户 Array

    // app
    {
        path: '/',
        component: '../layouts/BasicLayout',
        Routes: ['src/pages/Authorized'],
        authority: ['admin', 'user'],
        routes: [
            {
                path: '/dashboard',
                name: 'dashboard',
                icon: 'dashboard',
                hideChildrenInMenu: true,                    // 隐藏所有子菜单,但这块需要加一个对应dashboard路由的component: './Dashboard/Analysis'
                routes: [
                    {
                        path: '/dashboard/analysis',
                        name: 'analysis',
                        component: './Dashboard/Analysis',
                    },
                    ...
                ],
            }
        ]
    }
    // new 这里是新增布局
    {
        path: '/new',
        component: '../layouts/new_page',
        routes:[...]
    },


二、config.js 配置代理到后端服务器

    {
        proxy:{
            '/server/api/': {
                target: 'https://preview.pro.ant.design/',
                changeOrigin: true,
                pathRewrite: { '^/server': '' }, // /server/api/currentUser -> /api/currentUser
            },
        }
    }

三、支持SASS

    $ npm i node-sass sass-loader --save            // 安装依赖


四、页面添加 dva

    modle - 分两种: 1、全局models(存在/src/models/)   2、页面models (存在于每个业务下/models 不能被其他页面所引用)

    service - 请求数据


五、请求的过程

    1、UI 组件交互操作

    2、调用 model 的 effect

    3、调用统一管理的 service 请求函数

    4、使用封装的 request.js 发送请求

    5、获取服务端返回

    6、然后调用 reducer 改变 state

    7、更新 model


六、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'); },
    };

    1、可以引用Mock.js第三方库

        import mockjs from 'mockjs';

        export default {
            // 使用 mockjs 等三方库
            'GET /api/tags': mockjs.mock({
                'list|100': [{ name: '@city', 'value|1-100': 50, 'type|0-2': 1 }],
            }),
        };

七、自定义主题

    config/config.js文件

    theme: {
        'font-size-base': '14px',
        'badge-font-size': '12px',
        'btn-font-size-lg': '@font-size-base',
        'menu-dark-bg': '#00182E',
        'menu-dark-submenu-bg': '#000B14',
        'layout-sider-background': '#00182E',
        'layout-body-background': '#f0f2f5',
    };


八、项目总结

    1、Mock数据不能在生产环境使用,只能在开发环境

    2、使用动态路由时切换时取不到参数,见下面UMI动态路由解决方法

目录

├── config              # umi 配置,包含路由,构建等配置
│   ├── config.js                        #    构建
│   ├── plugin.config.js
│   ├── router.config.js      # 路由配置文件
├── mock                # 本地模拟数据
├── public
│   └── favicon.png         # Favicon
├── layouts                            # 框架页面
├──     ├── BasicLayout                # Basic框架页
├──     ├── Header                        # 头  
├──   ├── Footer                        # 尾
├── locales
|          ├── zh-CN
|            |            ├── menu.js            # 配置显示在菜单对应路由的中文名
├── src                                    # 重要
│   ├── assets              # 本地静态资源
│   ├── components          # 业务通用组件
│   │       ├── GlobalHeader        # 顶部右侧部分内容
│   ├── e2e                 # 集成测试用例
│   ├── layouts             # 通用布局
│   │            ├── BasicLayouts      # 基础布局
│   ├── models              # 全局 dva model
│   |            ├── menu.js                    # 菜单处理过滤
│   |            ├── login.js                # 登录请求
│   ├── pages               # 业务页面入口和常用模板
│   │            ├── document.ejs        # 首页模板
│   │            ├── User                        # Login/Register  登录和注册组件
│   ├── services            # 后台接口服务
│   ├── utils               # 工具库
│   ├── locales             # 国际化资源
│   ├── global.less         # 全局样式
│   ├── defaultSettings.js    # 配置菜单样式等
│   └── global.js           # 全局 JS
├── utils                                # 工具
├──     ├── request.js                # 封装Ajax请求
├──     ├── Authorized                # 授权
├── models                            # 全局
├──     ├── menu                            # 菜单的配置和过滤
├──   ├── 
├── tests               # 测试工具
├── README.md
└── package.json

Umi.js

umi,中文可发音为乌米, 内置了react、react-router,以路由为基础,支持next.js的约定式路由

一、安装

    $ yarn global add umi     // 安装 umi -v 来查看版本

    $ mkdir myumi && cd myumi

    1、脚手架创建

        $ yarn creat umi                 // 通过creat-umi脚手架创建,其实就安装了 Ant Design Pro 的简版没有components


    2、普通创建

        $ umi g page index            // 简单创建页面

            umi g page users

        $ umi dev            // 启动服务

        $ umi build        // 构建


二、路由

    约定式路由 - 启动服务后在pages下产生一个.umi临时目录里面有router.js,umi 会根据 pages 目录自动生成路由配置

    配置式路由 - 如果使用配置可以在,config/router.config.js

    1、路由跳转: 

        import Link from 'umi/link'            // 加载link

        export default function(){
            return (
                <div>
                    <Link to="/user">跳转到用户</Link>
                </div>
            )
        }

        命令式:
            function goToListPage() {
                router.push('/list');
            }

    2、动态路由

        umi约定 带 $ 前缀的目录或文件为动态路由

        + pages/
            + $post/
                - index.js
                - comments.js
            + users/
                $id.js
            - index.js

        [
            { path: '/', component: './pages/index.js' },
            { path: '/users/:id', component: './pages/users/$id.js' },
            { path: '/:post/', component: './pages/$post/index.js' },
            { path: '/:post/comments', component: './pages/$post/comments.js' },
        ]

        注意: 动态路由切换时不会在调用componentWillMount,需要在componentDidUpdate来侦听

             state = {
                chartId: ''
            };

            componentDidUpdate(){
                const { computedMatch } = this.props;
                const { chartId } = this.state;

                if(chartId !== computedMatch.params.id){
                    this.initChartList();
                }
            }

            initChartList(){
                const { dispatch, computedMatch } = this.props;
                console.log(computedMatch.params.id)

                this.setState({
                    chartId: computedMatch.params.id
                })

                dispatch({
                    type: 'chartData/getChartsData',
                    payload: {
                        pageId: computedMatch.params.id
                    }
                });
            }


    3、路由嵌套

        配置routers

        export default {
            routes: [
                { path: '/users', component: './users/_layout',
                    routes: [
                        { path: '/users/detail', component: './users/detail' },
                        { path: '/users/:id', component: './users/id' }
                    ]
                },
            ],
        };

    4、权限

        PrivateRoute.js来渲染/list

    https://umijs.org/zh/guide/router.html#%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1


三、Mock 数据

    let agentDataList = [...]
    function getAgents(req, res) {
        const dataSource = agentDataList;
        const result = {
            list: dataSource,
            total: dataSource.length,
        };
        return res.json(result);
    }

    export default {
        'POST /api/arbitration/agent/query': getAgents,
    }

    --- 可以引入mock.js ---
    import mockjs from 'mockjs';
    export default {
        // 使用 mockjs 等三方库
        'GET /api/tags': mockjs.mock({
            'list|100': [{ name: '@city', 'value|1-100': 50, 'type|0-2': 1 }],
        }),
    };

antdPro 流程

一、app.js入口

    // 获取权限路由,也可以在这添加路由
    fetch('/api/auth_routes')
  .then(res => res.json())
  .then(ret => {
    authRoutes = ret;
    oldRender();
  });


二、login 登录接口

    request: /api/login/account
    response: {status: "ok", type: "account", currentAuthority: "admin"}


三、设置和获取权限 

    router.config.js 配置Routes每个页面都调用Authorized.js来判断权限
    {
        path: '/',
        component: '../layouts/BasicLayout',
        Routes: ['src/pages/Authorized'],                // 设置
        authority: ['admin', 'user', 'ROLE_RDDPL4WSV0'],
        routes: [
            { path: '/', redirect: '/dashboard/workplace', authority: ['admin', 'user', 'ROLE_RDDPL4WSV0'] },
        ]
    }


    utils/authority   getAuthority、setAuthority

    存储到localStrage中的antd-pro-authority


四、菜单

    modules/menu        getMenuData()获取菜单的方法

    layouts/BasicLayouts        页面布局,SiderMenu组件menuData菜单数据

    menuData格式
    [{
        "path": "/dictionary",
        "icon": "book",
        "name": "数据字典",
        "locale": "menu.dictionary",
        "authority": ["admin", "user"],
        "children": [{
            "path": "/dictionary/list",
            "name": "字典列表",
            "exact": true,
            "locale": "menu.dictionary.list"
        }, {
            "path": "/dictionary/create",
            "name": "新建字典",
            "exact": true,
            "locale": "menu.dictionary.create"
        }]
    }]

react使用typescript

1、state和props定义

    interface IProps {
        aProps: string;
        bProps: string;
    }
    interface IState {
        aState: string;
        bState: string;
    }

    class App extends React.PureComponent<IProps, IState> {
        state = {
            aState: '',
            bState: '',
        };

        render(){
            this.props.aProps;
            this.state.aState;
            return null;
        }
    }

    const mapStateToProps = () => {
        return {
            aProps: 'a',
            bProps: 'b'
        }
    }
    const mapDispatchToProps = {};
    export default connect(mapStateToProps, mapStateToProps)(App)

| https://www.jianshu.com/p/c7b3b9c98d04
| https://umijs.org/zh/plugin/umi-plugin-react.html#%E5%AE%89%E8%A3%85 // umiJS

axios

安装

$ npm i axios            // 阿西奥斯

引用 const axios = require('axios');

$ bower install axios

cdn <script src="http://unpkg.com/axios/dist/axios.min.js">

Request参数

{
    baseUrl: '/api'                    // 基础url
    url: '/databaseList',        // 请求的接口,与基础合起来为'/api/databaseList'
    method: 'get',        // 请求方式,default=get

    // 设置头部信息
    headers: {
        'Content-Type': 'Application-json',
        'X-token': '1k12hkj34j2kbjhs9df74b'},
    },

    // URL的参数,get或Content-Type='application/x-www-form-urlencoded'使用的参数,不能用data
    params: {
        ID: 12345
    },

    // data发送的主休,用于post、stream、buffer
    data: {
        username: 'sigunag',
        password: '*******'
    },

    // 超时时间
    timeout: 1000,

    // 响应类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
    responseType: 'json',

    // 响应的编码
    responseEncoding: 'utf8',

    // socket代理路径
    socketPath: null, // default

    // keepAlive 保持连接,默认不启动
    httpAgent: new http.Agent({ keepAlive: true }),
    httpsAgent: new https.Agent({ keepAlive: true }),

    // 代理主机
    proxy: {
        host: '127.0.0.1',
        port: 9000,
        auth: {
            username: 'mikeymike',
            password: 'rapunz3l'
        }
    },

    // 取消请求
    cancelToken: new CancelToken(function (cancel) {

    })

    // 一个可选的函数负责序列化“参数”
    paramsSerializer: function(params) {
        return Qs.stringify(params, {arrayFormat: 'brackets'})
    },

    transformRequest: [function (data, headers) {        // 在请求服务器之前的回调,适用于post
        return data;
    }],
    transformResponse: [function (data) {        // 在响应的回调,适用于post
        return data;
    }],
}

Response参数

{
    // 响应数据
    data: {},

    // 状态码
    status: 200,

    // http响应状态消息
    statusText: 'OK',

    // 响应头
    headers: {},

    // `config` is the config that was provided to `axios` for the request
    config: {},

    // `request` is the request that generated this response
    // It is the last ClientRequest instance in node.js (in redirects)
    // and an XMLHttpRequest instance the browser
    request: {}
}

创建实例

const axios = require('axios');


const request = axios.create({
      baseURL: '/api',     // api的base_url
        timeout: 10000,     // 请求超时时间 ms
})

/* 创建拦截器 */
// 请求拦截器
request.interceptors.request.use(
    (config) => {
        // Do something before request is sent
        return config;
    }, 
  (error) => {
        // Do something with request error
        return Promise.reject(error);
    }
);

// 响应拦截器
request.interceptors.response.use(
    (response) => {
        // Do something with response data
        return response;
    }, 
    (error) => {
        // Do something with response error
        return Promise.reject(error);
    }
);

axios.get('/user', {        
    params: {
        ID: 12345
    }
})
.then((d) => {
    // success
})
.catch((error) => {
    // error
})
.then(() => {
    //
})


一、请求参数 

    1、get或content-type="application/x-www-form-urlencoded" 使用 params来加参数

    2、post、content-type="application/json" 使用 data来传参数

axios.all 处理多个请求

就是promis.all(),多个请求全部执行成功后在执行

function getUserAccount() { return axios.get('/user/12345');     }
function getUserPermissions() { return axios.get('/user/12345/permissions'); }

axios.all([getUserAccount(), getUserPermissions()])
    .then(axios.spread(function (acct, perms) {
        // Both requests are now complete
    }));

API

一、axios(config)

    1、post请求

        axios.request('/user/12345',{
            method: 'post',
            data: {
                firstName: 'Fred',
                lastName: 'Flintstone'
            }
        });

    2、get请求

        axios.request('http://bit.ly/2mTM3nY', {
            method:'get',
            responseType:'stream'
        })
        .then(function(response) {
            response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
        });

二、创建实例

    const request = axios.create({
        baseURL: '/api',            // 基础
        timeout: 1000,                // 请求超时时间
        headers: {'X-Custom-Header': 'foobar'}
    });


{


}

axios-mock-adapter axios使用mock

https://github.com/ctimmerm/axios-mock-adapter

微信小程序、公众号开发

基础问题

一、appleID的获取

    https://mp.weixin.qq.com/wxopen/basicprofile?action=index&token=767275273&lang=zh_CN

    在开发设置选项 => AppID(小程序ID)

二、文件类型

    1、app.js 脚本文件        2、app.json 配置文件        3、app.wxml 页面结构        4、app.wxss样式文件


三、app.json全局配置

    {
        // 页面路径
        "pages": [
            "pages/index/index",            // 初始显示的组件用
            "pages/logs/index"
        ],

        // 默认页面窗口表现
        "window": {
                "backgroundTextStyle": "light",
            "navigationBarBackgroundColor": "#0E77CA",
            "navigationBarTitleText": "小程序Example",
            "navigationBarTextStyle": "#fff",
            "enablePullDownRefresh": true,
        },

        // 底部tab的表现
        "tabBar": {
            "list": [
                {
                    "pagePath": "pages/index/index",
                    "text": "首页"
                }, 
                {
                    "pagePath": "pages/logs/logs",
                    "text": "日志"
                }
            ]
        },

        // 设置网络超时时间
        "networkTimeout": {
            "request": 10000,
            "downloadFile": 10000
        },

        // 是否开启debug模式
        "debug": true,

        "workers": '',                            // 多线程代码放置的目录
        "pageOrientation": "auto",    // 是否启用屏幕旋转
        "subpackages": {},                    // 分包结构配置
        "resizable": true,                    // iPad上是否启用屏幕旋转
    }

    https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html


五、sitemap.json配置

    文件用于配置小程序及其页面是否允许被微信索引

Page() 用来注册一个页面

指定页面的初始数据、生命周期、事件处理

一、生命周期

    /** 监听页面加载 **/
    onLoad: function (options) {
        console.log(options);
    },

    /** 监听页面初次渲染完成 **/
    onReady: function () {

    },

    /** 监听页面显示 **/
    onShow: function () {

    },

    /** 监听页面隐藏 **/
    onHide: function () {

    },

    /** 监听页面卸载 **/
    onUnload: function () {

    },

    /** 页面相关事件处理函数--监听用户下拉动作 **/
    onPullDownRefresh: function (e) {
        this.setData({
            updata: JSON.stringify(e)
        })
        console.log(e)
    },

    /** 页面上拉触底事件的处理函数 **/
    onReachBottom: function (e) {
        this.setData({
            updata: JSON.stringify(e)
        })
        console.log(e)
    },

    /** 用户点击右上角分享 **/
    onShareAppMessage: function () {

    }


二、属性、方法

    data - 页面初始数据, WXML中调用 {{test}}

    onload - 监听页面加载

    onReady - 监听页面初次渲染完成

    onShow - 监听页面显示

    onHide - 监听页面隐藏

    onUnload - 监听页面卸载

    onPullDowRefesh - 监听用户下拉动作

    onReachBottom - 上拉触底事件

    onShareAppMessage - 用户点击右上角转发

        onShareAppMessage: function () {
            return {
                title: '自定义转发标题',
                path: '/page/user?id=123'
            }
        }

    onPageScroll - 页面滚动触发


三、绑定事件

    <view bindTap="viewTap">click me</view>

    Page({
        data:{
            message: 'view tap'
        },
        viewTap: () => {
            console.log(this.message);
        }
    })

五、Page.prototype.route - 获取当前页面的路径

六、Page.prototype.setData() - 用于将数据从逻辑层发送到视图层,同时改变对应的this.data的值

    Page({
        data:{
            username: 'siguang'
        }
        login: ()=>{
            this.setData({
                username: 'lulu'
            })
        }
    })

路由

所有页面的路由全部由框架管理

一、页面栈

    1、初始化 - 新页面入栈

    2、打开新页面 - 新页面入栈。  调用 API wx.navigateTo 或使用组件 <navigator open-type="navigateTo"/>

    3、页面重定向 - 当前页面出栈,新页面入栈。  调用 API wx.redirectTo 或使用组件 <navigator open-type="redirectTo"/>

    4、页面返回 - 页面不断出栈,直到目标返回页,新页面入栈。 调用 API wx.navigateBack 或使用组件<navigator open-type="navigateBack">或用户按左上角返回按钮

    5、Tab - 切换    页面全部出栈,只留下新的 Tab 页面。 调用 API wx.switchTab 或使用组件 <navigator open-type="switchTab"/> 或用户切换 Tab

    6、重加载 - 页面全部出栈,只留下新的页面。 调用 API wx.reLaunch 或使用组件 <navigator open-type="reLaunch"/>

    Example:
        bindViewTap: function() {
            wx.navigateTo({
                url: '../logs/logs'
            })
        }

二、getCurrentPages() 获取当前页面的栈的实例

三、Tips

    navigateTo, redirectTo 只能打开非 tabBar 页面。
    switchTab 只能打开 tabBar 页面。
    reLaunch 可以打开任意页面。

模块化

一、全局变量和方法

    全局方法通过 getApp()获取全局的应用实例

    全局数据设置:

        App({
            globalData: 1
        })


二、模块化

    1、exports 导出

        module.exports 或 exports对外暴露接口, exports是module.exports的一个引用

        小程序不支持直接引入node_modules, 如果需要就将代码拷到目录中

        // common.js
        function sayHello(name){
            console.log(`Hello ${name}`);
        }

        module.exports.sayHello = sayHello;


    2、require 引用

        const conmmon = require('common.js');
        Page({
            helloMina: () =>{
                common.sayHello('mina');
            }
        })

视图层

一、WXML

    1、数据绑定

        普通绑定: <view>{{message}}</view>

        属性绑定: <view id="item-{{id}}"> </view>

        控制属性: <view wx:if="{{condition}}"> </view>


    2、循环渲染

        // 注意这里取到当前数据要用item
        <view wx:for="{{arr}}">{{item}}</view>

        数组下标:
            <view wx:for="{{arr}}">
                序号:{{index}} 姓名:{{item.name}} 年龄:{{item.age}} 
            </view>

            两者相同
            <view wx:for="{{arr}}" wx:for-index="idx" wx:for-item="itemName">
                姓名:{{itemName.name}} 年龄:{{itemName.age}} 序号:{{idx}}
            </view>


    3、条件渲染

        <view wx:if="{{view == 'webView'}}">web view</view>
        <view wx:elif="{{view == 'app'}}">app</view>
        <view wx:else="{{view == 'mina'}}">mina</view>

        Page({
            data: {
                view: 'app'
            }
        })


    4、模板

        name: 模板名    is: 所要调用的模板名    data: 传入的数据

        <template name="staffName">
            <view>
                FirstName: {{firstName}}, lastName: {{lastName}}
            </view>
        </template>

        <template is="staffName" data="{{...staffA}}"></template>
        <template is="staffName" data="{{...staffB}}"></template>

        Page({
            data: {
                staffName: {fristName: 'sigunag', lastName: 'haha'},
                staffName: {fristName: 'yuwan', lastName: 'lulu'},
            }
        })

WXSS 样式语言

尺寸单位: rex, 可以根据屏幕宽度自行自适应

一、样式导入

    @import 'common.wxss'
    .middle-p {
        padding: 15px;
    }


二、内联样式

    data: {
        color: '#ddd'
    }
    <view style="color: {{color}}">

    <view class="middle-p">        // 多个class使用空格分隔


三、全局、局部样式

    定义在app.wxss中的样式为全局, 每个页的wxss为局部样式


四、选择器

    .class, #id, element, element, element, ::after, ::before

WXS 脚本

小程序自己的一套脚本语言, 可以直接编写到WXML中, 也可以单独写成一个.wxs文件

一、写到wxml中

    <!-- index.wxml>
    <wxs module="m1">
        var msg = 'hello world';
        module.exports.message = msg
    </wxs>

    <view>
        {{m1.message}}
    </view>


二、写成一个.wxs文件

    // pages/comm.wxs
    // 如果comm.wxs文件中要引用其它的wxs文件使用require,  var tool = require('./tools.wxs');

    var foo = "'hello world' from comm.wxs";
    var bar = function(d) {
        return d;
    }
    module.exports = {
        foo: foo,
        bar: bar
    };

    // 页面引用
    <wxs src="./../tools.wxs" module="tools" />
    <view> {{tools.msg}} </view>

事件

<view bindtap="add">{{count}}</view>

Page({
    data: {
        count: 1
    },
    add: (event)=>{
        this.setData({
            count: this.data.count++
        })
    }
})

一、事件分类

    分为冒泡事件和非冒泡事件

    冒泡事件:  bindtouchstart 前面加bind

        touchstart    手指触摸动作开始    
        touchmove    手指触摸后移动    
        touchcancel    手指触摸动作被打断,如来电提醒,弹窗    
        touchend    手指触摸动作结束    
        tap    手指触摸后马上离开    
        longpress    手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发    1.5.0
        longtap    手指触摸后,超过350ms再离开(推荐使用longpress事件代替)    
        transitionend    会在 WXSS transition 或 wx.createAnimation 动画结束后触发    
        animationstart    会在一个 WXSS animation 动画开始时触发    
        animationiteration    会在一个 WXSS animation 一次迭代结束时触发    
        animationend    会在一个 WXSS animation 动画完成时触发

    事件绑定和冒泡:

        bind 不会阻止冒泡事件向上冒泡,bindtap
        catch 可以阻止冒泡事件向上冒泡。catchtap

    事件捕获:

        捕获阶段监听事件时,采用capture-bind、capture-catch关键字, 后者将中断捕获阶段和取消冒泡

    事件对象:

        baseEvent对象


二、view、block标签

    view 渲染单独一行类似块元素

    block 渲染成内联元素

引用

提供两种引用方法import 和 include

一、import 引用外部的<template>模板

    <!-- item.wxml -->
    <template name="item">
        <text>{{text}}</text>
    </template>

    <!--  index.wxml  -->
    <import src="item.wxml"/>
    <template is="item" data="{{text: 'forbar'}}"/>


二、include 引用非<template>模板的文件,公用的头尾等

    <!-- index.wxml -->
    <include src="header.wxml"/>
    <view> body </view>
    <include src="footer.wxml"/>

    <!-- header.wxml -->
    <view> header </view>

    <!-- footer.wxml -->
    <view> footer </view>

运行机制

小程序两种启动方式:

    冷启动: 用户首次打开或小程序被微信主动销毁后在次打开的情况,

    热启动: 用户已经打开某个小程序,在一定时间内在次打开,此时无需重新启动,只需将后台切换到前台

开发总结

1、小程序初始指定页面

    app.json中, 调整pages数组的顺序, 第一个就是最先被载入

    "pages":[
        "pages/my/my",
        "pages/index/index",
        "pages/logs/logs"    
    ]

2、当前页面使用修改标题

    在当前页面下的.json文件中加入

    goods-details.json
    {
        "navigationBarTitleText": "商品详情"
    }

3、获取元素上的自定义属性值

    1) evt.currentTarget.dataset.propertyindex;        

    2) evt.detail

    <view bindtap="labelItemTap" data-propertyindex="{{idx}}"></view>        // 注意这里自定义属性需要以"data-"开头,并且不能为大写,如果有大写取值时全部为小写

    js:

    labelItemTap: function(evt){
        let val = evt.currentTarget.dataset.propertyindex;
    }

4、在app.json中配置pages的路径会自动创建目录和基本文件这里

    这里注意创建js时候会将生命周期方法和上拉下拉刷新方法全部都创建好,不必重写 onPullDownRefresh()、onReachBottom();

问题

如果修改 checkbox 的样式

时间选择器只有时、分,没有秒

slider滑动组件拖动块不能改颜色

小程序下拉刷新不触发 onPullDownRefresh

小程序与RN相比

小程序布局写法简单,RN的布局比较麻烦

小程序的组件简单,RN组件麻烦,并且IOS和Android兼容

RN可以随意发起网络请求访问数据,小程序需要指定服务器并且需要https协议

RN需要与通过Xcode来进去打包、并且需要在appStor进行发布审核

RN做的app需要到商店下载使用,小程序发布后在微信就可以找到

API

1、getApp() 取App实例, 下面可以设置globalData来设置全局数据

    const app = getApp();
    app.globalData.userInfo;        // 获取当前用户信息

2、getCurrentPages(): 数组中第一个元素为首页,最后一个元素为当前页面

setTimeout、setInterval定时器


一、网络

    1、wx.request: 网络请求

        wx.request({
    url:url,
    data:data,
    header:{
        "Content-Type":"application/json"
    },
    success:function(res){
                console.log(res.data)
    },
    fail:function(err){
                console.log(err)
    }
    })

    2、wx.uploadFile: 上传文件

    3、wx.downloadFile: 下载文件

    4、wx.webSocket: 都需要设置指定的服务器

    app.json中通过networktimeout配置超时时间


二、存储

    1、wx.setStorage/wx.setStorageSync: 存储到Storage上

    2、wx.getStorage/wx.getStorageSync: 获取Storage的数据

    3、wx.clearStorage/wx.clearStorageSync: 清除

    4、wx.removeStorage/wx.removeStorageSync: 删除某一个


三、文件系统

    const fs = wx.getFileSystemManager()


四、多线程Worker

    app.json中配置 { "workers": "workers" }

    Worker.postMessage() 来发送数据

    Worker.onMessage() 来接收数据


五、服务端

    getAccessToken: 获取access_token,是小程序全局唯一后台接口调用凭据

    code2Session


六、硬件

    1、wx.openBluetoothAdapter: 打开蓝牙

    2、wx.closeBluetoothAdapter: 关闭蓝牙 或小程序被销毁为止


七、消息




wx.getSystemInfo 或者 wx.getSystemInfoSync 获取小程序的基本库版本

wx.canIUse 判断是否可以在该基础库版本下直接使用对应的API或者组件

####

一、input的双向绑定

    <input placeholder="这是一个可以自动聚焦的input" class="inp" bindinput="inpValue" />

    {

        inpValue(e){

        }
    }

| http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html // 公众服务平台所有的sdk
| https://mp.weixin.qq.com/debug/wxadoc/introduction/index.html?t=20171013 // 小程序
| https://www.w3cschool.cn/weixinapp/9wou1q8j.html
| http://203.195.235.76/jssdk/ 小程序demo
| https://github.com/gooking/awesome-wechat-weapp 微信小程序开发资源汇总

numjucks模板

numjucks

numjucks可以用任意扩展名来命名模板名文件,推荐使用'.njk'

$ npm install nunjucks

require('nunjucks');

变量

{{ usernmae }}    {{ foo.bar }}

过滤器

{{ foo | title }}    {{ foo | join(',') }}

模板继承

定义一个"block",子模板可以覆盖它

一、Example

    A.html

        {% block header %}{% endblock %}

			
aaaa
B.html {% extends 'A.html' %} {% block header %}
  • aaaa
  • bbbb
  • cccc
{% endblock %} 二、super()

if

{% if num > 20 %}
		
大于20显示些内容
{% endif %} {% if num > 20 %} 大于20 {% elif num < 6 %} 小于6 {% else %} 其它 {% endif %}

for

一、遍历数组

    var items = [{ title: "foo", id: 1 }, { title: "bar", id: 2}];

    <h1>标题</h1>
    <ul>
        {% for item in items %}
				
  • {{item.title}}
  • {% endfor %} </ul> 二、遍历对象 var food = { 'ketchup': '5 tbsp', 'mustard': '1 tbsp', 'pickle': '0 tbsp' }; <div> {% for key, value in food %}

    {{key}} - {{value}}

    {% endfor %} </div>

    set 设置和修改变量

    let username = 'siguang';
    
    {{ username }}            // siguang
    {% set username = 'lulu' %}
    {{ username }}            // lulu
    

    extends 指定模板继承

    {% extends 'A.html' %}
    
    {% block header %}
    		
    • aaaa
    • bbbb
    • cccc
    {% endblock %}

    block 区块

    {% block css %}
    		
    	{% endblock %}
    

    include 可以引用的模板

    {% include "item.html" %}
    

    import 加载不同的模板

    filter 区块中内容调用过滤器

    {% filter replace("force", "forth") %}
    		may the force be with you
    	{% endfilter %}
    

    注释

    去除前后空格

    var str = ' sssfsdfs ';
    
    {% -%}
    

    运算符

    表达式 String、Number、Array、Dicts、Boolean
    
    运算符 +、-、/、//、%、*、**
    
    比较 ==、===、!=、!==、>、>=、<、<=
    
    逻辑 and、or、not   {% if users and showUsers %} ... {% endif %}
    

    函数

    传入一个函数,在这里可以执行 {{ foo(1,2,3) }}
    

    表达式

    {{ /bar$/g }}
    
    g: 应用到全局
    i: 不区分大小写
    m: 多行模式
    y: 粘性支持(sticky
    

    参考资料
    http://mozilla.github.io/nunjucks/cn/templating.html

    Jade 模板

    jade介绍、安装

    jade是前后端都可以使用的模板引擎7
    
    1、安装:
    
        sudo npm i -g jade
    
    
    2、介绍
    
        元素标签不需要写<>
    
        子元素与父元素需要换行并tab缩进
    
        标签与文本需要使用空格来隔开
    
    
    3、jade的缺点
    
        1)可移植性差
    
        2)调试困难
    
        3)性能一般
    
    4、初始阶段开发效率,稳定性成和协作的成本
    

    jade 头尾标签

    <!DOCTYPE>
    html
        head
            title ${title}
    
        body
            h1 标题内容
    

    命令行编译jade文件

    # jade index.jade         // 会将jade文件编译成同级目录的index.html文件,并且是没有代码格式的只有一行
    
    # jade -P index.jade     // 有缩进,可读的格式
    
    # jade -P -w index.jade // 侦听jade文件有变化执行转换的命令
    
    小技巧: 在sublime中打开 index.jade 和 index.html文件, 选择view菜单 -> layout/ columns2 变成两列,将index.html放到另一列中,这样每次保存就可以看到html代码
    

    属性文本和值

    1、class和id
    
        div.row
    
        div#row
    
        div#row.column-samil    // id="row" class="column-samil"
    
        div.rowA.main        // class="rowA main"
    
    
    2、属性
    
        a标签的href属性值,和自定义属性和值
        a(href="http://haha.com",
            title="jade",
                data-uid="siguang")
    
        input(name="course" type="check" checked)
    

    混合的文本和标签

    1、如果字符里有点进行处理
    
        // 不会把.aa解析成 class="aa" 并且换行,也能写html标签
        div.row
            p.
                1.aa <strong>这里字体加粗</string>
                2.bb
                3.cc 
                4.dd
    
        或者
        div.row
            p
                | 1.aa 
                | 2.bb
                | 3.cc 
                | 4.dd
    

    注释和条件注释

    1、单行注释 //
    
    2、不可见的注释 //-
    
    3、块注释        //- 在当前节点的开头
    
    4、条件注释
    
        <!--[if IE 8]>
            <html class='ie8'>
        <![endif]>
    
    
        </html>        // 需要html
    
    
    
    div.row
        // a(href="http://haha.com", title="siguang", data-index="1") 去主站
    
        //- input(name="course" type="check" checked)
    
    div.row
    //-
        p.
            1.aa <strong>这里字体加粗</string>
            2.bb
            3.cc 
            4.dd
    

    变量声明

    声明: - var course = 'jade'
    
    获取: #{jade}
    
    1、命令行下传值
        jade index.jade -P -w --obj '{"name":"siguang", age: 30}'
    
        div.row
            div.column-12
                姓名: #{name}
    
            div.column-12
                年龄: #{age}
    
    2、通过json传值
    
        jade index.jade -P -O test.json
    
        test.json
        {
            'name': 'siguang',
            'age': 30
        }
    

    转义

    1、将html转成字符串输出
    
        - var data = '<script>alert(123)</script>'
    
        p #{data}
    
    
    2、非转义
    
        - var data = '<script>alert(123)</script>'
    
        p !{data}
    

    流程

    1、if...else...
    
        - var isData = true
        if isData
            div 对象存在
        else
            对象不存在
    
    
    2、case
    
        - var name = 'jade'
        case name
            when 'java'
                div java
    
            when 'jade'
                p hello jad
    
    
    
    3、for 或 each 循环
    
        - var data = {'name': 'siguang', 'nage': 30}
        div.row
            - for(var key in data)
                div= key +'='+data[key]
    
        each()
    

    mixin

    相同结构的内容可以放到mixin中,相同一个函数
    
    1、无参
        mixin 函数名        // 声明 
            p 这里是函数的块内容
            p 这里是函数的块内容
            p 这里是函数的块内容
    
        +函数名            // 调用
    
    2、有参
    
        mixin 函数名(参数)
            each key in data
                li= data[key]
    
        +函数名({username: 'siguang', age: 30});
    

    模板继承

    代码复用
    
    定义一个html的基本结构,内容只写到body中
    
    public.jade
    
        DOCTYPE html
        html
            head
    
            body
                block desc
                    p 内容继承
                block content    // 这里接收内容
    
    
    main.jade
    
        // 通过extends继承到哪个 jade文件
        extends public
    
        block content        // 这里写到哪里
            div.row
                p aaaa
                p aaaa
                p aaaa
    
            div.row-b
                p bbb
                p bbb
                p bbb
    

    include 引用

    引用一个jade文件
    
    DOCTYPE html
    html
        head
            include head
    
        body
            include login
    

    jade api

    http的原声写法
    
    1、jade.compile(source, 传值): 返回一个函数来生成html
    
    2、jade.compileFile(path, 传值)
    
    3、jade.compileClient(source, 传值)
    
    4、jade.render(source, 传值):
    
    5、jade.renderFile(jade文件, 传值):
    
    
    compile()示例
        var http = require('http');
        var jade = require('jade');
    
        var server = http.createServer(function(req, res){
            res.writeHead(200, {'ContentType': 'text/html'});
    
            var fn = jade.compile('div #{course}', {});
            var html = fn({course: 'jade'});
    
            res.end(html);
        })
    
        server.listen('8081', 'localhost')
    
    
    render()示例
    
        var http = require('http');
        var jade = require('jade');
    
        var server = http.createServer(function(req, res){
            res.writeHead(200, {'ContentType': 'text/html'});
            var html = jade.render('div #{course} #{name}', {course: 'jade', name: 'siguang'});
            res.end(html);
        })
    
        server.listen('8081', 'localhost')
    
    
    {pretty:true} 如果不加此属性html会是压缩模式,加上格式化的代码
    

    将html编译成jade文件

    安装: sudo npm install html2jade -g
    
    生成命令: html2jade ./public/index.html > index.jade
    
    在node中转换
    
    var html2jade = require('html2jade');
    
    html2jade.convertDocument(document, {}, function(err, jade){
        console.log('反编译后的jade文件')
    })
    
    
    在线转换: http://html2jade.vida.io/
    

    | 参考资料
    | http://www.cnblogs.com/fullhouse/archive/2011/07/18/2109945.html
    |
    |

    Rap的使用和mock数据

    /** Rap */

    Rap

    阿里的产品和mockjs,来模拟真实数据
    
    https://github.com/thx/RAP/wiki/user_manual_cn#%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE
    

    Rap使用

    一、注册和登录Rap
    
        http://rapapi.org/
    
    二、分为团队、业务线、项目
    
        1、查找你所在的团队
    

    查找你所在的团队

    2、进入你所在的团
    

    查找你所在的团队

    3、创建业务
    

    查找你所在的团队

    4、创建模块和使用
    

    查找你所在的团队

    三、其它技巧
    
        1、将一个接口的字段下所有字段copy到另一个接口
    
            选择要copy的字段名,到另一个接口粘贴后在control+Enter,就将所有的内容全部copy过来
    

    查找你所在的团队

    四、MOCK工具
    
        1、使用参数的变量
            请求字段
                page   
    
            响应字段
                pageResponse 字段  @mock=${page}        // 这里最终pageResponse的显示就是Request中page的输入
    
                或者写默认值   @mock=${page=100}    // 如果请求不写page值默认为100
    
        2、id自动加1
    
            变量名     备注
            id|+1     @mock=100        // 表示id从100开始,每次加1
    
        3、其它写法
    
            @mock=@DATE
    
            @mock=true
    
            @mock=function(){return 100 + Math.random()*100}
    

    查找你所在的团队

    Rap的使用和mock数据

    Mock.js

    Mock拦截Ajax请求,
    
    一、安装、使用
    
        $ npm i mockjs --save
    
        import Mock from 'mockjs';
        var data = Mock.mock({
            // 属性 list 的值是一个数组,其中含有 1 到 10 个元素
            'list|1-10': [{                
                'id|+1': 1                            // 属性 id 是一个自增数,起始值为 1,每次增 1
            }]
        })
        // 输出结果
        console.log(JSON.stringify(data, null, 4))
    
    
    二、Mock.js提供4个方法方法和一个工具库
    
        1、方法
    
            Mock.mock(url, type, { 响应值 }) - 设置拦截请求、返回响应结果
    
            Mock.setup({                // 设置响应时间
                timeout: 400
            })
    
            Mock.valid()
    
            Mock.toJSONSchema()
    
        2、工具库
    
            Mock.Random
    
    
    三、工具库
    
        const Mock = require('mockjs)
        const Random = Mock.Random;            // 先获取Random对象
    
        1、Random.boolean();        // true 生成出一个布尔值
    
        2、Random.natural();        // 8518407945788098
    
            Random.natural(60, 100);        // 生成出一个自然数60-100之间
    
        3、Random.integer(min, max);        // 7546601449898424
    
        4、Random.float();            // 1479142551150828.5
    
        5、Random.character()        // "E"
    
        6、Random.string(count)    // 随机一个字符串
    
        7、Random.range(10)            // [0,1,2,3,4,5,6,7,8,9]
    
        8、Random.date()                // "2005-09-28"
    
        9、Random.time()                // "00:43:01"
    
        10、Random.datetime()
    
        11、Random.now()                // "2019-02-01 10:38:56"
    
        12、Random.image('200x100', color, 'text')            // 生成一个宽200高100的图片占位
    
        13、Random.dataImage('200x100', 'Hello Mock.js!')
    
        14、Random.color()            // 生成一个颜色 "#f2a079"
    
        15、Random.rgb()                // "rgb(190, 121, 242)"
    
        16、Random.rgba()                // "rgba(121, 157, 242, 0.37)"
    
        17、Random.paragraph()    // 生成内容
    
        18、Random.url()
    
        19、Random.email()            // email
    
        20、Random.ip()                    // 随机ip
    
        21、Random.province()        // 随机省会名'黑龙江'
    
        22、Random.city()                // 随机城市名'哈尔滨'
    
        23、Random.county()            // 随机区名'南岗'
    
        24、Random.capitalize('hello')            // 首字母大写 'Hello'
    
        25、Random.upper( str )、Random.lower( str )        // 转换大小写
    
        26、Random.pick(['a', 'e', 'i', 'o', 'u'])            // "u" 随机一个
    
        27、Random.shuffle(['a', 'e', 'i', 'o', 'u'])        // 洗牌 ["a","i","o","e","u"]
    
        28、Random.id()    // "320000200603050615"
    
        29、Random.guid()                // "CbdCfC92-9cb6-7ebb-1a7c-e28AbCD0fd04"
    
        上面所有方法都可以写成@占位符的方式
    
        data: {
      boolean: Random.boolean()
    }
    
        data: {
      boolean: '@boolean'
    }
        这两个都相同,具体参考     http://mockjs.com/examples.html#Array
    
    
    四、语法
    
        'name|rule': value
    
        生成规则 有 7 种格式:
    
            'name|min-max': 'abc'                        // min-max 生成一个字符串,重复次数大于min,小于max
    
            'name|count': value
    
            'name|min-max.dmin-dmax': value
    
            'name|min-max.dcount': value
    
            'name|count.dmin-dmax': value
    
            'name|count.dcount': value
    
            'name|+step': value
    
    
    五、示例
    
         1、属性值是字符串String
    
            'name|min-max': 'ab'        // 重复 'ab' 字符串,重复次数大于等于 min,小于等于 max。  { name: 'abababab'}
            'name|count': 'ab'             // 重复 'ab' 字符串,重复次数等于 count
    
    
        2、属性值是数值Number
    
            'name|+1': 100                     // 初始值自动加1,返回101
            'name|1-100': 100             // 生成一个大于等于 1、小于等于 100 的整数,属性值 100 只用来确定类型。
            'name|1-100.1-10': 100     // 生成一个浮点数,整数部分大于等于 1、小于等于 100,小数部分保留 1 到 10 位。
    
    
        3、属性值是布尔Boolean
    
            'name|1': true                 // 返回true或false
            'name|min-max': true     // 随机生成一个布尔值,值为 value 的概率是 min / (min + max),值为 !value 的概率是 max / (min + max)。
    
    
        4、属性值是对象Object
    
            'name|min-max': {        // 从属性值 {} 中随机选取 min 到 max 个属性。
                "310000": "上海市",
                "320000": "江苏省",
                "330000": "浙江省",
                "340000": "安徽省"
            }         
            'name|count': {}             // 随机出对象中个数的对象属性
    
    
        5、属性值是数组 Array
    
            'name|1': [{}, {} ...]                 // 从属性值 [{}, {} ...] 中随机选取 1 个元素,作为最终值。
            'name|min-max': [{}, {} ...]     // 重复属性值 [{}, {} ...] 生成一个新数组,重复次数大于等于 min,小于等于 max。
            'name|count': [{}, {} ...]         // 重复属性值 [{}, {} ...] 生成一个新数组,重复次数为 count。
    
    
        6、属性值是函数function
    
            Mock.mock({
                'foo': 'Syntax Demo',
                'name': function() {
                    return this.foo
                }
            })
    
            // 返回
            {
                "foo": "Syntax Demo",
                "name": "Syntax Demo"
            }
    
    
        7、属性值为RegExp
    
            Mock.mock({                
                'regexp': /[a-z][A-Z][0-9]/                // { "regexp": "sW7" }
            })
    
    
        8、Path 通过 @key来找到指定的值
    
            Mock.mock({
                "foo": "Hello",
                "nested": {
                    "a": {
                        "b": {
                            "c": "Mock.js"
                        }
                    }
                },
                "absolutePath": "@/foo @/nested/a/b/c"            // 这里输出 "absolutePath": "Hello Mock.js"
            })
    
    
    六、Vue框架中使用Mcok.js
    
        mockData.js 定义mock接口和响应数据
    
            import Mock from 'mockjs'
            const Random = Mock.Random;    
    
            Mock.mock('/api/login', 'post', {
                data: {
                    'username|1': Random.cfirst() + Random.clast(),
                    'toKen': Random.id()
                },
                message: 'ok',
                status: '000000'
            })
    
        request.js    请求类
    
            import axios from 'axios'
            import {MessageBox, Notification, Loading} from 'element-ui'
    
            // 创建axios实例
            const request = axios.create({
                baseURL: '/api', // api的base_url
                timeout: 20000, // 请求超时时间 ms
            })
    
            // request 拦截器,在每个请求之前执行
            request.interceptors.request.use(config => {
                return config
            }, error => {    
                console.error(error)
                return Promise.reject(error)
            })
    
            // response 拦截器,在每个请求返回之后执行
            request.interceptors.response.use(
                response => {
                    const res = response.data;
                    return res;
                },
                error => {
                    Notification.error({
                        title: '错误',
                        message: error.message,
                        duration: 10000
                    })
                    return Promise.reject(error)
                }
            )
            export default request
    
        main.js
    
            import mockData from '@/utils/mockData'
    
        login.vue
    
            request({
                url: '/login',
                method: 'post',
            }).then(od => {
                that.$notify.success({
                    title: '成功',
                    message: od.message
                });
                that.$router.push('/main')
            })
    

    Rap

    阿里的产品和mockjs,来模拟真实数据
    
    https://github.com/thx/RAP/wiki/user_manual_cn#%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE
    

    Rap使用

    一、注册和登录Rap
    
        http://rapapi.org/
    
    二、分为团队、业务线、项目
    
        1、查找你所在的团队
    

    查找你所在的团队

    2、进入你所在的团
    

    查找你所在的团队

    3、创建业务
    

    查找你所在的团队

    4、创建模块和使用
    

    查找你所在的团队

    三、其它技巧
    
        1、将一个接口的字段下所有字段copy到另一个接口
    
            选择要copy的字段名,到另一个接口粘贴后在control+Enter,就将所有的内容全部copy过来
    

    查找你所在的团队

    四、MOCK工具
    
        1、使用参数的变量
            请求字段
                page   
    
            响应字段
                pageResponse 字段  @mock=${page}        // 这里最终pageResponse的显示就是Request中page的输入
    
                或者写默认值   @mock=${page=100}    // 如果请求不写page值默认为100
    
        2、id自动加1
    
            变量名     备注
            id|+1     @mock=100        // 表示id从100开始,每次加1
    
        3、其它写法
    
            @mock=@DATE
    
            @mock=true
    
            @mock=function(){return 100 + Math.random()*100}
    

    查找你所在的团队

    | http://mockjs.com/examples.html

    Jenkins

    Jankins

    Jankins是自动化测试的一键部署工具
    
    服务器: Linux、CentOS
    
    数据库 - MySQL Server      github 账户    java开发工具 Intellij Idea
    

    jenkins安装

    jenkins.io 官网
    
    1、download Generic Java package (.war)
    
    2、命令行中找到 下载的文件Jenkins.war
    
    3、$ java -jar jenkins.war        // 安装
    
    4、http://localhost:8080        // 解锁通过给出的服务器文件路径 
    
        1)$ vim /Users/apple/.jenkins/secrets/initialAdminPassword        // 路径不同注意取到密码 添加到管理员密码中
    
        2)创建admin账户
    
        3)配置Jenkins URL http://localhost:7890/
    
    5、安装完成
    
    6、插件安装
    

    前端算法

    排序算法

    一、冒泡法
    
        前后两个值相比
    
        function bubble(){
            var arr = [34,5,7,2,4,6,8];
            var len = arr.length;
    
            for(var i=0; i<len; i++){
                // 这里 j<len-1 也可以,但j<len-1-i的目换是不用在去比较之前的结果 
                for(var j=0; j<len-1-i; j++){   
                    if(arr[j] > arr[j+1]){        // 从小向大, 如果从大到小改成 <
                        var temp = arr[j+1];
                        arr[j+1] = arr[j];
                        arr[j] = temp;
                    }
                }
            }
            return arr;
        }
        console.log(bubble());
    

    冒泡

    二、选择排序
    
        用当前的所在的数来与之后所有的数来判断找出最小数插入
    
        function selectionSort(){
            var arr = [34,5,7,26,8,13];
            var len = arr.length;
            var minIndex, temp;
    
            for(var i=0; i<len; i++){
                minIndex = i;               // 循环进来后先指向当前第一个要比较的数,下面循环会将比较小最值的下标赋给它
    
                // 找出之后的最小数
                for(var j=i+1; j<len; j++){
                    if(arr[j] < arr[minIndex]){     // 这里控制排序
                        minIndex = j;
                    }
                }
    
                // 将最小数排到当前i的位置
                temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
    
            return arr;
        }
        console.log(selectionSort());
    

    选择排序

    三、插入排序
    
        将一个值与之前的值进行比较如果大于当前值就插入在当前位置
    
        function insertionSort(){
            var arr = [34,5,7,26,8,13];
            var len = arr.length;
            var preIndex, current;
    
            for(var i=1; i<len; i++){
                preIndex = i-1;
                current = arr[i];   // 存储当前值
    
            while(preIndex >= 0 && arr[preIndex] > current){
                console.log(arr[preIndex], current);
                arr[preIndex+1] = arr[preIndex];        // 将
                preIndex--;
            }
    
                arr[preIndex+1] = current;
            }
    
            return arr
        }
    
        console.log(insertionSort());
    

    插入排序

    快速排序 
    

    选择排序
    选择排序

    | https://wowphp.com/post/komxdx8qe862.html // 排序