antd design pro前端填坑笔记

antd design pro前端填坑笔记

  • 1、react组件调用dispatch页面不渲染
  • 2、github/gitlab 拉取合并请求代码
      • 修改别人提交的代码(合并和修改commit)
      • 暂存区处理
  • 3、组件样式覆盖
  • 4、不同命名空间组件相互调用
  • 5、antd 组件图片模拟上传测试
    • index.jsx文件
    • style.less文件
    • 全局mock文件
  • 6、自定义可编辑单元格组件不渲染问题
  • 7、自定义表格最后一行渲染
  • 挖坑,填坑持续更新中。。。
  • 同时也希望大家留言评论。。。
  • 干了这碗酒
      • 寄语
      • 主页

1、react组件调用dispatch页面不渲染

state参数是引用类型,如果直接返回state,dva会认为没有修改state,所以不会刷新
建议

return {...state}

2、github/gitlab 拉取合并请求代码

通过git拉取github/gitlab上的Pull Request(PR)/Merge Request(MR)到本地进行code review
Github:
git fetch origin pull/3188/head:pr3188
3188PR的id
https://github.com/apache/carbondata/pull/3188

Gitlab:
git fetch remote merge-requests/MERGE_REQUEST_ID/head:BRANCH_NAME

修改别人提交的代码(合并和修改commit)

1、合并commit

git rebase -i  COMMIT_ID(修改的上一个ID)

2、修改最后提交的commit

git commit --amend 修改最后提交的commit

3、代码回退
a) 在未add之前,直接git checkout file_name即可;
b)在提交之后,通过git reset --hard commit_id即可

暂存区处理

1、git stash
这个指令会把所有未提交的修改都保存起来。
2、git stash pop
将缓存堆中的第一个stash删除,并将对应修改应用到当前目录下。
3、git stash apply
将指定缓存堆栈中的stash应用到工作目录中,默认是 stash@{0},但并不会删除stash拷贝
4、git stash drop
删除指定的stash
5、git stash list
查看所有的暂存区
6、git stash clear
清除所有的暂存区
7、git stash show
查看stash修改情况,默认为stash@{0},加-p查看特定stash的全部diff,
8、git stash branch + 分支名
如果你储藏了一些工作,暂时不去理会,然后继续在你储藏工作的分支上工作,你在重新应用工作时可能会碰到一些问题。如果尝试应用的变更是针对一个你那之后修改过的文件,你会碰到一个归并冲突并且必须去化解它。如果你想用更方便的方法来重新检验你储藏的变更,你可以运行 git stash branch,这会创建一个新的分支,检出你储藏工作时的所处的提交,重新应用你的工作,如果成功,将会丢弃储藏。

3、组件样式覆盖

对组件添加一层div标签,并将组件样式写在div样式里面,防止样式全局污染,例如,Input` 自带的类名为 input-style,定义新的类名在div上,这会覆盖div内部Input样式

// Input 组件
import styls from './input.less'
<div className={style["input-bx"]}>
<Input/>
</div>
.input-box :global{
	.input-style{
    	background-color: pink;
    }
}

4、不同命名空间组件相互调用

对于不同命名空间的组价调用,会报错找不到命名空间,出现这种问题的原因是model service mock 不是全局的,将组件下面的这三个文件分别剪切放在全局的三个文件夹中即可。

5、antd 组件图片模拟上传测试

直接上代码,主要参考antd组件上传图片代码API

index.jsx文件

import React, {useState, useEffect} from 'react';
import request from "@/utils/request";
import {EyeOutlined, DeleteOutlined, PlusOutlined} from '@ant-design/icons';
import {Upload, Button, Modal, message} from 'antd';
import styles from './style.less';

const getBase64 = (file) => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = error => reject(error);
  });
}

const maxNum = 8;

const Avatar = props => {
  const [fileList, setFileList] = useState([]);
  const [showImg, setShowImg] = useState([]);
  const [previewVisible, setPreviewVisible] = useState(false);
  const [uploading, setUploading] = useState(false);
  const [previewImage, setPreviewImage] = useState("");
  const [previewTitle, setPreviewTitle] = useState("");

  useEffect(() => {
    getImgAll();
  }, []);

  // 获取图片
  const getImgAll = () => {
    request(`/api/sys/img/get`, {
      method: 'POST',
    }).then(res => {
      if (res.status === 'ok') {
        setShowImg(res.data);
      } else {
        message.error("获取图片失败!")
      }
    }).catch(err => {
      throw err;
    })
  }

  // 开始上传图片
  const handleUpload = async (e) => {
    e.stopPropagation();
    setUploading(true);

    for (let i = 0; i < fileList.length; i++) {
      fileList[i] = {
        lastModified: fileList[i].lastModified,
        name: fileList[i].name,
        size: fileList[i].size,
        type: fileList[i].type,
        uid: fileList[i].uid,
        webkitRelativePath: fileList[i].webkitRelativePath,
        url: await getBase64(fileList[i].originFileObj)
      };
    }
    request(`/api/sys/img/upload`, {
      method: 'POST',
      data: fileList,
    }).then(res => {
      setUploading(false);
      setFileList([]);
      message.destroy();
      message.success({content: '上传成功.', duration: 1, onClose: () => getImgAll()});
    }).catch(err => {
      setUploading(false);
      message.destroy();
      message.error('上传失败.');
    })
  }

  //删除已经上传图片
  const onRemoveImg = file => {
    message.destroy();
    request(`/api/sys/img/delete`, {
      method: 'POST',
      data: file,
    }).then(res => {
      if (res.status === 'ok') {
        getImgAll();
        message.info("删除成功!");
      } else {
        message.error("删除失败!")
      }
    }).catch(err => {
      throw err;
    })
  }
  // 删除未上传图片
  const onRemove = file => {
    const index = fileList.indexOf(file);
    const newFileList = fileList.slice();
    newFileList.splice(index, 1);
    setFileList(newFileList);
  }

  const handlePreview = async file => {
    if (!file.url && !file.preview) {
      file.preview = await getBase64(file.originFileObj);
    }
    setPreviewImage(file.url || file.preview);
    setPreviewVisible(true);
    setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1));
  };

  const ImgBox = props => {
    const {file} = props;
    return (
      <div className={styles["gl-box"]}>
        <img className={styles["gl-img"]} src={file.url} alt=""/>
        <div className={styles["img-box"]}>
          <EyeOutlined onClick={() => handlePreview(file)} className={styles["gl-icon"]}/>
          <DeleteOutlined onClick={() => onRemoveImg(file)} className={styles["gl-icon"]}/>
        </div>
      </div>
    )
  };

  return (
    <div>
      <div key="img-box">
        {
          showImg.map((i, j) => <ImgBox key={j} file={i}/>)
        }
      </div>
      {
        showImg.length >= maxNum ?  `文件仅支持上传${maxNum}张图片,若更改请删除后重新上传。` :
          (<Upload
            onRemove={(file) => onRemove(file)}
            beforeUpload={(file) =>false}
            fileList={fileList}
            listType="picture-card"
            onPreview={(file) => handlePreview(file)}
            onChange={(info) => {
              if (info.fileList.length + showImg.length > maxNum) {
                message.destroy();
                message.warning(`仅支持上传${maxNum}张图片`)
              }
              setFileList(info.fileList.splice(0,maxNum-showImg.length));
            }}
          >
            <div><PlusOutlined/></div>
            <Button
              size={"small"}
              type="primary"
              onClick={(e) => handleUpload(e)}
              disabled={fileList.length === 0}
              loading={uploading}
              style={{position: "relative", bottom: -20}}
            >
              {uploading ? '...' : '上传'}
            </Button>
          </Upload>)}

      <Modal
        visible={previewVisible}
        title={previewTitle}
        footer={null}
        onCancel={() => setPreviewVisible(false)}
      >
        <img alt="example" style={{width: '100%'}} src={previewImage}/>
      </Modal>

    </div>
  );
}


export default Avatar;

style.less文件


.gl-box{
  display:inline-block;
  height: 105px;
  width: 105px;
  border:1px solid #eee;
  margin: 5px;
  overflow: hidden;
  text-align: center;
}
.gl-icon{
  font-size:16px;
  color:#eee;
  margin: 0 5px;
}

.gl-img{
  height: 104px;
  width: 104px;
  z-index:1;
  cursor: pointer;

}
.img-box {
  height: 104px;
  width: 104px;
  position: relative;
  line-height: 104px;
  bottom: 0;
  z-index: 2;
  background-color: rgba(0, 0, 0, 0.5);
  vertical-align: middle;
}

.gl-box:hover{
  .img-box{
    transition: all .3s ease;
    transform: translateY(-104px);
  }
}

全局mock文件

(放在全局mock文件里面即可)
img.js

let imgList = [
  {
    url:'https://i01piccdn.sogoucdn.com/905894db522971e6',
    lastModified: 1591877022945,
    name: "direwolf.jpg",
    size: 41033,
    type: "image/jpeg",
    uid: "rc-upload-1592210832893-2",
    webkitRelativePath: "",
  },
]
const imgData = (req, res) => {
  imgList = imgList.concat(req.body);//imgList=[...imgList,...req.body]
  res.json({status: 'ok', data: req.body});
}
const getData = (req, res) => {
  res.json({status: 'ok', data: imgList});
}
const deleteData = (req, res) => {
  imgList.splice(imgList.indexOf(imgList.filter(i=>i.url===req.body.url)[0]), 1);
  res.json({status: 'ok', data: imgList});
}
export default {
  'POST /api/sys/img/upload': imgData,
  'POST /api/sys/img/get': getData,
  'POST /api/sys/img/delete': deleteData,
};

6、自定义可编辑单元格组件不渲染问题

对于业务需求需要对单元格内容可编辑,并对组件实时渲染,例如自己封装的Checkbox组件如下,具体功能是根据操作实现对列数据的展示效果。

import React,{useState} from 'react';
import {Checkbox} from "antd";

const CheckboxCom=props=>{
// row,text  为表格的row 行数据和值
// type 是自定义属性,判断是否固定列 是否显示列等 例如是 fixed
  const {row,onChangeItem,type,text} = props;
  const [ch,setChecked] = useState(undefined);
  const onChange = value=>{
    setChecked(value);
    row[type] = value;
    onChangeItem(row);
  }
  return (<Checkbox onChange={e=>onChange(e.target.checked)} checked={ch||text} />)
}

export default CheckboxCom;

当组件渲染的时候,组件会根据表格数据,动态绑定值。
但是在设置恢复默认设置的时候,并未渲染组件。通过判断ch是否存在来回填checked 就可以解决问题了,也就是在没有改变值的情况下,checked充当了 defaultValue 的作用。

7、自定义表格最后一行渲染

summary属性中定义antd 表格的汇总行
官网

/**
 * Created by lidianzhong on 2020-07-08.
 * To: More pain, more gain.
 */

import React, {useState} from 'react';
import {Table, Pagination, Checkbox} from 'antd';
import {SearchOutlined, PlusCircleTwoTone, MinusCircleTwoTone} from '@ant-design/icons';
import Mock from "mockjs";


const dataSource = Array(100)
  .fill(0, 0, 100)
  .map((item, i) => {
    return Mock.mock({
      index: i + 1,
      key: i + 1,
      "name|1": ['胡彦斌', "kankan", "kankan1"],
      "money|1-100": 32,
      address: Mock.mock("@city()"),
      address0: Mock.mock("@city()"),
      address1: Mock.mock("@city()"),
      address2: Mock.mock("@city()"),
      address3: Mock.mock("@city()"),
      address4: Mock.mock("@city()"),
      address5: Mock.mock("@city()"),
      address6: Mock.mock("@city()"),
    })
  });

const defaultPageSize = 20;
const TableComponents = () => {

  const [filteredInfo, setFilteredInfo] = useState({});
  const [sortedInfo, setSortedInfo] = useState({});
  const [data, setData] = useState([]);

  useState(() => {
    queryFun(1, defaultPageSize);
  }, [])


  const onHeaderRow = (column, index) => {
    console.log(column, index);
  }
  const onRow = (column, index) => {
    // console.log(column, index);
  }
  const children1=[];
  for (let i = 0; i < 7; i++) {
    children1.push({
      title: '住址' + i, dataIndex: 'address' + i, key: 'address' + i, width: 200
    });
  }
  let columns = [
    {
      title: "序号",
      dataIndex: 'index',
      key: 'index',
      width: 100,
      fixed: 'left',
    },
    {
      title: 姓名,
      dataIndex: 'name',
      key: 'name',
      width: 100,
      align: 'center',
      ellipsis: true,
      className: 'kankan',
      // colSpan:1,
      // defaultFilteredValue:'kankan',
      // defaultSortOrder:'ascend',
      // filterDropdownVisible:true,
      // filtered:true,
      filterMultiple: true,
      // filterDropdown:()=>
filterDropdown
, onCell: (record, rowIndex) => { return { onClick: event => { console.log("onCell单击行触发") }, // 点击行 onDoubleClick: event => { console.log("onCell双击行触发") }, onContextMenu: event => { console.log("onCell菜单触发") }, onMouseEnter: event => { console.log("onCell鼠标移入触发") }, // 鼠标移入行 onMouseLeave: event => { console.log("onCell鼠标移出触发") }, }; }, // onFilter:(e)=>{}, // onFilterDropdownVisibleChange:()=>{}, onHeaderCell: column => { return { onClick: event => { console.log("onHeaderCell单击行触发") }, // 点击行 onDoubleClick: event => { console.log("onHeaderCell双击行触发") }, onContextMenu: event => { console.log("onHeaderCell菜单触发") }, onMouseEnter: event => { console.log("onHeaderCell鼠标移入触发") }, // 鼠标移入行 onMouseLeave: event => { console.log("onHeaderCell鼠标移出触发") }, }; }, filters: [ {text: 'kankan', value: 'kankan'}, {text: 'kankan1', value: 'kankan1'}, {text: '胡彦斌', value: '胡彦斌'}, ], filteredValue: filteredInfo.name || null, onFilter: (value, record) => record.name.includes(value), }, { title: '身价', dataIndex: 'money', key: 'money', width: 100, defaultSortOrder: 'ascend', sortDirections: ["ascend", "descend"], showSorterTooltip: true, sorter: (a, b) => a.money - b.money, sortOrder: sortedInfo.columnKey === 'money' && sortedInfo.order, }, { title: '住址', children: [ {title: '住址', dataIndex: 'address1', key: 'address1', width: 200}, ...children1, ] }, ]; const columnss = columns.reduce((total,curr,index,arr)=>{ if(curr.children){ return total.concat(curr.children); }else{ return total.concat(curr); } },[]); console.log(columnss); /** * @fun self-define summery. * @param currentData * @returns {*} */ const onSummary = (currentData) => { const a = { index: '总计', key:"total", name: '', money: 0, address: '', address0: "", address1: "", address2: "", address3: "", address4: "", address5: "", address6: "", }; const data = currentData.reduce((total, currentValue, currentIndex, arr) => { return { ...a, money: total.money + currentValue.money, } }, a) return <> {columnss.map((i, j) =>{data[i.dataIndex]}) } } const titleFunction = enable => { return enable[0].name + " " + enable[0].address; } const expandableSelect = { rowExpandable: record => record.name !== 'kankan1', childrenColumnName: '展开', defaultExpandAllRows: false, // defaultExpandedRowKeys: [1], expandIcon: ({expanded, onExpand, record}) => { //https://codesandbox.io/s/fervent-bird-nuzpr?file=/index.js:1450-1677 return expanded ? ( onExpand(record, e)}/> ) : ( onExpand(record, e)}/> ) }, expandIconColumnIndex: 0, // expandedRowKeys: [2,6], expandedRowRender: (record, index, indent, expanded) => { // console.log(record, index, indent, expanded); return

record:{record.name}

index:{index}

indent:{indent}

expanded:{expanded}

}, indentSize: 20, expandRowByClick: true, onExpand: (expanded, record) => { console.log(expanded, record); }, onExpandedRowsChange: (expandedRows) => { console.log("expandedRows", expandedRows) } } const handleChange = (pagination, filters, sorter) => { console.log('Various parameters', pagination, filters, sorter); setFilteredInfo(filters); setSortedInfo(sorter); }; function queryFun(page, size) { setData([...dataSource].splice((page - 1) * size, size)); } return (
titleFunction(currentPageData)} dataSource={data} columns={columns} showHeader={true} bordered={true} summary={(currentData) => onSummary(currentData)} scroll={{x: 800, y: 400}} size={'small'} onChange={(pagination, filters, sorter) => handleChange(pagination, filters, sorter)} // onHeaderRow={(column, index)=> onHeaderRow(column, index)} // onRow={(column, index)=> onRow(column, index)} onRow={(record, index) => { return { onClick: event => { console.log("单击行触发") }, // 点击行 onDoubleClick: event => { console.log("双击行触发") }, onContextMenu: event => { console.log("菜单触发") }, onMouseEnter: event => { console.log("鼠标移入触发") }, // 鼠标移入行 onMouseLeave: event => { console.log("鼠标移出触发") }, }; }} onHeaderRow={column => { return { onClick: () => { console.log("点击表头行触发", column); }, // 点击表头行 }; }} // sortDirections={["ascend","descend"]} // showSorterTooltip={true} expandable={expandableSelect} pagination={false} /> { queryFun(page, pageSize); }} onShowSizeChange={(current, size) => { queryFun(current, size); }} total={dataSource.length} showSizeChanger showQuickJumper pageSizeOptions={[10, 20, 50, 100, 200]} defaultCurrent={1} defaultPageSize={defaultPageSize} showTotal={total => `总计 ${total} 条`} /> ) } export default TableComponents;

挖坑,填坑持续更新中。。。

同时也希望大家留言评论。。。

干了这碗酒

寄语

关于具体逻辑,在代码注释中已经给出。想学东西,希望读懂每一行代码,而不是简单的复制看效果。

不为别人,只为自己也要变得优秀。

主页

冰原狼主页:https://kankan.fun/
CSDN主页:https://blog.csdn.net/qq_38025939/
Github主页:https://github.com/kankanol1

明天的你一定会感谢现在拼命的自己!

你可能感兴趣的:(React,antd)