跟着做react项目(至P93)

导航

  • 富文本编辑器组件
  • add-update.jsx 提交表单事件
  • 角色管理
    • Table表格
      • 可选择的表格(Antd)
      • Table的onRow
      • Tree树形控件
    • 可选择表格(部分)代码
    • Tree树形控件 antd4.x版

富文本编辑器组件

react-draft-wysiwyg github作者
组件demo

admin.jsx 后台管理的路由组件

原来设置height: ‘100%’, 由于富文本组件太大,会覆盖footer组件。所以改为最小高度minHeight

<Layout style={{ minHeight: '100%' }}>

1.初始化商品描述需要将html格式字符串转为富文本格式。文档的最下面
在这里插入图片描述
2.编辑器显示图片。文档最下面
在这里插入图片描述
得到图片怎么展示到编辑器
跟着做react项目(至P93)_第1张图片

uploadImageCallBack函数,两个功能(上传图片,在编辑器展示图片)

xhr.open("POST", "/manage/img/upload"); // 请求地址
const data = new FormData();
data.append("image", file); //请求参数名
xhr.send(data);
xhr.addEventListener("load", () => {
    const response = JSON.parse(xhr.responseText); // 后台响应数据
    let url = response.data.url; //图片地址
    resolve({ data: { link: url } });
});

结果图:
跟着做react项目(至P93)_第2张图片

<Item
    label="商品详情"
    labelCol={{ span: 2 }}
    wrapperCol={{ span: 20 }}
>
    <RichTextEditor ref={this.editor} detail={product.detail} />
</Item>

add-update.jsx 提交表单事件

1.接口请求函数
2.收集数据
3.根据结果提示信息

onFinish = async (values) => {
     const imgs = this.pw.current.getImgs()
     const detail = this.editor.current.getDetail()
     const { name, desc, price, categoryIds } = values
     let pCategoryId = '', categoryId = ''
     if (categoryIds.length === 1) {
         pCategoryId = '0'
         categoryId = categoryIds[0]
     } else {
         pCategoryId = categoryIds[0]
         categoryId = categoryIds[1]
     }
     const product = { name, desc, price, pCategoryId, categoryId, detail, imgs }
     if (this.isUpdate) {
         product._id = this.product._id
     }
     // 发生请求
     const result = await reqAddOrUpdateProduct(product)
     if (result.status === 0) {
         message.success(`${this.isUpdate ? '更新' : '添加'}商品成功`)
         this.props.history.goBack()
     } else {
         message.error(`${this.isUpdate ? '更新' : '添加'}商品失败`)
     }
 }

角色管理

用户归属于一种角色,每种角色能看到的菜单栏不一样。也可以说角色用来限制用户的功能。

roles数据库
跟着做react项目(至P93)_第3张图片

Table表格

期望的静态页面
在这里插入图片描述
控制变量,this.state。role实际指向roles中的某个元素,所以修改role对象的属性值,roles的该元素也会变。

state = { 
	roles: [], // 所有角色的列表 
	role: {}, // 选中的 role
}

可选择的表格(Antd)

在这里插入图片描述

第一列是联动的选择框。可以通过 rowSelection.type 属性指定选择类型,默认为 checkbox。
跟着做react项目(至P93)_第4张图片

数组的原因是,有可能是多选框。数组的元素就 决定 哪些行被选中。
在这里插入图片描述

Table的onRow

期望不是点击按钮才处于选中状态,而不是点击该行容易地方都选择按钮。

onRow: 设置行属性
onRow的值为函数,函数返回一个对象,对象的属性为不同的事件处理函数。
跟着做react项目(至P93)_第5张图片

通过点击事件,拿到被选中的行数据,更新this.state.role。设置selectedRowKeys数组,Table展现哪行被选中。


知识点一:
注意空对象也是true

a = {}
if(a) //true

知识点二:
地址(引用)没变,react建议不要直接修改数据

const roles = this.state.roles // 不建议
roles.push(role)
this.setState({roles})

跟着做react项目(至P93)_第6张图片
知识点三:
render: (create_time) => formateDate(create_time)
可以简写成
render: formateDate


Tree树形控件

antd 4.x 比 3.x简洁 很多回调函数需要自己去测试,在知道具体的参数代表什么。

onCheck = (checkedKeys) => {
    console.log("onCheck", checkedKeys);
}

跟着做react项目(至P93)_第7张图片
在这里插入图片描述


只是在第一次构建AuthForm组件时,state记录了这次传过来的menus。如果后续再点击时,新的role就没有更新state状态数据了。

constructor(props) {
    super(props)
    // 根据传入角色的 menus 生成初始状态
    const { menus } = this.props.role
    this.state = {
        checkedKeys: menus,
    };
    this.treeData = menuConfig
}

之前为了解决情况表单,我们使用了Modal组件的destroyOnClose={true} 属性,删除了子元素。

方法二:
利用生命周期钩子,该方法第一次渲染组件不会调用。当父组件render导致子组件第二次渲染时,就会调用。nextProps接收新的props数据。

因为属于生命周期的流程,所以可以任性地直接修改state状态数据。
跟着做react项目(至P93)_第8张图片


可选择表格(部分)代码

selectedRowKeys: [role._id] 用一个数组(元素为每行的主键,key)来决定哪行代表选中状态。

而选中的这行数据,主要通过state状态数据进行存储。

所以给我们一个假象是:点击选中这行就能直接传数据给子组件

    onRow = (record) => {
        return {
            onClick: event => {
                this.setState({ role: record })
            },
        }
    }

    selected = (record, selected) => {
        // console.log(selected)
        if (selected) {
            this.setState({ role: record })
        } else { // 复选框才能打击取消选择
            this.setState({ role: {} })
        }
    }
	render() {
        const { roles, role, isShowAdd, isShowAuth } = this.state
        return (
            <Card title={title}>
                <Table bordered
                    rowKey='_id'
                    dataSource={roles}
                    columns={this.columns}
                    pagination={{ defaultPageSize: PAGE_SIZE }}
                    rowSelection={{
                        type: 'radio',
                        selectedRowKeys: [role._id],
                        onSelect: this.selected
                    }}
                    onRow={this.onRow}
                />
                <Modal title="添加角色" visible={isShowAdd}
                    onCancel={() => {
                        this.setState({ isShowAdd: false })
                    }}
                    onOk={this.addRole}
                    destroyOnClose={true}
                >
                    <AddForm
                        setForm={form => this.form = form}
                    />
                </Modal>

                <Modal title="设置角色权限" visible={isShowAuth}
                    onOk={this.updateRole}
                    onCancel={() => {
                        this.setState({ isShowAuth: false })
                        // this.form.current.resetFields()
                    }}
                    destroyOnClose={true}
                >
                    <AuthForm ref={this.auth} role={role} />
                </Modal>
            </Card>
        )
    }

Tree树形控件 antd4.x版

checkedKeys={checkedKeys} 这里也是靠一个数组(元素为每个节点的key)来决定哪些节点处于选中状态。

注意,如果父节点的所有子节点被选中,父节点的key也会存在checkedKeys,但只要一个子节点未选中,就不包含父节点的key

export default class AuthForm extends Component {
    static propTypes = {
        role: PropTypes.object.isRequired,
    };

    constructor(props) {
        super(props)
        // 根据传入角色的 menus 生成初始状态
        const { menus } = this.props.role
        this.state = {
            checkedKeys: menus,
        };
        //菜单栏数组,元素为对象,包含title,key,children即可代表树形结构
        this.treeData = menuConfig 
    }

    // 为父组件提供最新 menus 数据的方法
    getMenus = () => this.state.checkedKeys

    // 点击复选框触发
    onCheck = (checkedKeys) => {
        console.log("onCheck", checkedKeys);
        this.setState({ checkedKeys })
    }

    render() {
        const { role } = this.props
        const { checkedKeys } = this.state

        const formItemLayout = {
            labelCol: { span: 4 }, //左侧label宽度
            wrapperCol: { span: 15 }, //右侧包裹输入框宽度
        };

        return (
            <div>
                <Item {...formItemLayout} label='角色名称'>
                    <Input value={role.name} disabled />
                </Item>
                <Tree
                    checkable
                    defaultExpandAll={true}
                    checkedKeys={checkedKeys}
                    onCheck={this.onCheck}
                    treeData={this.treeData}
                />
            </div>
        )
    }
}

跟着做react项目(至P93)_第9张图片
想着用新生命周期钩子代替,但不行,因为
在这里插入图片描述
而树形控件,有时需要传过来的props决定,有时有state决定。

你可能感兴趣的:(前端项目,react.js,javascript,前端)