react初体验之表格增删改查,新增与编辑为公共的弹窗组件(父子组件传值,修改数据)

    技术2023-10-14  93

    本实文主要是用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; } }
    Processed: 0.017, SQL: 9