title: react 第一次实战项目知识点记录
基础知识点项目地址:https://github.com/yangxinjian/reactPractice.git
完整项目地址(主要是这个)
https://github.com/yangxinjian/reactAntBike.git
image.png
image.png
准备阶段-基层环境
安装node.js(官网下载即可)
node -v (查看是否安装node完成)
安装yarn新一代的包管理工具facebook开发,你也可以选择cnpm
yarn的速度会比npm快
安装版本统一,更安全
更简洁的输出
更好的语义化
sudo cnpm install yarn -gyarn -v(查看是否安装yarn完成)
使用git在马云上进行托管,并在本地clone下来项目
git clone 你项目的地址cd 你的项目
配置gitignore(git命令忽视)
vim .gitignorei(编辑命令).DS_Store(Mac自带)node_modules(node包)dist(打包的压缩文件)*.log(错误信息等)
初始化项目
yarninit/cnpminit
提交项目
gitadd.(保存到暂存区)git commit-m'备注信息'(把暂存区内容保存到分支)git pull(拉取其他分支代码)git push(将更新内容提交进入远程分支)
安装webpack打包工具(配置规则查看webpack章节)
yarn add webpack--dev/cnpm install webpack--dev在根目录下创建一个webpack.config.js文件1.需要处理的文件类型 html=>html-webpack=plugin js es6=>babel+babel-preset-react css=>css-loader+sass-loader img=>url-loader+file-loader2.常用模块 html-webpack-plugin=>html单独打包成文件 extract-text-webpack-plugin=>样式打包成单独文件 CommonsChunkPlugin=>提出通用模块3.webpack-dev-server(1)为webpack项目提供web服务(2)更改代码自动刷新,路径转发(3)yarn add webpack-dev-server--dev(4)解决多版本共存
1.配置webpack,在创建好的webpack.config.js中配置
添加模块输出口
constpath=require('path')module.exports={entry:'./src/app.js',output:{path:path.resolve(__dirname,'dist'),// __dirname代表根目录filename:'你想输出的文件名字.js'}}
添加html插件
yarn add html-webpack-plugin--dev// 生成html5文件插件在webpack.config.js中设置constpath=require('path')constHtmlWebpackPlugin=require('html-webpack-plugin')// 引入插件module.exports={entry:'./src/app.js',output:{path:path.resolve(__dirname,'dist'),filename:'你想输出的文件名字.js'},plugins:[// 使用插件newHtmlWebpackPlugin({template:'.src/index.html'// 引用模板自定义html文件,使打包出来的html与此文件一致})]}
添加babel插件 (将es6语言转换成es5)
yarn add babel-core@6.26.0babel-preset-env@1.6.1babel-loader@7.1.2--dev// 安装在webpack.config.js配置constpath=require('path')constHtmlWebpackPlugin=require('html-webpack-plugin')module.exports={entry:'./src/app.js',output:{path:path.resolve(__dirname,'dist'),filename:'app.js'},module:{rules:[{test:/\.js$/,exclude:/(node_modules)/,// 将不需要装换的文件夹排除use:{loader:'babel-loader',options:{presets:['env']}}}]},plugins:[newHtmlWebpackPlugin({template:'.src/index.html'// 引用自定义html文件})// 生成html5文件]}
安装react的插件
yarn add babel-preset-react --dev / cnpm install babel-preset-react --dev
yarn add html-webpack-plugin--dev// 生成html5文件插件在webpack.config.js中设置constpath=require('path')constHtmlWebpackPlugin=require('html-webpack-plugin')// 引入插件module.exports={entry:'./src/app.js',output:{path:path.resolve(__dirname,'dist'),filename:'你想输出的文件名字.js'},plugins:[// 使用插件newHtmlWebpackPlugin({template:'.src/index.html'// 引用模板自定义html文件,使打包出来的html与此文件一致})]}
添加babel插件 (将es6语言转换成es5)
yarn add babel-core@6.26.0babel-preset-env@1.6.1babel-loader@7.1.2--dev// 安装在webpack.config.js配置constpath=require('path')constHtmlWebpackPlugin=require('html-webpack-plugin')module.exports={entry:'./src/app.js',output:{path:path.resolve(__dirname,'dist'),filename:'app.js'},module:{rules:[{test:/\.js$/,exclude:/(node_modules)/,// 将不需要装换的文件夹排除use:{loader:'babel-loader',options:{presets:['env','react']// 只需要在这里引用react}}}]},plugins:[newHtmlWebpackPlugin({template:'.src/index.html'// 引用自定义html文件})// 生成html5文件]}
安装样式的插件
>安装cssyarn add style-loader@0.19.1css-loader@0.28.8--dev在项目src中新建一个index.css页面,并在app.jsx中引入页面importReactfrom'react'importReactDOMfrom'react-dom'import'./index.css'安装webpack打包css成独立文件的插件yarn add extract-text-webpack-plugin@3.0.2--dev在webpack.config.js中更改对css的配置配置引入constExtractTextPlugin=require('extract-text-webpack-plugin'){test:/\.css$/,use:ExtractTextPlugin.extract({// 这里改变fallback:'style-loader',use:'css-loader'})}由于这是一个插件,需要在plugin中配置>安装sassyarn add sass-loader--devyarn add node-sass--dev在webpack.config.js中rules css配置下添加{test:/\.scss$/,use:ExtractTextPlugin.extract({fallback:'style-loader',use:['css-loader','sass-loader']})}
对图片的处理
yarn add url-loader --sev
在webpack.config.js中配置{test: /\.(png|jpg|gif)$/,
use: [{loader: 'url-loader',
options:{limit:8192 // 文件大于8k被当做文件}}]}
对字体图标的处理
yarn add font-awesome{test: /\.(eot|svg|ttf|woff|woff2|otf)$/,
use: [{loader: 'url-loader',
options:{limit:8192 // 文件大于8k被当做文件}}]}
对公共模块的处理
在plugin中处理
constpath=require('path')constwebpack=require('webpack')//为了引用webpack自带方法constHtmlWebpackPlugin=require('html-webpack-plugin')constExtractTextPlugin=require('extract-text-webpack-plugin')module.exports={entry:'./src/app.jsx',output:{path:path.resolve(__dirname,'dist'),filename:'js/app.js'},module:{rules:[{test:/\.jsx$/,exclude:/(node_modules)/,// 将不需要装换的文件夹排除use:{loader:'babel-loader',options:{presets:['env','react']// 自动根据环境打包}}},{test:/\.css$/,use:ExtractTextPlugin.extract({fallback:'style-loader',use:['css-loader']})},{test:/\.scss$/,use:ExtractTextPlugin.extract({fallback:'style-loader',use:['css-loader','sass-loader']})},{test:/\.(png|jpg|gif|jpeg)$/,use:[{loader:'url-loader',options:{limit:8192,// 文件大于8k被当做文件name:'resource/[name].[ext]'}}]},{test:/\.(eot|svg|ttf|woff|woff2|otf)$/,use:[{loader:'url-loader',options:{limit:8192,// 文件大于8k被当做文件name:'resource/[name].[ext]'}}]}]},plugins:[newHtmlWebpackPlugin({template:'./src/index.html'// 引用自定义html文件}),// 生成html5文件newExtractTextPlugin('css/[name].css'),// 将样式单独打包出来生成新的css页面// 提出公共模块,webpack自带newwebpack.optimize.CommonsChunkPlugin({name:'common',// 手动指定的通用木块filename:'js/base.js'})]}
webpack 自动刷新处理webpack-dev-server
yarn add webpack-dev-server
在config下与plugin同级加上
devServer:{}为了防止打包后的图片在根目录下找不到
output:{path:path.resolve(__dirname,'dist'),publicPath:'/dist/',//在这里添加路径filename:'js/app.js'},编译打包就用webpack-dev-server就可以了
使用react环境搭建项目
yarn add react react-dom 在app.js中引用react结构,并将app.js的后缀更改为jsx,webpack.config.js中的js配置也要变成jsx,入口文件的js也要更改为jsximportReactfrom'react'importReactDOMfrom'react-dom'
package.json的配置
"scripts": { "dev": "node_modules/.bin/webpack-dev-server", "dist": "node_modules/.bin/webpack -p" },
这样就可以使用yarn dev启动项目
yarn dist 打包项目
react正式开始咯(上诉方法均为自己手打搭建一个react项目,了解每一步,接下来是react提供的项目创建方法)
react => 视图层框架 组件化 JSX表达式 虚拟DOM
Facebook 开源的一个JavaScript库
React结合生态库构成一个MVC框架(vue也是mvc)
特点:Declarative(声明式编码:只需要声明在哪里做什么,无需关心如何实现);Component-Based(组件化编码);高效-高效的DOM Diff算法,最小化页面重绘
单向数据流
生态介绍
vue生态:vue + vue-router + vuex + axios + babel + webpack
react生态: react + react-router + redux + axios + babel + webpack
项目的创建(另一种方式,但是本人喜欢上面的手动配置,看得懂)
yarnadd/cnpm installglobal/-g create-react-app(全局安装)在工作区创建项目 create-react-app 你的项目名称 cd 你的项目名称 cnpm/yarn start 启动
JSX语法
添加html
letjsx=<div>thisisa jsx programmer</div>ReactDOM.render(jsx,// 将jsx组件放到渲染的dom下document.getElementById('app))
添加样式
行内样式letstyle={color:'red'}letjsx=<divstyle={style}></div>引入class样式在index.scss中设置body{.jsx{font-size:16px;}}letjsx=<divclassName="jsx"></div>// react中使用className引用样式名称
添加逻辑
(1)使用变量
letname="pig"letjsx=<div>I am a {pig}</div>ReactDom.render(jsx,document.getElementById('app'))
(2)条件判断
lettruth=trueletjsx=(//加括号的目的是为了换行的时候,编辑器不会给我们自动填补分号<div> {// 条件判断需要加上{}truth?<p>I am a pig</p>:<p>I am not a pig</p>} </div>)
(3)jsx中插入注释
{/*我是一个注释*/}
(4)数组的使用
letnames=['pig','dog','chicken']letjsx=({names.map((name,index)=><pkey={index}>I am {name}</p>)})
添加组件
(1)基础
functionComponent(){return<h1>I am a pig</h1>}ReactDom.render(<Component/>,// 如果是变量直接饮用,如果是组件需要加上标签document.getElementById('app'))
(2)es6组件写法
classES6ComponentextendsReact.Component{render(){return<h1>I am a pig in es6</h1>}}ReactDom.render(<div> // 两个组件共存需要包裹在一个div中
<Component/> <ES6Component> </div>,
document.getElementById('app')
)
(3)组件初始化变量
classComponentextendsReact.Component{constructor(props){super(props);this.state={name:'pig'}}render(){return<h1>I am a {this.state.pig}</h1>}}
(4)更改组件初始化变量
classComponentextendsReact.Component{constructor(props){// props在子组件中只能被使用不能被改变super(props);this.state={name:'pig'}}render(){setTimeOut(()=>{this.setState({name:'Pi g Pig'})},2000)return<h1>I am a {this.state.pig}</h1>}}
(5)父组件传值
classComponentextendsReact.Component{constructor(props){super(props)}render(){return<h1>I am a {this.props.name}</h1>}}ReactDom.render(<Componentname="pig"/>,docuement.getElementById('app'))
(6)组件添加点击事件(方法一)
classComponent extends React.Component{constructor(props){super(props);this.state={age:18}this.addAge=this.addAge.bind(this)}addAge(){this.setState({age:this.state.age+1})}render(){return(<div><h1>I am{this.state.age}years old</h1><button onclick={this.addAge}><button/></div>)}}ReactDom.render(<Component/>,docuement.getElementById('app'))
(7)组件添加点击事件(方法二)
classComponentextendsReact.Component{constructor(props){super(props);this.state={age:18}}addAge(){this.setState({age:this.state.age+1})}render(){return(<div> <h1>I am {this.state.age} years old </h1> <buttononclick={(e)=>{this.addAge(e)}}><button/> </div> )
}
}
ReactDom.render(
<Component/>,
docuement.getElementById('app')
)
(8)组件添加输入框更改事件
classComponentextendsReact.Component{constructor(props){super(props);this.state={age:18}}changeValue(e){this.setState({age:e.target.value})}render(){return(<div> <h1>I am {this.state.age} years old </h1> <inputtype="text"onChange={(e)=>{this.changeValue(e)}}/> </div>)}}ReactDom.render(<Component/>,docuement.getElementById('app'))
(9)容器性组件嵌套组件
classComponent extends React.Component{constructor(props){super(props);this.state={age:18}}changeValue(e){this.setState({age:e.target.value})}render(){return(<div><h1>I am{this.state.age}years old</h1><input type="text"onChange={(e)=>{this.changeValue(e)}}/></div>)}}classTitle extends React.Component{constuctor(props){super(props)}render(props){return<h1>{this.props.title}</h1>}}classApp extends React.Component{render(){return(<div><Title title="app"/><Component/>// 在这里引用小组件component</div>)}}ReactDom.render(<App/>,// 这里换成Appdocuement.getElementById('app'))
(10)组件嵌套组件
classComponentextendsReact.Component{constructor(props){super(props);this.state={age:18}}changeValue(e){this.setState({age:e.target.value})}render(){return(<div> <h1>I am {this.state.age} years old </h1> <inputtype="text"onChange={(e)=>{this.changeValue(e)}}/> </div>)}}classAppextendsReact.Component{render(){return(<div> <h1>app</h1> <Component/> // 在这里引用小组件component
</div>)}}ReactDom.render(<App/>,// 这里换成Appdocuement.getElementById('app'))
(11)容器性组件嵌套组件,传值可以为任何html形式
classComponent extends React.Component{constructor(props){super(props);this.state={age:18}}changeValue(e){this.setState({age:e.target.value})}render(){return(<div><h1>I am{this.state.age}years old</h1><input type="text"onChange={(e)=>{this.changeValue(e)}}/></div>)}}classTitle extends React.Component{constuctor(props){super(props)}render(props){return<h1>{this.props.children}</h1>// 这里变成获取子children}}classApp extends React.Component{render(){return(<div><Title><span>我是spanspan</span><a href="">link</a></Title>//更改为html形式<Component/></div>)}}ReactDom.render(<App/>,// 这里换成Appdocuement.getElementById('app'))
(12)子组件给父组件传值
classFather extends React.Component{constructor(props){super(props);this.state={bgColor:'red'}}changeMyBgColors(color){this.setState({bgColor:color})}render(){return(<div style={{background:this.state.bgColor}}><h1>我是爸爸</h1><Child bgColor={this.state.bgColor}changeColor={(color)=>{this.changeMyBgColors(color)}}/></div>)}}classChild extends React.Component{constructor(props){super(props)}changeMyBgColor(){this.props.changeColor('blue')}render(){return(<div><h2>我是baby</h2><button onClick={(e)=>{this.changeMyBgColor(e)}}>我想改变我爸爸的背景颜色</button></div>)}}ReactDOM.render(<Father/>,document.getElementById('app'))
(13)兄弟之间的组件通信(子1传父,父在传子2)
classChild1extendsReact.Component{constructor(props){super(props)this.state={color1:'red'}}changeMyBrotherColor(props){this.props.change2Color(this.state.color1)}render(){return(<div> <h2>我是孩子1</h2> <buttononClick={(e)=>{this.changeMyBrotherColor(e)}}>我要改变我弟弟的颜色咯</button> </div>)}}classChild2extendsReact.Component{constructor(props){super(props)}render(){return(<div> <h2style={{color:this.props.color22}}>我是孩子2</h2> </div>)}}classFatherextendsReact.Component{constructor(props){super(props)this.state={color2:'yellow'}}changColor(colorsss){this.setState({color2:colorsss})}render(){return(<div> <h1>这是我的孩子们</h1> <Child1change2Color={(color)=>{this.changColor(color)}}/> <Child2color22={this.state.color2}/> </div>)}}ReactDOM.render(<Father/>,document.getElementById('app'))
react生命周期
getDefaultProps // 初始化props属性,props来自其他组件
getInitialState // 初始化组件的状态
componentWillMount // 组件加载之前
render // 渲染
componentDidMount // 组件dom插入之后
componentWillReceiveProps // 接受父组件的传递
shouldComponentUpdate // 组件的更新处罚
componentWillUpdate // 组件要更新前
componentDidUpdate // 组件更新后
componentWillUnmount // 组件的销毁
Mounting : 挂载阶段
Updating: 运行时阶段
Unmounting: 卸载阶段
Error Handling: 错误处理
importReactfrom'react'importReactDOMfrom'react-dom'import'./index.scss'classChildextendsReact.Component{// 构造函数constructor(props){super(props)this.state={data:'oldzhuzhu'}console.log('这里是初始化数据constructor')}componentWillMount(){// 组件渲染前console.log('componentWillMount')}componentDidMount(){// 组件渲染结束console.log('componentDidMount')}componentWillReceiveProps(){// 将要接受父组件传来的props触发console.log('componentWillReceiveProps')}shouldComponentUpdate(){// 子组件是不是应该更新console.log('shouldComponentUpdate')returntrue// 如果是false,后面的update就不会跟着更新}componentWillUpdate(){// 组件将要更新console.log('componentWillUpdate')}componentDidUpdate(){// 组件更新完成console.log('componentDidUpdate')}componentWillUnmount(){// 组件将要销毁调用console.log('componentWillUnmount')}// 点击事件handleClick(){console.log('这里是更新数组')this.setState({data:'zhuzhuzhu'})}// 渲染render(){console.log('render')return(<div> {this.state.data} 接收到的props: {this.props.data} <buttononClick={()=>{this.handleClick()}}>更新组件</button> </div>)}}classFatherextendsReact.Component{constructor(props){super(props)this.state={data:'old props'}}changeData(){this.setState({data:'new props',show:true})}byeChild(){this.setState({show:false})}render(){return(<div> {this.state.show?<Childdata={this.state.data}/>:null} <buttononClick={()=>{this.changeData()}}>改变子组件的props</button> <buttononClick={()=>{this.byeChild()}}></button> </div>)}}ReactDOM.render(<Father/>,document.getElementById('app'))
按顺序输出值:
constructor// 构造函数初始化componentWillMount// 组件渲染前render// 组价渲染componentDidMount// 选件渲染完成componentWillReceiveProps// 子组件接收到父组件传来的propsshouldComponentUpdate// 是否组件进行更新,true更新,false接下来的周期不触发componentWillUpdate// 组件更新前render// 更新componentDidUpdate// 组件更新结束componentWillUnmount// 组件被摧毁之前
react-router
1.router几种方式
页面路由
window.location.href='地址'// www.baidu.comhistory.back()//回退
hash 路由
window.location='#hash'window.onhashchange=function(){console.log('current hash'+window.location.hash)}
h5路由
history.pushState('name','title','/path')// 推进一个状态history.replaceState('name','title','/path')// 更换一个状态window.onpopstate=function(){console.log(window.location.href)console.log(window.location.pathname)console.log(window.location.hash)console.log(window.location.search)}
2. react-router几种方式
hash
importReactfrom'react'importReactDOMfrom'react-dom'import{HashRouterasRouter,Route,Link}from'react-router-dom'// 这里是Hashimport'./index.scss'classAextendsReact.Component{constructor(props){super(props)}render(){return(<div>Component A</div>)}}classBextendsReact.Component{constructor(props){super(props)}render(){return(<div>Component B</div>)}}classWrapperextendsReact.Component{constructor(props){super(props)}render(){return(<div> <Linkto="/a">组件A</Link> <br/> <Linkto="/b">组件B </Link> {this.props.children} </div>)}}ReactDOM.render(<Router> <Wrapper> <Routepath="/a"component={A}/> <Routepath="/b"component={B}/> </Wrapper> </Router>,document.getElementById('app'))
browser
如果改成import{BrowserRouterasRouter,Route,Link}from'react-router-dom'路径地址都会变成 http://localhost:8080/a,此时请求的是后端代码,在复制这个链接在其他页面打开时,会报成404,因为后台并没有生成这个地址
3.router传参,组件接受不同组件传参
引入switch
import {HashRouter as Router,Route,Link,Switch} from 'react-router-dom'
class A extends React.Component { constructor (props) { super(props) } render () { return (
开始正式共享单车项目知识点(react全家桶+ant ui 组件+公共机制封装)
地址:https://github.com/yangxinjian/reactAntBike.git
react基础知识,生命周期(见上部分的基础知识点)
router4.0
redux集成开发
ant最实用基础组件
ant栅格系统
Etable组件封装
BaseForm组件封装
表格内嵌单选,复选封装
axios请求插件封装
api封装
错误拦截
权限,菜单封装等
地图,图表的使用
安装脚手架(上述有步骤,可选择自己搭建,也可以使用官方脚手架)
sudo cnpm install -g create-react-app
初始化项目
create-react-app bikesystem (你项目的名称:注意不用大写字母)
安装react-router
yarn add react-router
启动项目
yarn start
项目所需要的插件
安装react-router,axios
安装AntD
暴露webpack配置文件
安装less-loader
修改less-loader
sudo yarnaddreact-router-dom axios less-loadersudo yarnaddlesssudo yarn antd(支付宝做的ui组件)
引用antd样式
import{Button}from'antd'// 引用某一个组件<Button>使用组件</Button>import'antd/dist/antd.css'
想要按需加载对应组件css,需要安装babel,安装后就无需引用上面的css
sudo yarnaddbabel-plugin-import sudo yarnaddless@^2.7.3在package.json 的babel下加入"plugins":[["import",{"libraryName":"antd","style":"css"}]]
暴露webpack文件,得到config文件夹
sudo yarn eject
更改config/webpack.config.js ,使项目能识别less文件,配置后重启生效
在 // style files regexes下 添加
constlessRegex=/\.less$/;constlessModuleRegex=/\.module\.less$/;
在 cssRegex引用后面下 添加less配置对象
{test: lessRegex,
exclude: lessModuleRegex,
use: getStyleLoaders({importLoaders:3,// 这里不要与其他配置的数字一样sourceMap:isEnvProduction && shouldUseSourceMap,},'less-loader'),sideEffects:true,},{test: lessModuleRegex,
use: getStyleLoaders({importLoaders:3,// 这里不要与其他配置的数字一样sourceMap:isEnvProduction && shouldUseSourceMap,modules:true,getLocalIdent:getCSSModuleLocalIdent,},'less-loader'),},
项目架构
在src中新建组件文件夹,取名component,分别根据项目搭建出header头部文件夹,footer底部文件夹,NavLeft左菜单文件夹,以及在src下新建admin.js
Jietu20190401-163524.jpg
在admin.js中配置主结构,用row,col,并引入三个外部组件,注意!!!三个外部组件的内容不能为空,否则会报错
importReactfrom'react'import{Row,Col}from'antd';importHeaderfrom'./components/header';importFooterfrom'./components/footer';exportdefaultclassAdminextendsReact.Component{render(){return(<Row> <Colspan="3"> left
</Col> <Colspan="21"> <Header> header
</Header> <Row> contet
</Row> <Footer> footer
</Footer> </Col> </Row>)}}
作为主要的菜单结构,单独封装出一个js,写在了config下的menuConfig.js中,请大家自行git clone 我的项目地址,本项目是开源的项目
public里文件是将要被打包部署到服务器上。一般是图片等元素信息
项目中使用的功能方法
1. 请求外部的百度地图下的天气API
先在百度地图开放平台,创建应用,选择浏览器,生成自己的AK码
在代码中安装jsonp
sudo yarnaddjsonp--save
封装jsonp方法
importJsonPfrom'jsonp'exportdefaultclassAxios{// 链式调用staticjsonp(options){returnnewPromise((resolve,reject)=>{JsonP(options.url,{param:'callback'},function(err,response){if(response.status=='success'){// 成功回调resolve(response);}else{reject(response.messsage);// 失败回调}})})}}
在组件中调用
importaxiosfrom'../../axios'state={}componentWillMount(){this.getWeatherAPIData()// 调用方法}// 获取天气api,encodeURIComponent编码对中文的处理getWeatherAPIData(){letcity='北京'axios.jsonp({url:'http://api.map.baidu.com/telematics/v3/weather?location='+encodeURIComponent(city)+'&output=json&ak=3p49MVra6urFRGOT9s8UBWr2'// api地址 , ak是你自己申请的应用ak}).then((res)=>{if(res.status=='success'){letdata=res.results[0].weather_data[0];// 取当前的天气this.setState({dayPictureUrl:data.dayPictureUrl,weather:data.weather})}})}// 在render中渲染<spanclassName="weather-img"> <imgsrc={this.state.dayPictureUrl}alt=""/> </span><spanclassName="weather-detail"> {this.state.weather} </span>
2.react-router4.0(不需要路由配置,一切皆组件,浏览器端)
核心用法:
HashRouter和BrowserRouter
hash:http://localhost:3000/#/adminbrowser:http://localhost:3000/admin
2.Route:path,exact,component,render --- 参考项目中的pages下的router-demo下的router2文件夹的内容
<Router> <Home> // home 是主界面,包含的都是他的子组件路由
<Routepath="/"component={Main}exact></Route> <Routepath="/about"component={About}></Route> <Routepath="/topics"component={Topics}></Route> </Home> </Router>主界面加载子组件的地方,添加{this.props.children}
3.NavLink,Link ------ 通过this.props.match接受路由带的内容--- 参考项目中的pages下的router-demo下的router1文件夹的内容
<HashRouter>{/* 需要根节点 */}<div><ul><li><Linkto="/">Home</Link></li><li><Linkto="/about">About</Link></li><li><Linkto="/topics">Topics</Link></li></ul>{/* /about会检索到/和/about,所以防止加载两次,加上exact精确匹配 */}<Routepath="/"component={Main}></Route><Routepath="/about"component={About}></Route><Routepath="/topics"component={Topics}></Route></div></HashRouter>
4.Switch
<Switch>{/* switch只会加载一次,按顺序 */}<Routepath="/"component={Main}></Route><Routepath="/about"component={About}></Route><Routepath="/topics"component={Topics}></Route></Switch>
5.Redict
<Redirectto="/admin/home"/>
withRouter 直接跳转路由
import{withRouter}from'react-router-dom'引入 使用this.props.history.push({pathname:'/admin'})渲染,在exportdefault中增添withRouter(Form.create()(OrganizeManage))
3.项目中运用router实现菜单导航路由
根路由的编写
在src目录下建立router.js文件 , 并在全局index.js中更换Router
在router.js中引用app.js作为主框架
importReactfrom'react'import{HashRouter,Route,Switch}from'react-router-dom'importAppfrom'./App'importLoginfrom'./pages/login'importAdminfrom'./admin'exportdefaultclassIRouterextendsReact.Component{render(){return(<HashRouter> <App> <Routepath="/login"component={Login}/> (一级路由--登录界面)
<Routepath="/admin"component={Admin}/> (一级路由--登录进来的页面)
</App> </HashRouter>)}}
在app中引用子路由
importReact,{Component}from'react';importlogofrom'./logo.svg';import'./App.css';classAppextendsComponent{render(){return(<div> {this.props.children} </div>);}}exportdefaultApp;
在一级路由下嵌套二级路由,更改的admin界面下的路由配置
// 二级路由<Admin><Routepath="/admin/ui/button"component={Button}/></Admin>}/> 在admin.js中更改<RowclassName="content">{this.props.children} // 这里引用</Row>
菜单路由link配置
引用路由 在NavLeft页面下import{NavLink}from'react-router-dom'在menu-item中包裹路由<Menu.Itemtitle={item.title}key={item.key}> <NavLinkto={item.key}>{item.title}</NavLink> // 这里跳转地址
</Menu.Item>
配置路由加载错误的情况下的展示页面
先建立文件夹nomatch包裹404展示文件,再在路由里面引用
<Switch><Routepath="/admin/ui/buttons"component={Buttons}/><Routecomponent={NoMatch}></Route></Switch>
Ant design UI组件的基本使用
在项目地址下的ui文件夹有基本的使用展示,你可以选择clone我的项目下到本地进行查看,接下来的笔记介绍几种初学者会遇到的使用
1. form组件实现登录
创建用户名和密码以及登录摁钮
需要引用FormItem const FormItem = Form.item
} placeholder="请输入用户名"/> } placeholder="请输入密码"/> 登录
添加输入验证
第一步:在render中创建getFieldDecorator对象
const{getFieldDecorator}=this.props.form;
第二步:给标签内嵌入js语法实现验证
<FormItem> {getFieldDecorator('userName',{// username是定义的用户名变量,不同输入框的命名要是分别的initialValue:'',rules:[{required:true,message:'用户名不能为空'},{min:5,max:10,message:'长度不在范围内'},{pattern:newRegExp('^\\w+$','g'),// 正则表达式都可以message:'用户名必须为字母或者数字'}]})(<Inputprefix={<Icontype="user"/>}placeholder="请输入用户名"/>)} </FormItem>
第三步:通过Form创建表单
classFormLoginextendsReact.Component将前面的exportdefault去掉exportdefaultForm.create()(FormLogin);在结尾中加入
添加摁钮点击校验
第一步: 给摁钮绑定事件
<Buttontype="primary"onClick={this.handleSubmit}>登录</Button>
第二步:编写事件
handleSubmit=()=>{letuserInfo=this.props.form.getFieldsValue();this.props.form.validateFields((err,values)=>{if(!err){// 如果没有错的情况下message.success(`${userInfo.userName} 恭喜你,您通过本次表单组件学习,当前密码为:${userInfo.userPwd}`)}})}
2. datePicker日期控件的引用
想要设置默认值,需要引用moment插件
sudo yarn add moment--saveimportmoment from 'moment<FormItemlabel="生日">{getFieldDecorator('birth',{initialValue:moment('2018-08-08'),// 获取momentrules:[{required:true}]})(<DatePickershowTime format="YYYY-MM-DD"/>)}</FormItem>
3.栅格左右大小分配格式提取
constformItemLayout={// 栅格样式 复用labelCol:{xs:24,sm:4},wrapperCol:{xs:24,sm:8}}<FormItem{...formItemLayout}>使用es6结构赋值</FormItem>
4.上传文件
<Upload listType="picture-card"howUploadList={false}// axtion是服务器的地址action="//jsonplaceholder.typicode.com/posts/"nChange={this.handleChange}>{this.state.userImg?<imgsrc={this.state.userImg}/>:<Icontype="plus"></Icon>}</Upload>handleChange=(info)=>{// 上传图像if(info.file.status==='uploading'){this.setState({loading:true});return;}if(info.file.status==='done'){// 正常是调用服务器的上传地址}}
5. easy mock,语法参考mock.js
是一款可以适用于前端编写线上接口,以便测试调用,自动创建项目,编写接口,放入数据
' result|10':[{// 生成十条数据"code":0,"message":'失败',"result|10":[{'id|+1':0,// 递增+1'userName':'@cname',// 随机的名字'sex|1-2':1,// 随机在1-2中选择'telephone':'888888','state|1-5':1,// 随机在1-5中选择'interest|1-8':1,// 随机在1-8中选择'birth':'1995-06-30','address':'地球',}]
6. axios使用与封装
最简单的引用
// 动态获取mock数据,根据上步创建的接口获取importaxios from'axios
request = () => {
let baseUrl = 'https://www.easy-mock.com/mock/5caffee40ee3ff114ba3e62b/yxjapi'
axios.get(`${baseUrl}/table/list`).then((res) =>{
if (res.data.code == '0'){this.setState({dataSource2:res.data.result})}})}
封装axios请求
staticajax(options){constbaseURL='https://www.easy-mock.com/mock/5caffee40ee3ff114ba3e62b/yxjapi'// 接口地址returnnewPromise((resolve,reject)=>{axios({url:options.url,method:'get',baseURL:baseURL,timeout:7000,params:(options.data.params&&options.data)||''}).then((response)=>{if(response.status=='200'){// http请求自带statusletres=response.dataif(res.code=='0'){// 项目服务器后台接口业务层面的判断resolve(res)}else{Modal.info({title:'提示',content:res.data.messsage})}}else{reject(response.data)}})})}
使用
axios.ajax({url:'/table/list',data:{params:{page:1}}}).then((res)=>{if(res.code=='0'){this.setState({dataSource2:res.result})}})
7. 表格分页的封装
// 分页的封装pagination(data,callback){letpage={onChange:(current)=>{callback(current)},current:data.result.page,pageSize:data.result.page_size,total:data.result.total,showTotal:()=>{return`共${data.result.total}条`},showQuickJumper:true}returnpage}
使用
request=()=>{axios.ajax({url:'/table/list',data:{params:{page:1},isShowLoading:true}}).then((res)=>{if(res.code=='0'){this.setState({dataSource2:res.result.list,selectedRowKeys:[],// 删除后的重置selectedRows:null,// 删除后的重置pagination:util.pagination(res,(current)=>{// 根据点击的页玛进行数据变化处理// to-do_this.params.page=current _this.request()message.success(`当前页${current}`)})})}})<TablebordereddataSource={this.state.dataSource2}columns={columns}pagination={this.state.pagination}/>
8 . 组件使用外部class的form表单,获取表单对象
绑定wrappedComponentRef方法输出表达对象给dataform自定义,通过
letdrgInfo=this.dataForm.props.form.getFieldsValue()获取数据<OpenFormDataswrappedComponentRef={(datas)=>{this.dataForm=datas}}/>
9. 地图功能的实现(基于项目中的骑车路线)
创建ak,加载百度地图sdk
地图初始化,添加地图控件
绘制路线(通过坐标点)
绘制服务区地图
(1) 创建ak,加载百度地图sdk
第一步:打开map.baidu.com,找到地图开放平台,点击进入
第二步:点击开发文档,点击web开发下的JavaScript API
第三步:在产品简介中,点击申请秘钥ak,创建应用,选择浏览器 端,白名单中设置*号,点击创建即可获取ak值
第四步:在public文件夹下的index.html的head部分中引用以下代码
<scripttype="text/javascript"src="http://api.map.baidu.com/api?v=2.0&ak=您的ak秘钥"></script>
(2)初始化地图
第一步:创建一个渲染地图的容器,取一个id值
<divid="orderDetailMap"className="order-map"></div>
第二步:为获取地图对象添加方法,并且添加控件,同时在接口数据返回后调用方法
renderMap=(result)=>{this.map=newwindow.BMap.Map('orderDetailMap');// 添加地图控件this.map.centerAndZoom('北京',11);// 设置地图的中心点this.addMapControl();}// 添加地图控件addMapControl=()=>{letmap=this.map;map.addControl(newwindow.BMap.ScaleControl({anchor:window.BMAP_ANCHOR_TOP_RIGHT}));map.addControl(newwindow.BMap.NavigationControl({anchor:window.BMAP_ANCHOR_TOP_RIGHT}));}
(3)绘制路线
// 绘制用户的行驶路线drawBikeRoute=(positionList)=>{letmap=this.map;letstartPoint='';letendPoint='';// lon 经度 lat 纬度if(positionList.length>0){// 判断行驶轨迹是否存在letfirst=positionList[0];letlast=positionList[positionList.length-1];startPoint=newwindow.BMap.Point(first.lon,first.lat);// 获取地图点// 创建开始坐标点的图标letstartIcon=newwindow.BMap.Icon('/assets/start_point.png',newwindow.BMap.Size(36,42),{// 整个图标imageSize:newwindow.BMap.Size(36,42),// 图片的大小anchor:newwindow.BMap.Size(18,42)})// marker是为了将icon图标嵌入到地图里面,并且要设置坐标点实现点letstartMarker=newwindow.BMap.Marker(startPoint,{icon:startIcon});this.map.addOverlay(startMarker);// 创建结束坐标点的图标endPoint=newwindow.BMap.Point(last.lon,last.lat);letendIcon=newwindow.BMap.Icon('/assets/end_point.png',newwindow.BMap.Size(36,42),{imageSize:newwindow.BMap.Size(36,42),anchor:newwindow.BMap.Size(18,42)})// marker是为了将icon图标嵌入到地图里面,并且要设置坐标点实现点letendMarker=newwindow.BMap.Marker(endPoint,{icon:endIcon});this.map.addOverlay(endMarker);// 连接路线图lettrackPoint=[];for(leti=0;i<positionList.length;i++){letpoint=positionList[i];trackPoint.push(newwindow.BMap.Point(point.lon,point.lat));}// 设置线的样式letpolyline=newwindow.BMap.Polyline(trackPoint,{strokeColor:'#1869AD',strokeWeight:3,strokeOpacity:1})this.map.addOverlay(polyline);this.map.centerAndZoom(endPoint,11);}}
(4) 绘制服务区地图
// 绘制服务区drwaServiceArea=(positionList)=>{// 连接路线图lettrackPoint=[];for(leti=0;i<positionList.length;i++){letpoint=positionList[i];trackPoint.push(newwindow.BMap.Point(point.lon,point.lat));}// 绘制服务区letpolygon=newwindow.BMap.Polygon(trackPoint,{strokeColor:'#CE0000',strokeWeight:4,strokeOpacity:1,fillColor:'#ff8605',fillOpacity:0.4})this.map.addOverlay(polygon);}
10. echart的使用
安装
sudo yarnaddecharts-for-react--savesudo yarnaddecharts--save
引用
importReactEchartsfrom'echarts-for-react';importechartsfrom'echarts/lib/echarts'可以按需引用echart中某一个组件// 引入饼图和折线图import'echarts/lib/chart/pie'
使用
getOption(){let option={title:{text:'用户骑行订单',x:'center'},legend:{orient:'vertical',right:10,top:20,bottom:20,data:['周一','周二','周三','周四','周五','周六','周日']},tooltip:{trigger:'item',formatter:"{a} <br/>{b} : {c} ({d}%)"},series:[{name:'订单量',type:'pie',radius:'55%',center:['50%','60%'],data:[{value:1000,name:'周一'}],itemStyle:{emphasis:{shadowBlur:10,shadowOffsetX:0,shadowColor:'rgba(0, 0, 0, 0.5)'}}}]}returnoption;}// render中渲染<ReactEcharts option={this.getOption()}style={{height:500}}/>
11. 富文本编辑器的使用 ------ react-draft-wysiwyg
安装富文本组件以及将组件内容装换成html格式的draftjs
sudo yarnaddreact-draft-wysiwyg draftjs-to-html--save
使用 参考项目代码把。。。文字过长了,不让发了,我都提交了
作者:文子哥哥
来源:简书