最近公司项目使用了ant design pro,从没接触过react的我只能趁着周末学习熟悉,赶紧上手。(都是泪。。)说到ant design pro,得先了解一下ant design是个什么东西?ant design蚂蚁金服基于react打造的一个服务于企业级产品的UI框架。而ant design pro呢?就是基于Ant Design这个框架
搭建的中后台管理控制台的脚手架 。连登陆界面主界面布局都写好了,只需要在里面写业务相关的页面就可以了,节省不少人力。它秉承 Ant Design 的设计价值观,致力于在设计规范和基础组件的基础上,继续向上构建,提炼出典型模板/业务组件/配套设计资源,进一步提升企业级中后台产品设计研发过程中的『用户』和『设计者』的体验。使用antd-pro 之前,开发的同学们最好了解 ES2015+、React、UmiJS、dva、g2 、 antd以及React Router v4的基础知识,这将为你的开发工作提供必要的基础。需要学习的东西挺多,上手门槛比VUE高了一些。这里主要记录本人从零搭建ant design pro的过程,以及常用的语法
项目搭建
首先,找个地方建个空目录,然后使用 npm create umi
脚手架,创建模板:
选择第一项:ant-design-pro。然后回车
为了简单起见,选择JavaScript创建项目,然后一路回车。到下面这个步骤项目就已经初始化好了
使用webstorm打开刚刚创建的工程,可以看到目录结构如下
├── config # umi 配置,包含路由,构建等配置
│ ├── config # 配置文件:包含路由、样式、proxy等
│ ├── defaultSettings # 默认设置:包括标题title、navTheme等
│ ├── plugin.config # webpack的Plugin配置
│ ├── themePluginConfig # 风格主题的配置
├── mock # 本地模拟数据
├── public
│ └── favicon.png # Favicon
├── src
│ ├── assets # 本地静态资源
│ ├── components # 业务通用组件
│ ├...
│ ├── GlobalHeader # 基础布局的头部
│ ├── AvatarDropdown # 用户头像下拉菜单
│ ├── NoticeIconView # 通知图标和通知消息视图
│ ├── plugin.config # webpack的Plugin配置
│ ├── RightContent # 基础布局的头部核心:包含搜索、头像、语言选择
│ ├── e2e # 集成测试用例
│ ├── layouts # 通用布局
│ ├── models # 全局 dva model
│ ├── pages # 业务页面入口和常用模板
│ ├── services # 后台接口服务
│ ├── utils # 工具库
│ ├── locales # 国际化资源
│ ├── global.less # 全局样式
│ └── global.ts # 全局 JS
├── tests # 测试工具
├── README.md
├── package.json
└── ... # 其他
然后进入目录,执行 npm install
下载前端依赖包,在下载依赖过程中可能会失败,显示会是权限问题,其实就是包下载不下来,报错如下
而一次出错之后,一般人都会再次npm install
,而npm install命令并不会主动清除上次安装的包,而你上次安装的包又不完整,包与包之间又有依赖关系,结果自然再次出错。所以,要想解决这个问题,就应该清除上次安装的包,想要彻底清除则一般需要以下3步,删除node modules中的全部文件。然后执行:npm cache clean --force
命令,npm可执行命令如下
npm start # 运行这个脚本会启动服务,自动打开默认浏览器展示你的页面。当你重新编辑代码后,页面还会自动刷新。
npm run build # 运行这个脚本将会编译你的项目,你可以在项目中的 dist 目录中找到编译后的文件用于部署。
npm run lint # 通过这个脚本来查看你的代码有哪些问题
npm test # 这个脚本会执行一系列测试,包括 e2e 测试。
npm run i18n-remove # 这个脚本将会尝试删除项目中所有的 i18n 代码,对于复杂的运行时代码,表现并不好,慎用。
执行 npm start,启动成功后可看到主界面
到此,ant design pro项目就搭建好了。下面介绍一下JSX语法吧,这是React官方推荐的模板语法,与VUE使用模板的方式差别还是挺大的。不过本人在使用了Vue和React后,觉得Vue的模板语法使用更加顺手,基本上符合Html的语法,上手更快。看个人习惯吧
JSX模板语法
简单来说,在JS中书写HTML语法(不是简单在JS中写HTML字符串),就可称之为JSX语法。JSX就是Javascript和XML结合的一种格式。React发明了JSX,利用HTML语法来创建虚拟DOM。当遇到<,JSX就当HTML解析,遇到{就当JavaScript解析。JS语法与JSX语法的区别。在普通的JS语法中,如果想渲染一段html文本的话,我们需要这么做。如下:
var child1 = React.createElement('li', null, 'First Text Content');
var child2 = React.createElement('li', null, 'Second Text Content');
var root = React.createElement('ul', { className: 'my-list' }, child1, child2);
等价于(JSX写法)
var root =(
<ul className="my-list">
<li>First Text Content</li>
<li>Second Text Content</li>
</ul>
);
后者将XML语法直接加入JS中,通过代码而非模板来高效的定义界面。之后JSX通过翻译器转换为纯JS再由浏览器执行。在实际开发中,JSX在产品打包阶段都已经编译成纯JavaScript,JSX的语法不会带来任何性能影响。另外,由于JSX只是一种语法,因此JavaScript的关键字class, for等也不能出现在XML中,而要如例子中所示,使用className, htmlFor代替,这和原生DOM在JavaScript中的创建也是一致的。JSX只是创建虚拟DOM的一种语法格式而已,除了用JSX,我们也可以用JS代码来创建虚拟DOM。
JSX的基本使用
要使用 JSX 则必须要引入React,React的每一个组件都有render函数,render函数返回的就是JSX渲染的内容,JSX的基本使用个HTML标签没有什么区别。
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<div>Hello word!</div>
);
}
}
export default App;
JSX占位符:Fragement
在JSX中返回的内容都必须包含在一个大的标签内,所以我们不得不在最外边套一层div,如果我们不希望页面渲染这层div的话就需要使用占位符-Fragement在JSX中返回的内容都必须包含在一个大的标签内,所以我们不得不在最外边套一层div,如果我们不希望页面渲染这层div的话就需要使用占位符-Fragement
import React, { Component, Fragement} from 'react';
class App extends Component {
render() {
return (
<Fragement>
<div>Hello word!</div>
<div>Hello React!</div>
</Fragement>
);
}
}
JSX中绑定事件
SX让事件直接绑定在元素上。
<button onClick={this.checkAndSubmit.bind(this)}>Submit</button>
和原生HTML定义事件的唯一区别就是JSX采用驼峰写法来描述事件名称,大括号中仍然是标准的JavaScript表达式,返回一个事件处理函数。React并不会真正的绑定事件到每一个具体的元素上,而是采用事件代理的模式:在根节点document上为每种事件添加唯一的Listener,然后通过事件的target找到真实的触发元素。这样从触发元素到顶层节点之间的所有节点如果有绑定这个事件,React都会触发对应的事件处理函数。这就是所谓的React模拟事件系统。尽管整个事件系统由React管理,但是其API和使用方法与原生事件一致。
JSX中使用样式
在JSX中使用样式和真实的样式也很类似,通过style属性来定义,但和真实DOM不同的是,属性值不能是字符串而必须为对象。例如:
<div style={{color: '#ff0000', fontSize: '14px'}}>Hello World.</div>
或者
var style = {
color: '#ff0000',
fontSize: '14px'
};
var node = <div style={style}>HelloWorld.</div>;
要明确记住,{}里面是JS代码,这里传进去的是标准的JS对象。在JSX中可以使用所有的的样式,基本上属性名的转换规范就是将其写成驼峰写法,例如“background-color”变为“backgroundColor”, “font-size”变为“fontSize”,这和标准的JavaScript操作DOM样式的API是一致的。
父组件向子组件传值
父组件Comment.js
import React from "react"
import ComentList from "./ComentList"
class Comment extends React.Component {
constructor(props) {
super(props);
this.state = {
arr: [{
"userName": "fangMing", "text": "123333", "result": true
}, {
"userName": "zhangSan", "text": "345555", "result": false
}, {
"userName": "liSi", "text": "567777", "result": true
}, {
"userName": "wangWu", "text": "789999", "result": true
},]
}
}
render() {
return (
<div>
<ComentList arr={this.state.arr}> //这里把state里面的arr传递到子组件,等号左边的arr就是形参名,在子组件中取参数也是取arr
</ComentList>
</div>
)
}
}
export default Comment;
子组件ComentList.js
import React from "react"
class ComentList extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="list">
<ul>
{
this.props.arr.map(item => { //这个地方通过this.props.arr接收到父组件传过来的arr,然后在{}里面进行js的循环
return (
<li key={item.userName}>
{item.userName} 评论是:{item.text}
</li>
)
})
}
</ul>
</div>
)
}
}
export default ComentList;
子组件向父组件传值
父组件Comment.js
import React from "react"
import ComentList from "./ComentList"
class Comment extends React.Component {
constructor(props) {
super(props);
this.state = {
parentText: "this is parent text",
arr: [{
"userName": "fangMing", "text": "123333", "result": true
}, {
"userName": "zhangSan", "text": "345555", "result": false
}, {
"userName": "liSi", "text": "567777", "result": true
}, {
"userName": "wangWu", "text": "789999", "result": true
},]
}
}
fn(data) {
this.setState({
parentText: data //把父组件中的parentText替换为子组件传递的值
},() =>{
console.log(this.state.parentText);//setState是异步操作,但是我们可以在它的回调函数里面进行操作
});
}
render() {
return (
<div>
//通过绑定事件进行值的运算,这个地方一定要记得.bind(this),不然会报错,切记切记,因为通过事件传递的时候this的指向已经改变
<ComentList arr={this.state.arr} pfn={this.fn.bind(this)}>
</ComentList>
<p>
text is {this.state.parentText}
</p>
</div>
)
}
}
export default Comment;
子组件ComentList.js
import React from "react"
class ComentList extends React.Component {
constructor(props) {
super(props);
this.state = ({
childText: "this is child text"
})
}
clickFun(text) {
this.props.pfn(text)//这个地方把值传递给了props的事件当中
}
render() {
return (
<div className="list">
<ul>
{
this.props.arr.map(item => {
return (
<li key={item.userName}>
{item.userName} 评论是:{item.text}
</li>
)
})
}
</ul>
//通过事件进行传值,如果想得到event,可以在参数最后加一个event,这个地方还是要强调,this,this,this
<button onClick={this.clickFun.bind(this, this.state.childText)}>
click me
</button>
</div>
)
}
}
export default ComentList;
最后想说一点,如果嵌套的父子组件很深好几层,这个时候我想你应该考虑用状态管理工具redux了