1.配置环境和初始化
2.下载antd
cnpm install antd --save
引入antd及其样式
import {Button} from 'antd';
import 'antd/dist/antd.css';
推荐一个图标网站:https://www.iconfinder.com/
推荐一个将html转化成jsx的网站:https://magic.reactjs.net/htmltojsx.htm
遇到的问题:
webpack-dev-server不能自动刷新:
1.webpack-dev-server并不能读取你的webpack.config.js的配置output!!
你在webpack.config.js里面的配置output属性是你用webpack打包时候才起作用的,对webpack-dev-server并不起作用
2.webpack-dev-server打包生产的文件并不会添加在你的项目目录中!!
它默认打包的文件名是bundle.js, webpack4.x默认打包的文件名是 main.js,不会真的出现在你的项目目录中,打包路径由你的contentBase决定!保存在内存中。
webpack-dev-server
为了加快打包进程是将打包后的文件放到内存中的,所以我们在项目中是看不到它打包以后生成的文件/文件夹的,但是,这不代表我们就不用配置路径了,配置过webpack.config.js
的小伙伴都知道output.path
这个参数是配置打包文件的保存路径的,contentBase
就和output.path
是一样的作用,如果不配置这个参数就会打包到项目的根路径下。
图片路径问题:
在写路径时,要相对于index.html文件
类样式无效:
在react中要用className来设置css样式,不能用class,如果要使用class,必须下载插件
cnpm install --save-dev babel-plugin-react-html-attrs
然后再编辑.babelrc文件
{
"plugins": [
"react-html-attrs"
]
}
也可以不用编辑.babelrc文件,通过 package.json 使用 .babelrc
{
"name": "my-package",
"version": "1.0.0",
"babel": {
// my babel config here
}
}
因此webpack.json中的babel属性中,plugins数组中添加"react-html-attrs"
"babel": {
"presets": [
"env",
"react"
],
"plugins": [
"react-html-attrs"
]
},
<BrowserRouter>标签中有且只有一个子标签,<Link></Link> <Route></Route>必须用同一个<BrowserRouter></BrowserRouter>包裹起来,且不能嵌套BrowserRouter。
使用BrowserRouter路由器刷新页面时找不到资源,如果<Link to='./details' target="_blank">有target="_blank",BrowserRouter打开一个新的窗口时,找不到资源,图片的路径也会发生变化,例如:图片在./src/images/logo.png,打开链接时,路径变成.details/src/images/logo.png,这样就找不到图片资源了。
解决BrowserRouter带来的这些问题,只要用BrowserRouter就可以了。
在模块中引入css文件,webpack打包后,在html文件的head标签的<style></style>中,所以在pc端和移动端css样式名字不能相同,如果使用less嵌套方式写css,就可以轻松避免这种现象。
要兼容PC和移动端需要下载响应式插件react-responsive
cnpm install react-responsive --save
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import PCIndex from './components/pc_index';
import MobileIndex from './components/mobile_index';
import MediaQuery from 'react-responsive';
export default class Root extends React.Component {
render() {
return (
<div>
<MediaQuery query='(min-device-width: 1224px)'>
<PCIndex/>
</MediaQuery>
<MediaQuery query='(max-device-width: 1224px)'>
<MobileIndex/>
</MediaQuery>
</div>
);
};
}
ReactDOM.render(
<Root/>, document.getElementById('test'));
pc_index.js
import React from 'react';
import PCHeader from './pc_header';
import PCFooter from './pc_footer'
export default class PCIndex extends React.Component {
constructor() {
super();
}
render() {
return (
<div>
<PCHeader/>
<PCFooter/>
</div>
);
};
}
pc_header.js
import React from 'react';
import { Row, Col } from 'antd';
import { Menu, Icon } from 'antd';
const SubMenu = Menu.SubMenu;
const MenuItemGroup = Menu.ItemGroup;
export default class PCHeader extends React.Component {
constructor() {
super();
this.state = {
current:"top",
};
}
render() {
return (
<header>
<Row>
<Col span={2}></Col>
<Col span={4}>
<a href="/" className="logo">
<img src="./src/images/logo.png" alt="logo"/>
<span>ReactNews</span>
</a>
</Col>
<Col span={16}>
<Menu mode="horizontal" selectedKeys={[this.state.current]}>
<Menu.Item key="top">
<Icon type="appstore" />头条
</Menu.Item>
<Menu.Item key="shehui">
<Icon type="appstore" />社会
</Menu.Item>
<Menu.Item key="guonei">
<Icon type="appstore" />国内
</Menu.Item>
<Menu.Item key="guoji">
<Icon type="appstore" />国际
</Menu.Item>
<Menu.Item key="yule">
<Icon type="appstore" />娱乐
</Menu.Item>
<Menu.Item key="tiyu">
<Icon type="appstore" />体育
</Menu.Item>
<Menu.Item key="keji">
<Icon type="appstore" />科技
</Menu.Item>
<Menu.Item key="shishang">
<Icon type="appstore" />时尚
</Menu.Item>
</Menu>
</Col>
<Col span={2}></Col>
</Row>
</header>
);
};
}
pc_footer.js
import React from 'react';
import {Row, Col} from 'antd';
export default class PCFooter extends React.Component {
render() {
return (
<footer>
<Row>
<Col span={2}></Col>
<Col span={20} className="footer">
© 2017 ReactNews. All Rights Reserved.
</Col>
<Col span={2}></Col>
</Row>
</footer>
);
};
}
mobile_index.js
import React from 'react';
import MobileHeader from './mobile_header';
import MobileFooter from './mobile_footer';
export default class MobileIndex extends React.Component {
render() {
return (
<div>
<MobileHeader/>
<MobileFooter/>
</div>
);
};
}
mobile_header.js
import React from 'react';
export default class MobileHeader extends React.Component {
render() {
return (
<div id="mobileheader">
<header>
<img src='./src/images/logo.png' alt="logo"/>
<span>ReactNews</span>
</header>
</div>
);
};
}
mobile_footer.js
import React from 'react';
import {Row, Col} from 'antd';
export default class MobileFooter extends React.Component {
render() {
return (
<footer>
<Row>
<Col span={2}></Col>
<Col span={20} className="footer">
© 2017 ReactNews. All Rights Reserved.
</Col>
<Col span={2}></Col>
</Row>
</footer>
);
};
}
pc.css
.logo{
align-items: center;
display: flex;
}
.logo img{
width: 48px;
height: 48px;
}
.logo span{
font-size: 24px;
padding-left: 5px;
}
.footer{
text-align: center;
}
mobile.css
html{
font-size: 50px;
}
#mobileheader{
flex: 1;
background: #f6f6f6;
}
#mobileheader header{
border-bottom: 1px solid #2db7f5;
padding-left: 10px;
}
#mobileheader header img{
height: 50px;
}
#mobileheader header span{
font-size: 35px;
vertical-align: top;
padding-left: 5px;
color: #2db7f5;
}
知识点:
自动登录:通过componentWillMount(),来判断localStorage.userid是否存在进行登录
localStorage有效期是永久,作用域是同一个浏览器且必须是同源,即协议、主机名以及端口三者必须相同。
在360浏览器中,http://localhost:8090/#/的控制台中输入localStorage.userid显示Jack
在360浏览器中,其他网页的控制台中输入localStorage.userid显示undefined
在Firefox浏览器中,http://localhost:8090/#/的控制台中输入localStorage.userid显示undefined
在360浏览器和谷歌浏览器中都是登录状态,在谷歌浏览器中退出账户并刷新页面,是未登录状态,此时刷洗360浏览器的页面,刷新后还是登录状态,不同浏览器之间的localStorage是不能共享的。
结论:localStorage的作用域必须是同一个浏览器且必须同源。