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}`;
});
高阶函数
函数作为参数调用
案例
// 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 组件
普通表单
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);
案例 - 工作
首页设计
-
设计组件
-
请求数据,处理数据
-
将数据导入到相应组件中
代码优化
案例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:利用组件 (拆分思想)
组件案例地址:
按钮组件:g-pm.vercel.app/btn
表单组件:g-pm.vercel.app/form
实战项目:
-
项目管理 g-pm.vercel.app/
参考: