本实文主要是用react+elementUI实现一个后台管理系统中最常见的功能,表格(增删改查、分页); 新增和修改弹窗是一个公共的子组件。接口是用node(express)实现,接口文章链接https://blog.csdn.net/CuiCui_web/article/details/107109689
1、 父组件中
先引入要使用的组件及方法
import React, { Component } from "react";
import axios from 'axios'; // 引入axios
import { Table,Button, MessageBox, Message, Pagination, Form, Input, Layout} from 'element-react';
import './table.scss' // 引入样式文件
编写table部分的代码以及数据定义
export default class table extends Component {
constructor(props) {
super(props);
this.state = {
// 表格的列
columns_student_info: [
{ label: "姓名", prop: "name",align:'center' },
{ label: "年龄", prop: "age",align:'center' },
{ label: "地址", prop: "address",align:'center' },
{ label: "操作", width:100, render: (row, column, index)=>{
return <span>
{/*<Button type="text" size="small" onClick={ this. }>查看</Button>*/}
<Button type="text" size="small" onClick={ this.updateClick.bind(this,row,index) }>编辑</Button>
<Button type="text" size="small" onClick={ this.deleteClick.bind(this,row,index) }>删除</Button>
</span>
}
}
],
students_list:[], // 表格数据
// 分页数据定义
page: {
pageSize: 5,
pageCurrent: 1,
total: 0,
},
form:{ // 查询条件
name: ''
}
}
}
}
/** 改变页大小方法 */
onSizeChange=(size)=>{
const page = Object.assign(this.state.page, { pageSize: size })
this.setState({
page: page
})
}
/** 改变当前是第几页 */
onCurrentChange=(current)=>{
const page = Object.assign( this.state.page, { pageCurrent: current })
this.setState({
page: page
})
}
// 查询条件数据实时更新
onChange(key, value) {
this.setState({
form: Object.assign(this.state.form, { [key]: value })
});
}
render() {
return (
<div className="table-demo">
<h2 >调用node编写接口数据</h2>
<div className="flex">
<div className="flex" style={{ width: "80%" }}>
<Form >
<Layout.Row gutter="20">
<Layout.Col span="16">
<Form.Item label="学生姓名" labelWidth="80">
<Input value={this.state.form.name} onChange={this.onChange.bind(this, 'name')}></Input>
</Form.Item>
</Layout.Col>
<Layout.Col span="8">
<Button style={{ height:"35px" }} type="primary" onClick={this.getData}>查询</Button>
</Layout.Col>
</Layout.Row>
</Form>
</div>
<Button style={{ height:"35px" }} type="primary" onClick={this.clicked}>新增</Button>
</div>
<Table
style={{ width:'100%' }}
height={200}
border
columns={ this.state.columns_student_info }
data={ this.state.list }
/>
<Pagination layout="total, sizes, prev, pager, next, jumper"
total={this.state.page.total}
pageSizes={[5,10,20]}
pageSize={ this.state.page.pageSize}
currentPage={this.state.page.pageCurrent}
onSizeChange={this.onSizeChange}
onCurrentChange={this.onCurrentChange}
/>
</div>
)
}
上述就是一个没有请求接口的表格数据,可以使用假数据查看效果。
2、 新增/编辑模块代码(子组件)
import React, { Component } from "react";
import {Dialog, Form, Input, Button} from 'element-react';
import './table.scss' // 引入样式文件
class addInfo extends React.Component {
constructor(props) {
super(props);
this.state = {
form: {
name:'',
age: '',
address:'',
id: ''
},
// 校验规则
rules: {
name: [
{ required: true, message:"请输入学生姓名", trigger: 'blur'}
],
age: [
{ required: false, message: "请输入学生年龄", trigger: 'blur' }
],
address: [
{ required: true, message: "请输入所有城市", trigger: 'blur' }
]
}
}
}
//监听组件传递的值:
componentWillReceiveProps(newProps)
{
if(newProps.formObj.id){
this.setState({
form: newProps.formObj
})
}
}
/** 确定按钮方法 */
handleSubmit=(e)=> {
e.preventDefault();
// 校验
this.refs.form.validate((valid) => {
if (valid) {
// 校验通过,通知父,在父中进行
this.props.toSubmit(this.state.form)
setTimeout(()=>{
this.refs.form.resetFields();
},1000)
} else {
console.log('error submit!!');
return false;
}
});
}
/** 取消按钮方法 */
handleReset=(e) =>{
e.preventDefault();
this.refs.form.resetFields();
// 通知父,父中操作取消
this.props.toReset()
}
onChange(key, value) {
this.setState({
form: Object.assign({}, this.state.form, { [key]: value })
});
}
render() {
return (
<Dialog
title={ this.props.title }
size="tiny"
visible={ this.props.dialogVisible }
onCancel={ this.handleReset }
lockScroll={ false }
style={{ padding: "20px" }}
>
<Form ref="form" model={ this.state.form } rules={ this.state.rules } labelWidth="80">
<Form.Item label="学生姓名" prop="name">
<Input value={ this.state.form.name } onChange={this.onChange.bind(this, 'name')}/>
</Form.Item>
<Form.Item label="学生年龄" >
<Input value={ this.state.form.age } onChange={this.onChange.bind(this, 'age')}/>
</Form.Item>
<Form.Item label="所在城市" prop="address">
<Input value={ this.state.form.address } onChange={this.onChange.bind(this, 'address')}/>
</Form.Item>
<div className="dialog-footer">
<Button type="primary" onClick={this.handleSubmit.bind(this)}>确定</Button>
<Button onClick={this.handleReset.bind(this)}>取消</Button>
</div>
</Form>
</Dialog>
)
}
}
export default addInfo;
注:
1、 弹窗中visible是通过this.props.dialogVisible
拿去父组件中设置的值,从而在父组件中控制这个值是true还是fasle; 标题也是同理,在父中进行改变,子直接使用即可this.props.title
2、类似vue中的$emit,react怎么将自己的事件以及数据给父,在父中执行呢?
this.props.toSubmit(this.state.form)
在父中,使用子组件的标签上直接绑定toSubmit方法即可
3、编辑弹窗与新增弹窗的区别就是判断id是否存在,在vue中,我们可以用watch监听;那么react中如何使用呢?
//监听组件传递的值:
componentWillReceiveProps(newProps)
{
if(newProps.formObj.id){
this.setState({
form: newProps.formObj
})
}
}
这个方法是判断,当id存在,就将组件传递来的值赋值给表单对象。
4、 弹窗x按钮方法直接调用取消方法onCancel={ this.handleReset }
3、父组件中使用弹窗(子组件的应用)
1、引入子组件
import AddInfo from './addInfo'
2、数据定义
constructor(props) {
super(props);
this.state = {
dialogVisible: false ,// 弹窗是否打开
title: '新增弹窗', // 新增弹窗,
formObj: {},
}
}
3、组件使用
render() {
return (
<div className="table-demo">
<AddInfo
title={ this.state.title }
formObj={ this.state.formObj }
dialogVisible={this.state.dialogVisible}
toSubmit={ this.submitClick }
toReset={ this.resetClick }/>
</div>
)
}
4、方法定义:
/** 查询接口 */
getData = () => {
axios({
url: 'http://localhost:3000/demo',
method: 'post',
data:{
pageSize: this.state.page.pageSize,
pageCurrent: this.state.page. pageCurrent,
name: this.state.form.name
}
})
.then((response) => {
console.log(response,'gggggggggggg')
const page = Object.assign( this.state.page, { total: response.data.total })
this.setState({
list: response.data.list,
page: page
})
})
.catch(function (error) {
console.log(error);
});
}
/** 会在组件已经渲染到Dom中后运行 */
componentDidMount(){
this.getData()
}
/** 组件卸载方法 */
componentWillUnmount(){
}
/** 新增按钮事件 */
clicked = ()=> {
this.setState({ dialogVisible: true,title: '新增信息' })
}
/** 编辑按钮事件 */
updateClick=(row)=>{
console.log(row)
if(row.id){
this.setState({
title: '修改信息',
dialogVisible: true
})
}
this.setState({
formObj: Object.assign({},row)
})
}
/** 弹窗确定按钮事件 */
submitClick=(val)=>{
console.log(val,'ggg')
// axios.post('http://localhost:3000/demo_add')
axios({
url: val.id? 'http://localhost:3000/demo_update': 'http://localhost:3000/demo_add',
method: 'post',
data:{
val
}
})
.then((response) => {
console.log(response)
Message({
type: 'success',
message: response.data
});
this.setState({ dialogVisible: false })
this.getData()
})
.catch(function (error) {
console.log(error);
});
}
/** 弹窗取消按钮事件 */
resetClick=()=>{
this.setState({ dialogVisible: false })
}
/** 删除按钮方法 */
deleteClick=(row,index)=>{
MessageBox.confirm('此操作将永久删除该文件, 是否继续?', '提示', {
type: 'warning'
}).then(() => {
axios({
url:'http://localhost:3000/demo_del',
method: 'delete',
data:{
id: row.id
}
})
.then((response) => {
Message({
type: 'success',
message: '删除成功!'
});
this.getData()
})
.catch(function (error) {
console.log(error);
});
}).catch(() => {
Message({
type: 'info',
message: '已取消删除'
});
});
}
/** 改变页大小方法 */
onSizeChange=(size)=>{
const page = Object.assign(this.state.page, { pageSize: size })
this.setState({
page: page
})
this.getData()
}
/** 改变当前是第几页 */
onCurrentChange=(current)=>{
const page = Object.assign( this.state.page, { pageCurrent: current })
this.setState({
page: page
})
this.getData()
}
注意:
1、 如何修改对象中一个属性值,利用es6语法
const page = Object.assign(this.state.page, { pageSize: size })
this.setState({
page: page
})
2、 类型vue中的生命周期方法,进入,即调接口渲染数据
/** 会在组件已经渲染到Dom中后运行 */
componentDidMount(){
this.getData()
}
最后贴上完整的父组件的代码:
import React, { Component } from "react";
import axios from 'axios'; // 引入axios
import { Table,Button,Dialog,MessageBox, Message, Pagination, Form, Input, Layout} from 'element-react';
import './table.scss' // 引入样式文件
import AddInfo from './addInfo'
export default class table extends Component {
constructor(props) {
super(props);
this.state = {
// 表格表头
columns_student_info: [
{ label: "姓名", prop: "name",align:'center' },
{ label: "年龄", prop: "age",align:'center' },
{ label: "地址", prop: "address",align:'center' },
{ label: "操作", width:100, render: (row, column, index)=>{
return <span>
<Button type="text" size="small" onClick={ this.updateClick.bind(this,row,index) }>编辑</Button>
<Button type="text" size="small" onClick={ this.deleteClick.bind(this,row,index) }>删除</Button>
</span>
}
}
],
students_list:[], // 表格数据
dialogVisible: false ,// 弹窗是否打开
title: '新增弹窗', // 新增弹窗,
formObj: {}, // 子组件表单数据
page: { // 分页
pageSize: 5,
pageCurrent: 1,
total: 0,
},
form:{ // 查询条件
name: ''
}
}
}
/** 查询接口 */
getData = () => {
axios({
url: 'http://localhost:3000/demo',
method: 'post',
data:{
pageSize: this.state.page.pageSize,
pageCurrent: this.state.page. pageCurrent,
name: this.state.form.name
}
})
.then((response) => {
const page = Object.assign( this.state.page, { total: response.data.total })
this.setState({
list: response.data.list,
page: page
})
})
.catch(function (error) {
console.log(error);
});
}
/** 会在组件已经渲染到Dom中后运行 */
componentDidMount(){
this.getData()
}
/** 组件卸载方法 */
componentWillUnmount(){
}
/** 新增按钮事件 */
clicked = ()=> {
this.setState({ dialogVisible: true,title: '新增信息' })
}
/** 编辑按钮事件 */
updateClick=(row)=>{
console.log(row)
if(row.id){
this.setState({
title: '修改信息',
dialogVisible: true
})
}
this.setState({
formObj: Object.assign({},row)
})
}
/** 弹窗确定按钮事件 */
submitClick=(val)=>{
console.log(val,'ggg')
// axios.post('http://localhost:3000/demo_add')
axios({
url: val.id? 'http://localhost:3000/demo_update': 'http://localhost:3000/demo_add',
method: 'post',
data:{
val
}
})
.then((response) => {
console.log(response)
Message({
type: 'success',
message: response.data
});
this.setState({ dialogVisible: false })
this.getData()
})
.catch(function (error) {
console.log(error);
});
}
/** 弹窗取消按钮事件 */
resetClick=()=>{
this.setState({ dialogVisible: false })
}
/** 删除按钮方法 */
deleteClick=(row,index)=>{
MessageBox.confirm('此操作将永久删除该文件, 是否继续?', '提示', {
type: 'warning'
}).then(() => {
axios({
url:'http://localhost:3000/demo_del',
method: 'delete',
data:{
id: row.id
}
})
.then((response) => {
Message({
type: 'success',
message: '删除成功!'
});
this.getData()
})
.catch(function (error) {
console.log(error);
});
}).catch(() => {
Message({
type: 'info',
message: '已取消删除'
});
});
}
/** 改变页大小方法 */
onSizeChange=(size)=>{
const page = Object.assign(this.state.page, { pageSize: size })
this.setState({
page: page
})
this.getData()
}
/** 改变当前是第几页 */
onCurrentChange=(current)=>{
const page = Object.assign( this.state.page, { pageCurrent: current })
this.setState({
page: page
})
this.getData()
}
onChange(key, value) {
this.setState({
form: Object.assign(this.state.form, { [key]: value })
});
}
render() {
return (
<div className="table-demo">
<h2 >调用node编写接口数据</h2>
<div className="flex">
<div className="flex" style={{ width: "80%" }}>
<Form >
<Layout.Row gutter="20">
<Layout.Col span="16">
<Form.Item label="学生姓名" labelWidth="80">
<Input value={this.state.form.name} onChange={this.onChange.bind(this, 'name')}></Input>
</Form.Item>
</Layout.Col>
<Layout.Col span="8">
<Button style={{ height:"35px" }} type="primary" onClick={this.getData}>查询</Button>
</Layout.Col>
</Layout.Row>
</Form>
</div>
<Button style={{ height:"35px" }} type="primary" onClick={this.clicked}>新增</Button>
</div>
<Table
style={{ width:'100%' }}
height={200}
border
columns={ this.state.columns_student_info }
data={ this.state.list }
/>
<Pagination layout="total, sizes, prev, pager, next, jumper"
total={this.state.page.total}
pageSizes={[5,10,20]}
pageSize={ this.state.page.pageSize}
currentPage={this.state.page.pageCurrent}
onSizeChange={this.onSizeChange}
onCurrentChange={this.onCurrentChange}
/>
<AddInfo
title={ this.state.title }
formObj={ this.state.formObj }
dialogVisible={this.state.dialogVisible}
toSubmit={ this.submitClick }
toReset={ this.resetClick }/>
</div>
)
}
}
样式文件代码:
.table-demo{
h2{
margin-bottom:10px;
&:not(:first-child){
margin-top:20px;
}
}
.flex-end{
display: flex;
justify-items: end;
justify-content: flex-end;
padding:0px 0 10px;
}
/deep/.el-dialog__header{
padding:0 0 10px !important;
margin-bottom:20px;
border-bottom:1px solid #ddd;
}
.dialog-footer{
display: flex;
justify-content: flex-end;
}
.flex{
display: flex;
justify-content: space-between;
}
}