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

本实文主要是用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;
  }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值