一直都知道单个vue组件中html元素过多,当发生数据更新时,会导致界面卡顿。网上的文章中有很多这类案例的文章,实际工作中我也遇到过,但自己从来没有在闲暇时(或者说自己的示例项目中),重现过,今天就要写个文章来重现这个场景。
示例
渲染200个表单项的界面
方式一:一次性渲染200个表单项
结论: 在输入框中输入文字时,能够明显的感觉到卡顿
<template>
<div>
<FormTemplate :count="200"></FormTemplate>
</div>
</template>
<script>
import FormTemplate from "./FormTemplate";
export default {
name: "StyleTextPage",
components: {
FormTemplate,
},
data() {
return {};
},
created() {},
methods: {},
};
</script>
<style scoped lang="scss"></style>
方式二:200表单项目,分成4个组件实现,每个50个表单项
结论: 在输入框中输入文字时,丝般顺滑
<template>
<div>
<!-- <FormTemplate :count="200"></FormTemplate>-->
<FormTemplate></FormTemplate>
<FormTemplate></FormTemplate>
<FormTemplate></FormTemplate>
<FormTemplate></FormTemplate>
</div>
</template>
<script>
import FormTemplate from "./FormTemplate";
export default {
name: "StyleTextPage",
components: {
FormTemplate,
},
data() {
return {};
},
created() {},
methods: {},
};
</script>
<style scoped lang="scss"></style>
基础代码
DynForm.vue: 一个简单的动态表单组件(基于el-form)
<template>
<el-form :model="formModel" v-bind="elFormAttrs">
<el-form-item
v-for="(formItemConfig, index) in formItemConfigArr"
:key="`${formItemConfig.prop}-${index}`"
:prop="formItemConfig.prop"
:rules="formItemConfig.rules"
:label="formItemConfig.label"
>
<el-input
v-if="formItemConfig.itemType === 'input'"
v-model="formModel[formItemConfig.prop]"
></el-input>
<el-select
v-else-if="formItemConfig.itemType === 'select'"
v-model="formModel[formItemConfig.prop]"
>
<template v-if="formItemConfig.optionArr">
<el-option
v-for="(option, pos) in formItemConfig.optionArr"
:key="`${option.value}-${pos}`"
:value="option.value"
:label="option.label"
></el-option>
</template>
</el-select>
</el-form-item>
</el-form>
</template>
<script>
export default {
name: "DynForm",
model: {
event: "change",
prop: "formData",
},
props: {
formData: {
type: Object,
},
/**
* prop: 唯一标识
* itemType: 表单项类型
* rules: 表单验证规则
* label: 显示标签
* optionArr: 下拉值
*/
formItemConfigArr: {
type: Array,
default: () => [],
},
// el-form支持的所有属性
elFormAttrs: {
type: Object,
},
},
data() {
return {
formModel: this.formData ? this.formData : {},
};
},
watch: {
formData: {
handler(newVal) {
this.formModel = newVal;
},
},
},
methods: {},
};
</script>
<style scoped></style>
FormTemplate.vue: 根据count数量生成一个大表单
<template>
<div>
<DynForm
v-model="formData"
:form-item-config-arr="formItemConfigArr"
:el-form-attrs="elFormAttrs"
></DynForm>
</div>
</template>
<script>
import DynForm from "@/components/form/dyn/DynForm";
export default {
name: "FormTemplate",
components: {
DynForm,
},
props: {
// input文本框数量
count: {
type: Number,
default: 50,
},
},
data() {
// 表单项配置
const formItemConfigArr = [
{
prop: "name",
label: "姓名",
itemType: "input",
},
{
prop: "sex",
label: "性别",
itemType: "select",
optionArr: [],
},
];
for (let i = 0; i < this.count; i++) {
formItemConfigArr.push({
prop: "name" + i,
label: "姓名",
itemType: "input",
});
}
return {
elFormAttrs: {
inline: true,
},
formData: null,
formItemConfigArr,
};
},
created() {
this.loadFormData();
this.loadSexOptions();
},
methods: {
loadFormData() {
setTimeout(() => {
this.formData = {
name: "张三",
sex: 1,
};
}, 1000);
},
loadSexOptions() {
setTimeout(() => {
const item = this.formItemConfigArr.find((item) => item.prop === "sex");
if (item) {
const sexOptionArr = [
{ value: 1, label: "男" },
{ value: 2, label: "女" },
{ value: 3, label: "未知" },
];
item.optionArr = sexOptionArr;
}
}, 1500);
},
},
};
</script>
<style scoped lang="scss">
.js-validate-form ::v-deep(.is-error .o-show-data) {
color: red;
}
</style>