react 表单快照

表单快照

在日常业务中,表单是我们经常打交道的一种场景;尤其在一些复杂的收集数据的业务系统中,尤为繁多;此时,开发的调试、和测试人员的工作变得繁重起来,由此想到是否可以将这种工作变得不那么繁琐;

需要实现的功能

1、在第一次填充数据的时候将其保存;(fill按钮)
2、在需要调用的时候将其取出赋值到对应表单上;(snapshot按钮)
3、确保其不影响功能。(拖拽)

代码

// 提示可以引用自己项目库中的api
import { message } from 'antd';
import { deepReadMoment, dealMomentFormData } from './utils';
const { NODE_ENV } = process.env;
export default class FormSnapshot {
  constructor({ component, form }) {
  // 此处可以根据自己设定的环境变量做选择
    if (NODE_ENV !== 'development') {
      return;
    }
    this.component = component;
    this.form = form;
    this.mask = document.createElement('div');
    this.createButton();
    document.body.appendChild(this.mask);
    this.setMask();
    this.ondragstartX = 0;
    this.ondragstartY = 0;
    // this.dom.style.left = `${localStorage.getItem(`${prefix}left`)}px`;
    // this.dom.style.top = `${localStorage.getItem(`${prefix}top`)}px`;
    this.mask.addEventListener('dragstart', this.dragstart.bind(this));
    this.mask.addEventListener('dragend', this.dragend.bind(this));
  }
  // 创建button
  createButton() {
    const fillButton = document.createElement('div');
    fillButton.style.display = 'flex';
    fillButton.style.width = '60px';
    fillButton.style.height = '30px';
    fillButton.style.background = 'green';
    fillButton.style.color = 'white';
    fillButton.style.justifyContent = 'center';
    fillButton.style.lineHeight = '30px';
    fillButton.innerHTML = 'fill';
    fillButton.addEventListener('click', this.saveFormData.bind(this));
    const snapshotButton = document.createElement('div');
    snapshotButton.style.display = 'flex';
    snapshotButton.style.width = '70px';
    snapshotButton.style.height = '30px';
    snapshotButton.style.background = 'green';
    snapshotButton.style.color = 'white';
    snapshotButton.style.justifyContent = 'center';
    snapshotButton.style.lineHeight = '30px';
    snapshotButton.innerHTML = 'snapshot';
    snapshotButton.addEventListener('click',this.snapshotFormData.bind(this));

    this.mask.appendChild(fillButton);
    this.mask.appendChild(snapshotButton);
  }

  setMask() {
    this.mask.setAttribute('draggable', true);
    this.mask.style.position = 'fixed';
    this.mask.style.zIndex = 9999;
    this.mask.style.width = '200px';
    this.mask.style.height = '50px';
    this.mask.style.display = 'flex';
    this.mask.style.alignItems = 'center';
    this.mask.style.justifyContent = 'space-around';
    this.mask.style.border = '1px solid green';
    this.mask.style.borderRadius = '10px';
    this.mask.style.top = '80px';
    this.mask.style.right = '20px';
    this.mask.ondragover = (event) => event.preventDefault();
  }
  // 保存表单数据
  saveFormData() {
    if (!this.component) {
      message.error('请传入组件实例');
      return;
    }
    if (!this.form) {
      message.error('当前组件中没有form表单');
      return;
    }
    let formData = this.form.getFieldsValue();
    if (!formData || JSON.stringify(formData) === '{}') {
      message.error('请先填写表单数据');
      return;
    }

    formData = dealMomentFormData(formData);

    localStorage.setItem(
      `${this.component.constructor.name}formData`,
      JSON.stringify(formData),
    );
  }
  // 生成快照 获取数据
  snapshotFormData() {
    if (!this.component) {
      message.error('请传入组件实例');
      return;
    }
    if (!this.form) {
      message.error('当前组件中没有form表单');
      return;
    }
    let formData = localStorage.getItem(
      `${this.component.constructor.name}formData`,
    );
    if (!formData) {
      message.error('当前组件还没有存储过数据');
      return;
    }
    formData = deepReadMoment(JSON.parse(formData));
    this.form.setFieldsValue({
      ...formData,
    });
  }
  dragstart(ev) {
    const event = ev;
    document.body.appendChild(this.mask);
    this.ondragstartX = event.x;
    this.ondragstartY = event.y;
    event.target.style.opacity = 0.328;
  }

  dragend(ev) {
    const event = ev;
    const { target } = event;

    const offsetX = event.x - this.ondragstartX;
    const offsetY = event.y - this.ondragstartY;

    let left = target.offsetLeft + offsetX;
    let top = target.offsetTop + offsetY;

    const width = target.offsetWidth;
    const bodyWidth = document.body.offsetWidth;
    if (left + width > bodyWidth) {
      left = bodyWidth - width;
    }
    left = left < 0 ? 0 : left;

    const height = target.offsetHeight;
    const bodyHeight = document.body.offsetHeight;
    if (top + height > bodyHeight) {
      top = bodyHeight - height;
    }
    top = top < 0 ? 0 : top;
	// 此处可以存储上次拖拽位置
    // localStorage.setItem(`${prefix}left`, left);
    // localStorage.setItem(`${prefix}top`, top);

    target.style.left = `${left}px`;
    target.style.top = `${top}px`;

    event.target.style.opacity = 1;
    // document.body.removeChild(this.mask);
  }

  leavePage() {
    if (this.mask) {
      // 卸载的时候删除引用 避免内存泄漏
      document.body.removeChild(this.mask);
      this.mask = null;
    }
  }
}
// window.FormSnapshot = FormSnapshot;

我们是以localStorage来实现的、所以在其中需要单独处理时间不能直接存储的问题 且无法直接json.stringify,以moment为例

import moment from 'moment';

// 在存储的时候对moment数据转化
export const dealMomentFormData = (formData) => {
  //
  if (typeof formData !== 'object') {
    return formData;
  }
  //
  if (formData instanceof moment) {
    return {
      value: formData.unix() * 1000,
      type: 'moment',
    };
  }

  // 数组或对象
  const result = formData instanceof Array ? [] : {};
  for (const key in formData) {
    result[key] = dealMomentFormData(formData[key]);
  }
  return result;
};

// 在读取的时候如果type为moment需要单独处理
export const deepReadMoment = (formData) => {
  if (JSON.stringify(formData) === '{}') {
    return null;
  }
  if (typeof formData !== 'object' || formData instanceof moment) {
    return formData;
  }
  if (formData.type === 'moment') {
    return moment(formData.value);
  }
  const result = formData instanceof Array ? [] : {};
  for (const key in formData) {
    result[key] = deepReadMoment(formData[key]);
  }
  return result;
};

此处是以class的name名字存储的,所以此方法不支持传入函数组件;

使用

import FormSnapshot from '@/formSnapshot/index.js';
constructor(props) {
    super(props);
    this.formSnapshot = null; // 初始化
}
componentDidMount() {
 // 此处的form 如果是ant4 就用对应formRef.current 此工具方法可以根据自己的项目业务再次封装,这里只是提供一个思路
 this.formSnapshot = new FormSnapshot({ component: this, form: this.props.form });
}
componentWillUnmount() {
  this.formSnapshot?.leavePage();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值