react知识点
state-setState
对象方式(对象合并方式 object.assigin())、函数方式 ( 队列 )
- 如何修改状态:不能用 this.state, 用 setState(setState 是异步批量执行的,如果
同时操作多个 setState 一起执行效率高) - setState 后如何获得更新的 state: 回调或钩子函数 componentDidUpdate 中
- 如何操作之前的 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 isundefined
.
npm install redux react-redux
组件交互
组件化
-
UI=F(state)
-
容器组件 VS 展示组件
- class function
- PureComponent : 定制了 shouldComponentUpdate 后的 Component( 浅比较 )
- 解套:确保数据类型是值类型
<Commenta key={i} {...c}/>
- 如果是引用类型,确保地址不变,同时不应该有深层数据变化
-
组件复合而非组件继承
{props.children}
-
高阶组件 HOC 函数
function Kai(props) {
return (
<div>
{props.stage}-{props.name}
</div>
);
}
// 高阶组件
const withName = Comp => {
// 假设通过特殊手段获取名称
return props => <Comp {...props} name="aaa" />;
};
export default withName(Kai);
- 装饰器 -es7
npm install --save-dev babel-plugin-transform-decorators-legacy
// 添加装饰器能力
config = injectBabelPlugin(
['@babel/plugin-proposal-decorators', { legacy: true }],
config
);
- 组件库 antd- 表单设计思想
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(...)
- React.createElement(...)执行结束会得到一个js对象树,能完整描述dom结构,称为虚拟DOM
- 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>
<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( 面试问题三部曲 )
- 什么是 jsx? js 语法扩展,用类似 xml 描述视图模板
- 为什么需要 jsx?执行快,类型安全,提高开发效率
- 原理: webpack babel-loader 预编译 jsx 为
React.CreateElement(type,props,...children)
{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
- css-loader: css to js webpack 才识别,否则报错
You may need an appropriate loader to handle this file type.
- style-loader: 插入页面生效
<header><style type="text/css"></style></header>
css 加上浏览器前缀
npm install autoprefixer postcss-loader
- postcss-loader: css 浏览器兼容性 -webkit-transform, 需要配置文件
postcss.config.js - 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
- webpack
- webpack-cli 启动 webpack-dev-server
- 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 例子:
-
postcss.config.js 支持 loader 的使用
-
将注入 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
- 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
- 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 请求
- 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"
}
- POST 请求 --koa 未封装获取 POST 请求参数的方法
- 2.1 需解析 context 中原生 Node.js 请求对象 req
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¶m2=value2" http://localhost:3000/
- 2.1.3 切换回去,看到 log`param1=value1¶m2=value2`
- 2.2 koa-bodyparser 中间件 -- 可以把 POST 请求中的参数解析到 ctx.request.body
中
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
- 多个中间件组合,使用 koa-compose
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--POST 请求中的参数解析到 ctx.request.body 中,不再用 ctx.req.on
- koa-router-- 简化路由,不再用 ctx.url 判断路径,ctx.method 判断请求类型
- npm install koa-static
- npm install koa-views
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');
});