当前位置:   article > 正文

Vue动态生成form表单+校验_vue动态表单

vue动态表单

1. 定义Form表单组件:

  1. <template>
  2. <div class="v-form-conatiner">
  3. <van-cell-group>
  4. <!-- 自定义cell-group表头 -->
  5. <template v-if="title" #title>
  6. <slot name="group-title">
  7. {{ title }}
  8. </slot>
  9. </template>
  10. <ValidationObserver slim ref="validationObserver">
  11. <template v-for="item in formModel">
  12. <!-- 输入框、选择框、日期选择器、文件上传、单选框、复选框等可输入组件渲染 -->
  13. <ValidationProvider
  14. v-if="!formModelOptions[item.key + 'Hidden']"
  15. :key="item.key"
  16. :name="item.options.label"
  17. :rules="item.options.rules ? item.options.rules : ''"
  18. v-slot="{ errors }"
  19. slim
  20. >
  21. <van-cell
  22. v-if="item.componentType === 'van-cell'"
  23. :title="item.options.label"
  24. :value="formData[item.key]"
  25. />
  26. <component
  27. v-else
  28. :is="item.componentType"
  29. :ref="`${item.key}`"
  30. :data="item.options"
  31. :keyName="item.key"
  32. v-model="formData[item.key]"
  33. @changed="changed(item)"
  34. :error-message="errors[0]"
  35. />
  36. </ValidationProvider>
  37. </template>
  38. </ValidationObserver>
  39. </van-cell-group>
  40. </div>
  41. </template>
  42. <script>
  43. import { ValidationProvider } from "vee-validate";
  44. import formItemBase from "./mixins/FormBase";
  45. import VantField from "@/components/common/form/VantField.vue";
  46. import VantPersonal from "@/components/common/form/VantPersonal.vue";
  47. import VantAgent from "@/components/common/form/VantAgent.vue";
  48. import VantRadio from "@/components/common/form/VantRadio.vue";
  49. import VantCheckBox from "@/components/common/form/VantCheckBox.vue";
  50. import VantMultiPicker from "@/components/common/form/VantMultiPicker.vue";
  51. import VantDatetimePicker from "@/components/common/form/VantDatetimePicker.vue";
  52. import VantPicker from "@/components/common/form/VantPicker.vue";
  53. import VantUploader from "@/components/common/form/VantUploader.vue";
  54. import VantUploaderImage from "@/components/common/form/VantUploaderImage.vue";
  55. import VantFormPopup from "@/components/common/form/VantFormPopup.vue";
  56. import VantCalendar from "@/components/common/form/VantCalendar.vue";
  57. export default {
  58. name: "VantForm",
  59. components: {
  60. ValidationProvider,
  61. VantField,
  62. VantPersonal,
  63. VantAgent,
  64. VantRadio,
  65. VantCheckBox,
  66. VantMultiPicker,
  67. VantDatetimePicker,
  68. VantPicker,
  69. VantUploader,
  70. VantUploaderImage,
  71. VantFormPopup,
  72. VantCalendar,
  73. },
  74. mixins: [formItemBase],
  75. props: {
  76. formModel: {
  77. // 表单初始化数据结构
  78. type: Array,
  79. default: function () {
  80. return [];
  81. },
  82. },
  83. value: {
  84. // 表单的值
  85. type: Object,
  86. default: function () {
  87. return {};
  88. },
  89. },
  90. title: {
  91. type: String,
  92. default: function () {
  93. return "";
  94. },
  95. },
  96. },
  97. model: {
  98. prop: "value",
  99. event: "changed",
  100. },
  101. data() {
  102. return {
  103. formData: {}, // 表单绑定的数据
  104. formModelOptions: {}, // form表单字段配置显示隐藏参数配置
  105. };
  106. },
  107. methods: {
  108. /**
  109. * 表单提交函数
  110. */
  111. onSubmit() {
  112. this.$refs.validationObserver.validate().then((success) => {
  113. // success结果返回布尔值
  114. if (!success) return;
  115. // 处理请求
  116. // this.$emit("success", this.formData);
  117. this.$nextTick(() => {
  118. // 清除验证状态,需注意值不会清除要自己手动清除
  119. this.$refs.validationObserver.reset();
  120. });
  121. });
  122. },
  123. /**
  124. * 表单校验
  125. */
  126. validate() {
  127. return new Promise((resolve) => {
  128. this.$refs.validationObserver.validate().then((success) => {
  129. resolve(success);
  130. // if (success) {
  131. // this.$nextTick(() => {
  132. // // 清除验证状态,需注意值不会清除要自己手动清除
  133. // window.validationObserver = this.$refs.validationObserver;
  134. // this.$refs.validationObserver.reset();
  135. // });
  136. // }
  137. });
  138. });
  139. },
  140. reset() {
  141. this.$refs.validationObserver.reset();
  142. },
  143. /**
  144. * 表单值发生改变回调函数
  145. * item: 表单字段数据模板
  146. */
  147. changed(item) {
  148. this.$emit("formItemChanged", item, this.formData); // 值变更,暴露变化的事件及值,父类中可以处理业务校验等逻辑
  149. this.$emit("changed", this.formData); // 值变更双向绑定
  150. },
  151. /**
  152. * 动态设置fromData的值,主要用于字段之间的依赖计算
  153. * name:属性名
  154. * value: 值
  155. */
  156. setFormDataByName(name, value) {
  157. this.$set(this.formData, name, value);
  158. },
  159. /**
  160. * 动态设置formModelOptions的值,主要用于字段之间联动显示等逻辑控制
  161. * name + "Hidden" 是动态组装的属性名
  162. * value对应属性的名字
  163. */
  164. setFormModelOptionsByIndex(name, value) {
  165. this.$set(this.formModelOptions, name + "Hidden", value);
  166. },
  167. /**
  168. * @param {*} fieldName 字段key值
  169. * @param {*} model form模板
  170. * @param {*} node form节点
  171. */
  172. setFieldToDiabled(fieldName, disabled) {
  173. let refNode = null;
  174. if (fieldName) {
  175. refNode = this.getFieldNode(fieldName);
  176. if (refNode && refNode.setDisabled) {
  177. refNode.setDisabled(disabled);
  178. }
  179. }
  180. },
  181. /**
  182. * 初始化数据
  183. */
  184. initData() {
  185. let isEdit = false;
  186. if (!this.$utils.isEmpty(this.value)) {
  187. isEdit = true;
  188. }
  189. // model带{{i18nKey}}资源国家化
  190. this.handleI18n(this.formModel);
  191. // 动态给属性form data添加属性,后期作为field控件的v-model的变量
  192. for (let i = 0; i < this.formModel.length; i++) {
  193. if (isEdit) {
  194. // 编辑数据复制
  195. this.formModel[i].value = this.value[this.formModel[i].key];
  196. }
  197. // 组装表格绑定的model
  198. this.$set(
  199. this.formData,
  200. this.formModel[i].key,
  201. this.formModel[i].value
  202. );
  203. /**
  204. * 字段的配置属性集合
  205. * 可以配置多个,根据需要进行扩展
  206. **/
  207. let formModelItem = this.formModel[i];
  208. // 字段显示控制字段,命名规则:[key]+Hidden
  209. this.$set(
  210. this.formModelOptions,
  211. formModelItem.key + "Hidden",
  212. formModelItem.options.hidden ? true : false
  213. );
  214. }
  215. },
  216. /**
  217. * 返回表单字段的ref引用
  218. */
  219. getFieldRefNode(keyName) {
  220. return this.$refs[keyName];
  221. },
  222. /**
  223. * 返回表单字段的ref引用
  224. */
  225. getFieldNode(keyName) {
  226. let refsNode = this.$refs[keyName];
  227. return refsNode && refsNode.length ? refsNode[0] : null;
  228. },
  229. },
  230. created() {
  231. this.initData();
  232. },
  233. watch: {
  234. formModel() {
  235. this.initData();
  236. },
  237. value(newVal, oldVal) {
  238. console.info(oldVal);
  239. // 编辑数据,处理数据回填
  240. if (newVal.isEdit) {
  241. this.formData = newVal;
  242. }
  243. // 数据回填,把编辑状态重置成非编辑状态,必备表单改变,重复处理数据
  244. this.isEdit = false;
  245. },
  246. },
  247. };
  248. </script>
  249. <style scoped lang="less">
  250. .v-form-conatiner {
  251. font-size: 14px;
  252. color: #646566;
  253. text-align: left;
  254. }
  255. .required {
  256. .van-cell-group__title:before {
  257. position: absolute;
  258. left: 2.133333vw;
  259. color: #ee0a24;
  260. font-size: 3.733333vw;
  261. content: "*";
  262. }
  263. }
  264. .v-cell-title {
  265. margin: 0;
  266. padding: 16px 16px 16px;
  267. color: rgba(69, 90, 100, 0.6);
  268. font-weight: normal;
  269. font-size: 14px;
  270. line-height: 16px;
  271. background-color: #f7f8fa;
  272. }
  273. </style>

2.form表单子组件:

  1. <script>
  2. import { ValidationProvider } from "vee-validate";
  3. import formItemBase from "./mixins/FormBase";
  4. // 表单子组件
  5. import VantField from "@/components/common/form/VantField.vue";
  6. import VantPersonal from "@/components/common/form/VantPersonal.vue";
  7. import VantAgent from "@/components/common/form/VantAgent.vue";
  8. import VantRadio from "@/components/common/form/VantRadio.vue";
  9. import VantCheckBox from "@/components/common/form/VantCheckBox.vue";
  10. import VantMultiPicker from "@/components/common/form/VantMultiPicker.vue";
  11. import VantDatetimePicker from "@/components/common/form/VantDatetimePicker.vue";
  12. import VantPicker from "@/components/common/form/VantPicker.vue";
  13. import VantUploader from "@/components/common/form/VantUploader.vue";
  14. import VantUploaderImage from "@/components/common/form/VantUploaderImage.vue";
  15. import VantFormPopup from "@/components/common/form/VantFormPopup.vue";
  16. import VantCalendar from "@/components/common/form/VantCalendar.vue";

3.处理校验逻辑:

使用ValidationObserver和ValidationProvider实现校验逻辑

  1. <ValidationObserver slim ref="validationObserver">
  2. <template v-for="item in formModel">
  3. <!-- 输入框、选择框、日期选择器、文件上传、单选框、复选框等可输入组件渲染 -->
  4. <ValidationProvider
  5. v-if="!formModelOptions[item.key + 'Hidden']"
  6. :key="item.key"
  7. :name="item.options.label"
  8. :rules="item.options.rules ? item.options.rules : ''"
  9. v-slot="{ errors }"
  10. slim
  11. >
  12. <van-cell
  13. v-if="item.componentType === 'van-cell'"
  14. :title="item.options.label"
  15. :value="formData[item.key]"
  16. />
  17. <!-- 动态渲染form表单的子组件 -->
  18. <component
  19. v-else
  20. :is="item.componentType"
  21. :ref="`${item.key}`"
  22. :data="item.options"
  23. :keyName="item.key"
  24. v-model="formData[item.key]"
  25. @changed="changed(item)"
  26. :error-message="errors[0]"
  27. />
  28. </ValidationProvider>
  29. </template>
  30. </ValidationObserver>

4. 定义form表单Json数据模板

CreateContactModel.js

  1. import {
  2. getPositionOptions,
  3. getCustomerPortraitOptions,
  4. getProjectRoleOptions,
  5. } from "../../../store/constants";
  6. export const contactInformationModel = [
  7. {
  8. key: "contactName", // 联系人姓名
  9. componentType: "vant-field",
  10. value: "",
  11. options: {
  12. label: "联系人姓名",
  13. type: "text",
  14. placeholder: "{{pleaseInput}}",
  15. rules: "required",
  16. required: true,
  17. },
  18. },
  19. {
  20. key: "contactNumber", // 联系人电话
  21. componentType: "vant-field",
  22. value: "",
  23. options: {
  24. label: "联系人电话",
  25. type: "tel",
  26. placeholder: "{{pleaseInput}}",
  27. rules: "required|phone",
  28. required: true,
  29. },
  30. },
  31. {
  32. key: "department", // 所属部门
  33. componentType: "vant-field",
  34. value: "",
  35. options: {
  36. label: "所属部门",
  37. type: "text",
  38. placeholder: "{{pleaseInput}}",
  39. },
  40. },
  41. {
  42. key: "position", // 职位
  43. componentType: "vant-radio",
  44. value: "",
  45. options: {
  46. label: "职位",
  47. data: getPositionOptions(),
  48. valueType: "single-dict", // 数据类型
  49. },
  50. },
  51. {
  52. key: "portrait", // 客户画像
  53. componentType: "vant-picker",
  54. value: "",
  55. options: {
  56. label: "客户画像",
  57. placeholder: "{{pleaseSelect}}",
  58. data: getCustomerPortraitOptions(),
  59. valueType: "single-dict", // 数据类型
  60. },
  61. },
  62. {
  63. key: "projectRole", // 项目中角色
  64. componentType: "vant-multi-picker",
  65. value: "",
  66. options: {
  67. label: "项目中角色",
  68. placeholder: "{{pleaseSelect}}",
  69. span: 8,
  70. data: getProjectRoleOptions(),
  71. valueType: "multi-dict", // 数据类型
  72. },
  73. },
  74. ];

5.动态生成form表单

  1. <template>
  2. <div class="create-opportunity">
  3. <!-- 联系人信息 -->
  4. <vant-form
  5. ref="contactInformation"
  6. title="联系人信息(可添加多个联系人)"
  7. :formModel="contactInformationModel"
  8. v-model="contactInformationFormData"
  9. class="required"
  10. >
  11. </vant-form>
  12. <!-- 机会保存-->
  13. <van-button
  14. v-if="!isCreateProject"
  15. type="info"
  16. @click="onSubmit"
  17. block
  18. round
  19. >保存</van-button
  20. >
  21. </div>
  22. </template>
  23. <script>
  24. import VantForm from "@/components/common/VantForm.vue";
  25. import { contactInformationModel } from "@/components/common/business/CreateContactModel";
  26. export default {
  27. name: "Test",
  28. components: {
  29. VantForm,
  30. },
  31. data() {
  32. return {
  33. //提交表单数据
  34. preparerInformationFormData: {}, // 联系人信息form表单
  35. contactInformationModel, // 联系人信息model
  36. };
  37. },
  38. };
  39. </script>

效果图:

 校验:

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/438205
推荐阅读
相关标签
  

闽ICP备14008679号