【组件设计】

116 阅读1分钟

grammyli 第二次分享 - 组件设计

组件的设计

案例 - button 组件

按钮组件

  • 确定相应配置数据
  • 配置数据值对应相应的 className
  • 将所有配置数据 className 赋值到按钮 class 上

    let { type, value, size, className, onClick, disabled, loading, danger, shape } =
      this.props;
    className = className ? className : "";
    // 按钮的类型
    const classTypes = {
      primary: "g-button-primary",
      dashed: "g-button-dashed",
      text: "g-button-text",
      link: "g-button-link",
    };
    let classType = "";
    if (type && type !== "default") {
      classType = classTypes[type];
    }
    // 按钮的大小
    const classSizes = {
      small: "g-button-small",
      large: "g-button-large",
    };
    let classSize = "";
    if (size && size !== "default") {
      classSize = classSizes[size];
    }
    // 是否是 danger
    danger = danger
    let classDanger = ''
    if (danger) {
      classDanger = 'g-button-dangerous'
    }
    // 形状
    const classShapes = {
      circle: 'g-button-circle',
      round: 'g-button-round',
    }
    let classShape = "";
    if (shape && shape !== "default") {
      classShape = classShapes[shape];
    }
    // 合并所有的 className
    const classNames = [classType, classSize, className, classDanger, classShape];
    let name = "g-button";
    classNames.forEach((n) => {
      if (!n && n.length === 0) {
        return;
      }
      name += ` ${n}`;
    });

地址: g-pm.vercel.app/btn

高阶函数

函数作为参数调用

案例

// map 方法
const gMap = (arr, cb) => {
  const newArr = []
  for (let i = 0; i < arr.length; i++) {
    let e = arr[i]
    newArr.push(cb(e))
  }
  return newArr
}

const arr = ['1', '2', '3']
console.log('new arr', gMap(arr, e => parseInt(e))

// filter 方法
const gFilter = (arr, cb) => {
  const newArr = []
  for (let i = 0; i < arr.length; i++) {
    let e = arr[i]
    if (cb(e)) {
      newArr.push(e)
    }
  }
  return newArr
}

高阶组件

组件作为参数调用

案例 - form 组件

普通表单

地址:g-pm.vercel.app/form

const createForm = () => {
  return (Comp) => {
    const data = {};
    return class Form extends React.Component {
      getFieldProps = (key, options) => {
        log("key", key);
        return {
          key,
          onInput: (e) => {
            const v = e.target.value;
            data[key] = v;
          },
        };
      };

      getFieldValue = () => {
        return data;
      };

      render() {
        const form = {
          getFieldProps: this.getFieldProps,
          getFieldValue: this.getFieldValue,
        };
        return <Comp form={form} />;
      }
    };
  };
};

const Test = ({ form }) => {
  return (
    <div style={{marginLeft: '24px'}}>
     username: <Input {...form.getFieldProps("username")} />
     height: <Input {...form.getFieldProps("height")} />

      <Button
        type="primary"
        value="提交"
        onClick={(e) => {
          log("form values", form.getFieldValue());
        }}
      />
      
    </div>
  );
};

export default createForm()(Test);

校验表单

Json Schema就是用来定义json数据约束的一个标准

const createForm = () => {
  return (Comp) => {
    const data = {};
    return class Form extends React.Component {
      getFieldProps = (key, options = {}) => {
        log("key", key);
        return {
          key,
          onInput: (e) => {
            const v = e.target.value;
            log("v", v);
            data[key] = data[key] || {};
            data[key].value = v;
            log("!options.validator", !options.validator);
            if (!options.validator) {
              return;
            }
            // 验证的规则
            const validator = new AsyncValidator({
              [key]: options.validator,
            });
            // 验证表单数据的值
            validator
              .validate({
                [key]: v,
              })
              .then(() => {
                data[key].error = null;
                log("验证成功");
              })
              .catch(({ errors }) => {
                log("err", errors);
                const err = errors.map((e) => e.message).join(',')
                log("err", err);
                data[key].error = err;
              })
              .then(() => {
                this.forceUpdate();
              });
          },
        };
      };

      getFieldValue = () => {
        return data;
      };

      getFieldError = (key) => {
        const err = data[key] && data[key].error
        return err
      }

      render() {
        const form = {
          getFieldProps: this.getFieldProps,
          getFieldValue: this.getFieldValue,
          getFieldError: this.getFieldError,
        };
        return <Comp form={form} />;
      }
    };
  };
};

const Test2 = ({ form }) => {
  return (
    <div style={{ marginLeft: "24px" }}>
      msg:
      <Input
        {...form.getFieldProps("msg", {
          validator: [
            {
              required: true,
              message: "username required",
            },
            {
              min: 3,
              max: 10,
              message: "meassage err err",
            },
          ],
        })}
        className={form.getFieldError('msg') ? 'g-red-border' : null}
      />
      <div className="g-red-color">{form.getFieldError('msg')}</div>
      <Button
        type="primary"
        value="提交"
        onClick={(e) => {
          log("form values", form.getFieldValue());
        }}
      />
    </div>
  );
};

export default createForm()(Test2);

表单数据联动

const createForm = () => {
  return (Comp) => {
    const data = {};
    return class Form extends React.Component {
      getFieldProps = (key, options = {}) => {
        log("key", key);
        return {
          key,
          disabled: options.disabled
            ? options.disabled(this.getFieldValue())
            : undefined,
          onInput: (e) => {
            const v = e.target.value;
            log("v", v);
            data[key] = data[key] || {};
            data[key].value = v;
            log("!options.validator", !options.validator);
            if (!options.validator) {
              return;
            }
            // 验证的规则
            const validator = new AsyncValidator({
              [key]: options.validator,
            });
            // 验证表单数据的值
            validator
              .validate({
                [key]: v,
              })
              .then(() => {
                data[key].error = null;
                log("验证成功");
              })
              .catch(({ errors }) => {
                log("err", errors);
                const err = errors.map((e) => e.message).join(",");
                log("err", err);
                data[key].error = err;
              })
              .then(() => {
                this.forceUpdate();
              });
          },
        };
      };

      getFieldValue = () => {
        return data;
      };

      getFieldError = (key) => {
        const err = data[key] && data[key].error;
        return err;
      };

      render() {
        const form = {
          getFieldProps: this.getFieldProps,
          getFieldValue: this.getFieldValue,
          getFieldError: this.getFieldError,
        };
        return <Comp form={form} />;
      }
    };
  };
};

const Test3 = ({ form }) => {
  return (
    <div style={{ marginLeft: "24px" }}>
      msg:
      <Input
        {...form.getFieldProps("msg", {
          validator: [
            {
              required: true,
              message: "username required",
            },
            {
              min: 3,
              max: 10,
              message: "meassage err err",
            },
          ],
        })}
        className={form.getFieldError("msg") ? "g-red-border" : null}
      />
      <div className="g-red-color">{form.getFieldError("msg")}</div>
      comment:
      <Input
        {...form.getFieldProps("comment", {
          validator: [
            {
              required: true,
              message: "username required",
            },
            {
              min: 5,
              max: 10,
              message: "meassage err err",
            },
          ],
          disabled(data) {
            if (!data?.msg?.value) {
              return false;
            } else {
              return data.msg.value === "www";
            }
          },
        })}
        className={form.getFieldError("comment") ? "g-red-border" : null}
      />
      <div className="g-red-color">{form.getFieldError("comment")}</div>
      <Button
        type="primary"
        value="提交"
        onClick={(e) => {
          log("form values", form.getFieldValue());
        }}
      />
    </div>
  );
};

export default createForm()(Test3);

案例 - 工作

首页设计

  1. 设计组件

  2. 请求数据,处理数据

  3. 将数据导入到相应组件中

代码优化

案例01: 利用 array 作用

// 之前
type === 'type1' || type === 'type2' || type === 'type3' || type === 'type4'

// 之后
['type1', 'type2', 'type3', 'type4'].includes(type)

案例02: 利用 objectj 作用

 之前:
  <svg-div
   v-if="type == 'type1'"
   icon-class="professoricon1"
   class="mencard-svgicon"
   />
   <svg-div
   v-if="type == 'type2'"
   icon-class="resourceicon1"
   class="mencard-svgicon"
   />
  <svg-div
   v-if="type == 'type3'"
   icon-class="resourceicon2"
   class="mencard-svgicon"
  />
  <svg-div
   v-if="type == 'type3'"
   icon-class="resourceicon2"
   class="mencard-svgicon"
  />

之后:
types: {
        type1: 'professoricon1',
        type2: 'resourceicon1',
        type3: 'resourceicon2'
       }

	 <svg-div
     icon-class="types[type]"
     class="mencard-svgicon"
   />

案例03: 利用函数

    formttedStartTime() {
      const startRight = this.form.startTime.clone().format('HH:mm:ss')
      const startLeft = this.form.startDate.clone().format('YYYY/MM/DD')
      const startText = `${startLeft} ${startRight}`
      const start = moment(startText, 'YYYY/MM/DD HH:mm:ss')
      return start
    },

案例04:利用组件 (拆分思想)

组件案例地址:

搜索工具:grammyli.com/t/search/

按钮组件:g-pm.vercel.app/btn

表单组件:g-pm.vercel.app/form

实战项目:

参考:

zhuanlan.zhihu.com/p/78472109