react学习心得(react基础+react全家桶+antd-ui知识)讲解

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 (

Component  A {                              return
当前组件是不带参数的A
}}                      />path={`${this.props.match.path}/sub`}                          render={(route) => {                              return
当前组件是sub
}}                      /> {                          return<div>当前组件是带参数的A,参数是 : {route.match.params.id}</div>}}/></Switch></div>)      }  }  class B extends React.Component {      constructor (props) {          super(props)      }      render () {          return (<div>Component B</div>)      }  }  class Wrapper extends React.Component {      constructor (props) {          super(props)      }      render () {          return (<div><Linkto="/a">组件A</Link><br/><Linkto="/a/123">带参数的组件A</Link><br/><Linkto="/a/sub">/a/sub子路径</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')  )

开始正式共享单车项目知识点(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

使用 参考项目代码把。。。文字过长了,不让发了,我都提交了

作者:文子哥哥

来源:简书

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345