react知识点

2019-08-06  本文已影响0人  栗子daisy

state-setState

对象方式(对象合并方式 object.assigin())、函数方式 ( 队列 )

  1. 如何修改状态:不能用 this.state, 用 setState(setState 是异步批量执行的,如果
    同时操作多个 setState 一起执行效率高)
  2. setState 后如何获得更新的 state: 回调或钩子函数 componentDidUpdate 中
  3. 如何操作之前的 state:不建议从 this.state 里面获取 , 用函数方式更新 state 。
// 回调
this.setState({}, function() {
  // 回调中可以拿到state更新后的值
});
componentDidUpdate(){
  // 钩子函数可以获取state更新后的值
}
// 操作之前的state--实现每次加2
this.setState((prevState, props) => ({
  // prevState可以拿到上一次更新后的state
  count: prevState.count + 1
}));
this.setState((prevState, props) => ({
  count: prevState.count + 1
}));

组件两种形态

class function

生命周期 16.0

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class Home extends Component {
  constructor(props) {
    super(props);
    this.state = {
      msg: props.prop
    };
    console.log('0 constructor');
  }

  componentWillMount() {
    // 组件将要挂载:可以访问属性和状态,进行api调用,但没办法进行dom操作
    console.log('1 componentWillMount组件将要挂载');
  }

  componentDidMount() {
    // 组件已经挂载,可进行状态更新操作
    console.log('2 componentDidMount组件已经挂载');
  }

  componentWillReceiveProps(nextProps) {
    // 组件属性更新:父组件传递的属性有变化
    console.log('3 componentWillReceiveProps组件属性更新');
    this.setState({
      msg: nextProps.prop
    });
  }

  shouldComponentUpdate(nextProps, nextState) {
    // 组件是否需要更新,返回布尔值
    console.log('4 shouldComponentUpdate组件是否需要更新');
    return false;
  }

  componentWillUpdate(nextProps, nextState) {
    // 组件将要更新
    console.log('5 componentWillUpdate组件将要更新');
  }

  componentDidUpdate(prevProps, prevState) {
    // 组件已经更新
    console.log('6 componentDidUpdate组件已经更新');
  }

  componentWillUnmount() {
    // 组件已经移除
    console.log('7 componentWillUnmount组件已经移除');
  }

  render() {
    console.log('render 组件渲染了');
    return (
      <div>
        state:{this.state.msg}
        props:{this.props.prop}
      </div>
    );
  }
}

Home.propTypes = {};

export default Home;

<Home prop={this.state.name} />;

onClick 传参 onClick={this.handleClick(child)}错误,自动执行
onClick={this.handleClick.bind(this,child)}或者
onClick={()=>this.addtocart(child)}

npm install react-router-dom The prop history is marked as required in
Router, but its value is undefined.

npm install redux react-redux

组件交互

组件化

function Kai(props) {
  return (
    <div>
      {props.stage}-{props.name}
    </div>
  );
}
// 高阶组件
const withName = Comp => {
  // 假设通过特殊手段获取名称
  return props => <Comp {...props} name="aaa" />;
};
export default withName(Kai);
// 添加装饰器能力
config = injectBabelPlugin(
  ['@babel/plugin-proposal-decorators', { legacy: true }],
  config
);

npm install antd

import Button from 'antd/lib/button';
import 'antd/dist/antd.css';

配置按需加载

// 具名导入
import { Button } from 'antd';

npm install react-app-rewired@2.0.2-next.0 babel-plugin-import --save

启动项目:

// package.json
 "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test --env=jsdom",
    "eject": "react-app-rewired eject"
  }
// config-overrides.js
const { injectBabelPlugin } = require('react-app-rewired');
module.exports = function override(config, env) {
  // 按需加载
  config = injectBabelPlugin(
    ['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }],
    config
  );
  return config;
};

children

children 是任意合法的 js 表达式,包括函数

const api = {
  getUser: () => ({ name: 'jerry', age: 20 })
};
function Fetcher(props) {
  //props:{name: "getUser", children: ƒ}
  let user = api[props.name](); //user:{name: "jerry", age: 20}
  return props.children(user);
}

<Fetcher name="getUser">
  {({ name, age }) => (
    <p>
      {name}-{age}
    </p>
  )}
</Fetcher>;
function FilterP(props) {
  return (
    <div>
      {/* React.Children提供若干操作嵌套内容的帮助方法 */}
      {/* props.children处理的数组本身 */}
      {React.Children.map(props.children, child => {
        console.log('child', child); //vdom
        if (child.type != 'p') {
          //过滤非p标签
          return;
        }
        return child;
      })}
    </div>
  );
}
<FilterP>
  <a>aaaaaaaaaaaaa</a>
  <p>ppppppppppp11111111111</p>
  <h5>h5555555555</h5>
  <p>ppppppppppppp55555555555555</p>
  <div>dsffdivvv</div>
</FilterP>;
// child {$$typeof: Symbol(react.element), type: "a",...}
function RadioGroup(props) {
  return (
    <div>
      {/* {
          //  Cannot add property name, object is not extensible对象不可扩展
        React.Children.forEach(props.children,child=>{
          child.props.name=props.name;
        })
      } */}
        {/* // 扩展后返回新的 */}
      {React.Children.map(props.children, child => {
        return React.cloneElement(child, { name: props.name });
      })}
    </div>
  );
}
function Radio({ children, ...rest }) {
  return (
    <label>
      <input type="radio" {...rest} />
      {children}
    </label>
  );
}

 {/* 编辑children */}
<RadioGroup name="mvvm">
  <Radio value="vue">vue</Radio>
  <Radio value="react">react</Radio>
  <Radio value="angular">angular</Radio>
</RadioGroup>
// <label><input type="radio" name="mvvm" value="vue">vue</label>

jsx原理

1.webpack+babel-loader 打包检测到jsx => React.createElement(...)

  1. React.createElement(...)执行结束会得到一个js对象树,能完整描述dom结构,称为虚拟DOM
  2. ReactDom.render(vdom,container)将vdom转换成dom追加到container中
    通过遍历vdom树
    kvdom转换dom

虚拟dom

bug

无法正常显示

var arr=["a","b","c"]
arr.includes("a") //true
var arr2=[{name:'aa',age:20},{name:'bb',age:30}]
arr2.every(person=>person.age===20)
//false
arr2.find(person=>{return person.age===20})
//{name: "aa", age: 20}
arr2.some(person=>{return person.age===20})
//true

持久化

react

jsx redux RN React-Server

npm install react

npm install babel-core babel-preset-env babel-preset-react babel-loader
babel-preset-stage-0 --save-dev 注意版本一致

{
  test: /\.jsx?$/,
  // test: /\.(js|jsx)$/,
  exclude: '/node_modules',
  include: src,
  use: ['babel-loader?cacheDirectory'],
}
.babelrc
{
  "presets": ["react", ["env", { "modules": false }]],
  "plugins": ["syntax-dynamic-import"]
}

happypack

npm isntall happypack

 module: {
    //模块:放loader/插件
    rules: [
      {
        test: /\.jsx?$/,
        exclude: '/node_modules',
        use: 'happypack/loader?id=babel'
      }],
  },
  plugins: [
  new HtmlWebpackPlugin({
    new HappyPack({
      id: 'babel', // 上面loader?后面指定的id
      threadPool: happyThreadPool,
      use: ['babel-loader?cacheDirectory'],
      verbose: true
    })
  ],
import React from 'react';
import ReactDOM from 'react-dom';
function loadIndex() {
  ReactDOM.render(<h1>hello world</h1>, document.getElementById('app'));
}
loadIndex();

"scripts": {
  "build": "webpack --config build/webpack.pro.config.js"
},

uglifyjs-webpack-plugin

const UglifyESPlugin = require('uglifyjs-webpack-plugin');
plugins: [
  new UglifyESPlugin({
    uglifyOptions: {
      compress: {
        warnings: false,
        drop_console: true,
        collapse_vars: true,
        reduce_vars: true
      },
      output: {
        beautify: false,
        comments: false
      }
    }
  })
];

tree shaking

按需加载

window.document.getElementById('btn').addEventListener('click', function() {
  import(/* webpackChunkName:"show" */ './show').then(show => {
    show('webpack');
  });
});

// show.js
module.exports = function(content) {
  window.alert('hello' + content);
};

npm install babel-plugin-syntax-dynamic-import 识别 import

function getAsyncComponent(load) {
  return class AsyncComponent extends PureComponent {
    componentDidMount() {
      load().then(({ default: component }) => {
        this.setState({
          component
        });
      });
    }
    render() {
      const { component } = this.state || {};
      return component ? createElement(component) : null;
    }
  };
}
function loadIndex() {
  ReactDOM.render(
    <HashRouter>
      <nav>
        <Link to="/">Home</Link>&nbsp;
        <Link to="/about">about</Link>
      </nav>
      <hr />
      <Route exact path="/" component={Home} />
      <Route
        path="/about"
        component={getAsyncComponent(() =>
          import(/* webpackChunkName: 'page-about' */ './views/about')
        )}
      />
    </HashRouter>,
    document.getElementById('app')
  );
}
loadIndex();

antd form 组件开发,源码功能开发

redux

npm install redux --save npm install react-redux --save

// index.js
import { Provider } from 'react-redux';
import store from './store'
 <Provider store={store}>
</Provider>
// store
import {createStore} from 'redux'
const counterReducer=(state=0,action)=>{// reducer: 状态修改具体执行者(state,action)->newState
    switch(action.type){
        case 'add':
        return state+1;
        case 'minus':
        return state-1;
        default:
        return state
    }
}
export default createStore(counterReducer)
// reduxtest
import React, { Component } from 'react';
import { connect } from 'react-redux';
class ReduxTest extends Component {
  constructor() {
    super();
  }
  render() {
    return (
      <div>
        {/* {store.getState()}
        <button onClick={()=>store.dispatch({type:'minus'})}>-</button>
        <button onClick={()=>store.dispatch({type:'add'})}>+</button> */}
        {this.props.num}
        <button onClick={() => this.props.minus()}>-</button>
        <button onClick={() => this.props.add()}>+</button>
      </div>
    );
  }
}
const mapStateToProps = state => ({ num: state });
const mapDispatchToProps = dispatch => ({
  add: () => dispatch({ type: 'add' }),
  minus: () => dispatch({ type: 'minus' })
});
export default connect(mapStateToProps, mapDispatchToProps)(ReduxTest);

redux中间件

npm install redux-thunk redux-logger
redux-thunk异步操作
redux-logger日志记录

react-router

npm install react-router-dom

核心三个 api 的实现

setState 原理

diff

jsx( 面试问题三部曲 )

  1. 什么是 jsx? js 语法扩展,用类似 xml 描述视图模板
  2. 为什么需要 jsx?执行快,类型安全,提高开发效率
  3. 原理: webpack babel-loader 预编译 jsx 为
    React.CreateElement(type,props,...children)

{typeof: Symbol(react.element), type: ƒ, key: null, ref: null, props: {…}, …}typeof:Symbol(react.element)
key:null
props:

webpack.config.js

const path=require('path')
module.exports={
    mode:'development',//production
    entry:{//入口
        index:'./index.js'//单入口
         // main: './main.js' //多入口
    },
    output:{
        path:path.resolve(__dirname,'build'),//默认是dist
        filename:'bundle.min.js'//多入口'[name].min.js'
    },
     module: {
    //模块:放插件,loader
    //json [{test,use}]
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader','css-loader']//从后往前
      },

      }
    ]
  }
}

webpack

mode

如果不写默认在生产模式,不好,所以报错 Set 'mode' option to 'development' or 'production' to enable defaults for eachenvironment.

loader

样式文件 loader

import style from './index.css' <script type="text/javascript" src='./build/bundle.min.js'></script>

css less

npm install style-loader css-loader

npm install less less-loader

  1. css-loader: css to js webpack 才识别,否则报错You may need an appropriate loader to handle this file type.
  2. style-loader: 插入页面生效<header><style type="text/css"></style></header>

css 加上浏览器前缀

npm install autoprefixer postcss-loader

  1. postcss-loader: css 浏览器兼容性 -webkit-transform, 需要配置文件
    postcss.config.js
  2. autoprefixer: 插件,css 加上浏览器前缀
{
  test: /\.less$/,
  use: ['style-loader','css-loader','less-loader', 'postcss-loader']//从后往前
},
postcss.config.js
const autoprefixer = require('autoprefixer');
module.exports = {
  plugins: [
    //   插件,支持loader
    autoprefixer
  ]
};

图片文件 loader

1. file-loader: 读取并输出文件

npm install file-loader

 {
  test: /\.(jpg|gif|png)$/i,
  use: {
    loader:'file-loader',
    options:{
      outputpath:'images/'
  }
},

file-loader: You may need an appropriate loader to handle this file type.
img/1.jpg------>build/images/0b7dcde232259cf01ef2db9d0584243d.jpg

2. url-loader: 读取并输出 base64

npm install url-loader

 {
  test: /\.(jpg|gif|png)$/i,
  use: {
    loader: 'url-loader',
    options: {
      outputPath: './images/',
      limit: 20 * 1024 //20k以下
    }
}

background-image:url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwME…6HX0JXlH7PHgDVPAvgu5uPEWw+J9evptW1RY33ok0)

es6 文件 loader

npm install babel-loader @babel/core @babel/preset-env

 {
  test: /\.jsx?$/,
  exclude: '/node_modules', // 排除
  use: {
    loader: 'babel-loader',
    options: {
      presets: ['@babel/preset-env']
    }
  }
},

webpack-dev-server: dev 环境启动服务

npm install webpack webpack-cli webpack-dev-server -D

  1. webpack
  2. webpack-cli 启动 webpack-dev-server
  3. webpack-dev-server 直接启动不行'webpack-dev-server' 不是内部或外部命令,也不 是可运行的程序或批处理文件。

npm init -yes

{
"name": "webpack01",
"scripts": {
  "start": "webpack-dev-server",
  "build": "webpack"
},

npm run start

Project is running at http://localhost:8080/

每次更新后保存会自动编译到浏览器内存 , 而不是磁盘文件,但是页面不会更新

热更新

注意路径

<script type="text/javascript" src="/bundle.min.js" />;

.eslintrc.js 代码质量管理

npm install eslint eslint-loader -D

{
  test: /\.js$/,
  exclude: '/node_modules',
  use: {  loader: 'eslint-loader', }
},
}
 devtool: 'sourse-map'

单元测试 jest

jest.io

npm install jest jest-webpack jest-webpack npm 库里面没有

const mod = require('../fortest');
//测试用例名称,函数
test('fab-7', () => {
  expect(mod.fab(7).toBe(13));
});
"scripts": {
  "start": "webpack-dev-server",
  "test": "jest-webpack"
},

npm run test 默认到 tests 目录里面找文件,返回结果

plugin : 扩展 webpack 功能

plugin 例子:

  1. postcss.config.js 支持 loader 的使用

  2. 将注入 bundle.js 里面的 css 提取到单独的文件中

    npm install extract-text-webpack-plugin -D

const ExtractTextPlugin=require('extract-text-webpack-plugin')
{
  test: /\.css$/,
  // use: ['style-loader', 'css-loader', 'postcss-loader'] //从后往前
  loaders:ExtractTextPlugin.extract({
    use: ['css-loader'] //从后往前
  })
},
 plugins:[
  new ExtractTextPlugin({
    filename:`[name]_[contenthash:8].css`
  })
]

webpack-dev-middleware

const express = require('express');
const webpack = require('webpack');
const webpackMiddleware = require('webpack-dev-middleware');
const config = require('./webpack.config');
const app = express();
const compiler = webpack(config);
app.use(webpackMiddleware(compiler));
app.get('/', () => {
  console.log('ds');
});
app.listen(9000, '127.0.0.1', function(err) {
  err && console.log(err);
});
plugins:[
  new HtmlWebpackPlugin({
    filename: 'index.html',
    template: path.resolve(rootPath, 'index.html'),
    chunksSortMode: 'none',
  }),
],

删除数组某个元素

//1splice会改变原来的数组
const newGoods = prevState.goods;
newGoods.splice(index, 1);
return {
  goods: newGoods
};
//2 filter,不改变原来数组
prevState.goods.filter(v => v.id !== good.id); 

数组用 push

对象用[...state,action.good]

session

会话控制,用户信息,购物车商品,用户浏览等都存储在 session 中,保存在服务器端(
内存、数据库、文件),最优:内存配合 redis,内存性能最好但重启服务器容易丢失数据
,redis 备份

npm install koa-session

npm install redis

单元测试

chai 断言库

npm install chai

  1. Assert :TDD 风格,类似 nodejs 提供的 Assert 模块
const { assert } = require('chai');
const foo = 'bar';
const beverages = { tea: ['chai', 'matcha', 'oolong'] };
assert.typeOf(foo, 'number'); //string
assert.typeOf(foo, 'string', 'foo is string');
assert.equal(foo, 'bar', 'foo equal "bar"');
assert.lengthOf(foo, 3, "foo's value has a length of 3");
assert.lengthOf(beverages.tea, 3, 'beverages has 3 types of tea');

AssertionError: expected 'bar' to be a number

  1. Expect/should: BDD 链式风格 , 接近自然语言
const { expect } = require('chai');
const foo = 'bar';
const beverages = { tea: ['chai', 'matcha', 'oolong'] };
expect(foo).to.be.a('number');
expect(foo).to.equal('bar');
expect(foo).to.have.lengthOf(3);
expect(beverages)
  .to.have.property('tea')
  .with.lengthOf(3);
const { should } = require('chai').should();
const foo = 'bar';
const beverages = { tea: ['chai', 'matcha', 'oolong'] };
foo.should.be.a('number');
foo.should.equal('bar');
foo.should.have.lengthOf(3);
beverages.should.have.property('tea').with.lengthOf(3);

Mocha 任务运行器

全局安装均可

npm install mocha -g

C:\Users\Administrator\AppData\Roaming\npm\_mocha -> C:\Users\Administrator\AppData\Roaming\npm\node_modules\mocha\bin\_mocha
C:\Users\Administrator\AppData\Roaming\npm\mocha -> C:\Users\Administrator\AppData\Roaming\npm\node_modules\mocha\bin\mocha
const { should } = require('chai').should();
const foo = 'bar';
describe('String', () => {
  it('foo should be a string', () => {
    foo.should.be.a('string');
  });
  it('foo should have lengthOf 3', () => {
    foo.should.have.lengthOf(3);
  });
});
describe('equal', () => {
  it('foo should equal bar', () => {
    foo.should.equal('bar');
  });
});

mocha index.js

server in http://localhost:8080
 String
    √ foo should be a string
    √ foo should have lengthOf 3
  equal
    √ foo should equal bar
  3 passing (131ms)
describe('asynchronous', () => {
  it('done should be executed after 200ms', done => {
    const fn = () => {
      foo.should.be.a('string');
      done();
    };
    setTimeout(fn, 200);
  });
});
asynchronous
    √ done should be executed after 200ms (201ms)

删除 done()

 1 failing
  1) asynchronous
       done should be executed after 200ms:
     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if
returning a Promise, ensure it resolves. (F:\koa2-tutorial\index.js)

npm install supertest

koa2

npm install koa

ctx:context 上下文

ctx 参数 说明 备注
req ctx.req 访问 request 对象 POST
request koa 对 node 请求的封装,提供很多属性用于开发 HTTP 服务器功能 GET
res XXX XXX
response koa 对 node 响应的封装,提供很多属性用于开发 HTTP 服务器功能 XXX
state 命名空间,用于中间件传递信息和前端视图
cookies 获取和设置 cookie
throw 抛出错误,把错误信息返回给用户
response 属性、方法 说明 备注
body 返回给用户的响应主体 XX
status 设置请求状态 200,404,500 等
type 响应的 Content-Type html;image/png;text/plan
accepts() 判断期望的响应类型 ctx.resquest.accepts('html')

ctx.response

const koa = require('koa');
const app = new koa();
app.use(async (ctx, next) => {
  await next();
  ctx.response.type = 'text/html';
  ctx.response.body = '<h1>hello word!!!</h1>';
  console.log('this', this, 'ctx', ctx);
});
app.listen(3000, () => {
  console.log('server in http://localhost:3000');
});

ctx.request 请求

  1. get 请求 --eg. 获取 get 请求中的参数
app.use(async (ctx, next) => {
  ctx.response.body = {
    url: ctx.request.url,
    query: ctx.request.query,
    querystring: ctx.request.querystring
  };
});

http://localhost:3000/?search=koa&keywords=context

{
  "url": "/?search=koa&keywords=context",
  "query": { "search": "koa", "keywords": "context" },
  "querystring": "search=koa&keywords=context"
}
  1. POST 请求 --koa 未封装获取 POST 请求参数的方法
app.use(async (ctx, next) => {
  let postdata = '';
  ctx.req.on('data', data => {
    postdata += data;
  });
  ctx.req.on('end', () => {
    console.log(postdata);
  });
});
- 2.1.1 启动服务器 node index.js
- 2.1.2 新命令行窗口 curl 命令模拟 POST 请求

curl -d "param1=value1&param2=value2" http://localhost:3000/

- 2.1.3 切换回去,看到 log`param1=value1&param2=value2`

npm install koa-bodyparser

app.use(bodyParser())
...
const bodyParser=require('koa-bodyparser')
app.use(bodyParser())
app.use(async (ctx)=>{
    if(ctx.url==='/' && ctx.method==="GET"){
        ctx.type='html';
        let html=`
        <h1>登录</h1>
        <form method="POST" action="/">
        <p>用户名:</p><input name="userName" type="text" />
        <p>密码:</p><input name="password" type="password" />
        <button type="submit">提交</button>
        </form>
        `
        ctx.body=html
    }else if(ctx.url==='/' && ctx.method==='POST'){
        let postData=ctx.request.body
        ctx.body=postData
    }
})
//{"userName":"77","password":"777"}解析出一个对象

npm install koa-router

const bodyParser = require('koa-bodyparser');
const Router = require('koa-router');
const router = new Router();
router.get('/', (ctx, next) => {
  ctx.type = 'html';
  let html = `
    <h1>登录</h1>
    <form method="POST" action="/">
    <p>用户名:</p><input name="userName" type="text" />
    <p>密码:</p><input name="password" type="password" />
    <button type="submit">提交</button>
    </form>
    `;
  ctx.body = html;
});
router.post('/', (ctx, next) => {
  let postData = ctx.request.body;
  ctx.body = postData;
  console.log('body', ctx.body);
});
app
  .use(bodyParser())
  .use(router.routes())
  .use(router.allowedMethods());

中间件,通过 app.use() 加载,先进后出的堆栈结构,洋葱模型

app.use(async (ctx,next)=>{
    console.log('1-1')
    await next()
    console.log('1-2')
})
app.use(async (ctx, next) => {
  console.log('2-1')
  await next();
  ctx.response.type = 'text/html';
  ctx.response.body = '<h1>hello word!!!</h1>';
  console.log('2-2')
});
// 1-1 2-1 2-2 1-2
const compose=require('koa-compose')
async function middlware1(ctx,next) {
    console.log('1-1')
    await next()
    console.log('1-2')
}
async function middlware2(ctx,next) {
    console.log('2-1')
    await next();
    ctx.response.type = 'text/html';
    ctx.response.body = '<h1>hello word!!!</h1>';
    console.log('2-2')
}
const all=compose([middlware1,middlware2])
app.use(compose)
常用中间件

koa-bodyparser

const koa = require('koa');
const app = new koa();
const bodyParser = require('koa-bodyparser');
const Router = require('koa-router');
const router = new Router();
router.get('/user', (ctx, next) => {
  ctx.type = 'html';
  let html = `
    <h1>登录</h1>
    <form method="POST" action="/user/login">
    <p>用户名:</p><input name="userName" type="text" placeholder="aaa" />
    <p>密码:</p><input name="password" type="password" placeholder="111"/>
    <button type="submit">提交</button>
    </form>
    `;
  ctx.response.body = html;
});
router.post('/user/login', (ctx, next) => {
  let { userName, password } = ctx.request.body;
  if (userName === 'aaa' && password === '111') {
    ctx.response.body = `hello,${userName}`;
  } else {
    ctx.response.body = '账号输入错误';
  }
  console.log('body', ctx.body);
});
app
  .use(bodyParser())
  .use(router.routes())
  .use(router.allowedMethods());
app.listen(8080, () => {
  console.log('server in http://localhost:8080');
});

koa-router

router.get('/home/:id/:name', (ctx, next) => {
  ctx.response.body = '<h1>Hello word!</h1>';
  console.log('params', ctx.params);
});
// http://localhost:8080/home/12/aa
// params {id: "12", name: "aa"}

操作数据库 mysql

sequelize:ORM 类库,方便操作数据库

npm install koa koa-bodyparser koa-router koa-cors sequelize mysql2

// jump-mobile-h5 埋点数据后台测试DEMO
const koa = require('koa');
const app = new koa();
const bodyParser = require('koa-bodyparser');
const Router = require('koa-router');
const router = new Router();
const Sequelize = require('sequelize');//ORM 类库,方便操作数据库
const cors = require('koa-cors');

// 连接数据库 databaseName,userName,password
const sequelize = new Sequelize('test', 'root', '111111', {
  host: 'localhost', //数据库服务地址
  dialect: 'mysql' //SQL语言类型
});
// 校验数据库连接
sequelize
  .authenticate()
  .then(() => {
    console.log('connected');
  })
  .catch(err => {
    console.error('connect failed');
  });
// 定义数据模型
// 系统数据
const sysData = sequelize.define('system', {
  uuid: Sequelize.UUID,
  dcEventType: Sequelize.STRING,
  dcPathname: Sequelize.STRING,
  dcCategory: Sequelize.STRING,
  time: Sequelize.STRING
});
// 业务数据
const busData = sequelize.define('buis', {
  comId: Sequelize.STRING,
  dcEventType: Sequelize.STRING,
  dcPathname: Sequelize.STRING,
  dcCategory: Sequelize.STRING,
  time: Sequelize.STRING,
  value: Sequelize.STRING
});
// 同步所有模型到数据库
sequelize
  .sync()
  .then(() => {
    console.log('数据库同步成功')
  })
  .catch(error => {
    console.log(`数据库同步失败:${error}`);
  });
// 创建数据
async function createsysData(logData) {
  return sysData.create(logData);
}
async function createbusData(logData) {
  return busData.create(logData);
}
// 获取POST请求,插入数据
router.post('/log/jumpDataCollect', async (ctx, next) => {
  let { dcCategory, dcPathname, param } = ctx.request.body;
  let logData = { dcCategory, dcPathname, ...param };
  if (dcCategory === 'system') {
    await createsysData(logData);
  } else if (dcCategory === 'buis') {
    await createbusData(logData);
  } else {
  }
  // 返回
  ctx.type = 'jsonMIME';
  ctx.body = {
    status: 0,
    message: 'success',
    result: logData
  };
});
app
  .use(cors()) //解决请求回调跨域
  .use(bodyParser())//POST 请求中的参数解析到 ctx.request.body 中
  .use(router.routes())//路由,结合路径和请求类型
  .use(router.allowedMethods());
app.listen(8080, () => {
  console.log('server in http://localhost:8080');
});
上一篇下一篇

猜你喜欢

热点阅读