# react项目记录
react
我们项目目前使用的react脚手架是create-react-app,官方脚手架,基本配置依赖已经完成,只需要下载安装我们接下来项目所需要的别的依赖包就可以了,create构建项目过程:
安装
- 安装nodejs npm 基础环境
- 运用npm 安装create-react-app
- 利用create-react-app构建项目
- 启动项目
- npm install -g create-react-app
- create-react-app my-app
- cd my-app
- my-app start
我本地现在用的是webstorm来启动工程,直接在webstrom的终端输入
npm start 就可以启动项目,启动成功之后浏览器会自动打开,如果端口占用,会提示切换到端口+1的端口,如,3001;每一次修改工程中的代码,都会自动刷新页面。
项目启动后,进入工程,查看src文件夹中的index.js,index.js为工程的入口文件,组件命名全部以.js为后缀。所用到的依赖包,都在package.json中有版本信息,新增依赖包,通过npm install --save xxx 来添加
代码书写方法
import React,{Component} from 'react';
import {Layout,BackTop} from 'antd'
import './index.css';
import Footer from '../common/bottom'
import Head from "./header";
const { Sider,Content} = Layout;
class Container extends Component{
render() {
return (
);
}
}
export default Container;
在编写组件时,必须引入react依赖。其余的是我们需要什么才引入什么,如,Head,Footer这都是我们在页面上需要展示的组件,通过ES6的语法糖import引入,来按需加载。
一个组件的js文件中,必须有的是
import React,{Component} from 'react';
class Container extends Component{
render() {
return (
);
}
}
export default Container;
这是基本结构。也可以是这样的形式
import React,{Component} from 'react';
export default class Bottom extends React.Component{
render() {
return (
);
}
}
我们一般编写代码是在开发环境,代码部署到服务器时都是运用的自动构建工具,将代码自动打包,转化之后的代码,我们叫产品环境。
用npm run build 命令打包
需要先修改package.json文件,添加上这个,来解决路径问题,之后再执行run build 命令
"homepage": ".",
打包之后的文件,在工程中的build文件夹中,进入build文件夹,双击index.html就可以看到我们之前编辑的页面。
用npm run eject 实现弹射,自定义我们自己的需求
run eject 命令是一个不可逆的操作,但是eject只是将webpack的一些配置文件弹射出来,让我们来改变配置文件,实现我们自己需要的功能配置,eject之后,工程中就会多出来两个文件就夹,一个是scripts,还有一个是config文件夹,我们在这次的项目中只是修改了三个地方。
1.paths.js 文件
function getServedPath(appPackageJson) {
const publicUrl = getPublicUrl(appPackageJson);
const servedUrl =
envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : './');
return ensureSlash(servedUrl, true);
}
这个地方修改的是将pathname:'/',修改为'./';
appBuild: resolveApp('dashboard'),
这个地方修改的是将原来的resolveApp('build')替换成了dashboard,目的是执行完build命令之后将build文件夹的名字换为dashboard;
2.webpack.config.dev.js 文件
修改这个文件的目的是让其能够将antd框架中的组件实现按需加载,避免全部加载过大,影响渲染速度,修改之后,需要重启才能看到生效,未修改之前项目页面的debug会有一个错误提示信息。
loader: require.resolve('babel-loader'),
options: {
plugins: [
['import', [{ libraryName: 'antd', style: 'css' }]],
],
cacheDirectory: true,
},
做的修改是在options中直接加上
plugins: [
['import', [{ libraryName: 'antd', style: 'css' }]],
],
3.webpack.config.prod.js 文件
这个文件的修改跟dev文件的修改是一样的,也是在bable-loader直接添加上
plugins: [
['import', [{ libraryName: 'antd', style: 'css' }]],
],
以上基本项目安装及配置
基础语法
初始化及周期函数
componentDidUpdate //界面刷新调用,钩子函数
componentDidMount //刚进入界面时候调用,钩子函数
constructor(props) {
super(props);//初始化state
}
componentWillUnmount() {
}//界面渲染结束后,一般我们在这个函数中来清除定时器,钩子函数
我们一般是通过this.state来进行初始化赋值
constructor(props){
super(props)
this.state = {
theme: 'light',
current: 'home',
mode: 'horizontal',
username:'Logon',
flags:true,
linkData:[],
ITCODEtips:''
}
}
static defaultProps = {
className: "layout",
isDraggable: true,
isResizable: true,
items: 3,
rowHeight: 115,
margin:[15,30],
onLayoutChange: function() {},
cols: {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2},
initialLayout: function () {}
};
样式
- 可以通过引入样式文件
import './index.css';
- 可以在组件内写样式,不过这里一切皆对象,在样式表文件中的border-right写法要转换成驼峰是写法borderRight,多个样式以逗号隔开, 在react中class要写成className
***
***
- 可以通过在上面定义样式,引入到行内
let backAndTextColor = {
backgroundColor:'red',
color:'white',
fontSize:40
};
***
图片引入
import logo from '../imgs/logo_red.png'
背景图片
图标引入
我们项目中送到的图标有两种,一种是直接在antd框架中的图标,一种是我们自定义的图标,由iconfont.com生成的字体图标
1.antd框架中的图标引用方法
import {Menu,Icon,Switch} from 'antd'
{subMenu.name}
type中写的就是我们需要的图标类型
2.我们自定义的图标引用方法
import '../fonts/iconfont.css'
只需在 i 标签中添加上两个类,iconfont(图标基本样式) 和 icon-lianjie (图标类型)
修改值
我们不能直接修改State的值,要通过修改setState的值来实现改变值
如:
constructor(props) {
super(props)
this.state = {
timer: 0
}
}
tick = () => {
this.setState({ timer:this.state.timer + 1 });
}
我们经常在代码中使用三元运算来进行简单的状态切换
changeTheme = (value) => {
this.setState({
theme: value ? 'dark' : 'light',
});
}
传值
{cardsmenu}这里的cardsmenu 是一个数组
cardsmenu是个属性(就跟我们在原来html中设置 data-id差不多),在CardsLayout中调用改数组的值通过props来调用
constructor(props){
super(props)
this.state={
cardsmenu:props.cardsmenu,
}
}
就是这样的用法,props.cardsmenu来调用之前我们赋予他的数组
函数
我们在项目中写函数方法的方式有
1. 箭头函数
handleClick = (e) => {
if(e.key==="logOut"){
this.setState({
current: 'home',
});
}
}
2.普通函数
handleClick(){
loginState(this)
LinkData(this)
}
3.写在render外面的函数
function loginState(){}
遍历取值
我们项目中主要使用的遍历方法是通过map来遍历
{linkItem.list.map(menulist =>(
{menulist.name}
))}
要注意的是,每个遍历出来的对象都要有一个你能够唯一识别的key,从而实现哪个值变化了根据key来加载改变的值,避免重复渲染,提高渲染速度。
fetch数据
我们之前都是用ajax来获取服务端的数据,进行数据交互,现在我们用的是fecth来获取数据
首先要做的就是在install fetch依赖包,我们项目上使用的是 fetch和whatwg-fetch
function LinkData(e){
fetch('http://ludp.lenovo.com/ludp/api/quicklinks/')
.then(function(response) {
return response.json();
})
.then(function(json) {
e.setState({
linkData:json
})
})
.catch(function(error) {
console.log('Request failed', error)
});
}
项目框架
我们本次的项目框架是antd,首先要做的就是现在安装antd依赖包
npm install antd --save
npm install babel-plugin-import --save
安装好之后就可以按需加载antd了(前提是完成上面webpack的配置)
antd的用法
参考:https://ant.design/docs/react/introduce-cn
路由 react-router
我们在项目中现在使用的react-touter版本为v4,最新的,
在最新版本中我们是这样来设置我们的路由的
import {HashRouter} from 'react-router-dom'
import { Route } from 'react-router'
export default class Routes extends Component{
render(){
return(
)
}
}
我们运用的是hashRouter,这个是带有锚点的路由 http://localhost:3000/#/ ,
在我们本地环境中就可以直接通过路由跳转,如果我们使用browserRouter的话就需要配置服务器环境才能正常访问页面,所以我们暂时先采用的是hashRouter,另外我们所用到的路由方法一般都是从react-router-dom里面引用的。
import {Route} from 'react-router-dom'
export default class Contents extends React.Component {
render() {
return (
);
}
}
exact属性是严格匹配才会跳转,path就是我们的跳转路径,也就是链接后面的路径,component是跳转时要加载的组件,可以同时使用多个route
import {Link} from 'react-router-dom'
{subMenu.name}
我们在项目中的跳转都是通过Link组件来代替我们之前的a标签,to来制定跳转路径,这个只是需要我们用到路由跳转的是时候才会用,一般的跳转链接还是可以用 a 标签的。
主要依赖库 react-grid-layout
{
_.map(this.state.layouts, function (l) {
var i = l.adds ? '+' : l.i;
return (
{l.data.data!==undefined?
:}
X
)
})
}
在这个里面控制布局的区域大小的是breakpoints属性,里面的数值设置就是我们的区域大小
我们要做的就是将每一个子组件的位置设定好
layouts: _.values(props.cardsmenu).map(function (item) {
return {
data:item,
x: item.x,
y: item.y,
w: item.w,
h: item.h,
maxH:item.maxH,
i: item.i.toString(),
static: item.static,
components:item.components
};
}),
x,y,w,h是必须的,如果没有设置则都会在0,0的位置。
在组件中,通过下面的方式来根据屏幕节点的改变,实现自适应布局
onBreakpointChange = (breakpoint,cols) => {
this.setState({
currentBreakpoint: breakpoint,
cols: cols
});
};
onLayoutChange = (layout,layouts) => {
this.props.onLayoutChange(layout,layouts);
};
删除
onRemoveItem(i,data){
this.setState({
layouts:_.reject(this.state.layouts, {i: i}),
cardsmenu:this.state.cardsmenu.concat(data)
})
}
X
新增
onAddItem(newLayout) {
this.setState({
layouts: this.state.layouts.concat(newLayout),
newCounter: this.state.newCounter + 1,
adds:true
});
}
在AddList组件中的方法
ClickADD(data,i){
var Dragprama = document.getElementsByClassName('addListItem');
Dragprama[i].classList.add('ClikedItem');
var newLayout = {};
newLayout.data = data;
newLayout.x = (0+i)*3;
newLayout.y=1;
newLayout.w=3;
newLayout.h=1;
newLayout.static=false;
newLayout.maxH = 1;
newLayout.i = (4+i).toString();
newLayout.components=CardsListII;
this.props.onadd(newLayout);
}
{item.icon}
{item.text}
遗留问题
目前我只是实现了一个组件的两种样式的显示,可以增加和删除,现在删除之后可以在新增的列表中添加,但不还未实现去重。新增可以新增,但是在重新切换新增按钮之后,之前已经拖拽过的项状态没有保存下来.