vue之动态表单(优化)

代码资源在这儿 ↑

vue之动态表单优化

  • vue2+js动态表单优化
  • vue3+ts动态表单优化

vue2+js动态表单优化

效果图
在这里插入图片描述

目录结构
在这里插入图片描述
五个文件的完整代码:

以下是App.vue

<template>
  <div>
    <router-view></router-view>
    <Formpage />
  </div>
</template>

<script>
import Formpage from './views/FormPage.vue';

export default {
  components: {
    Formpage
  },
}
</script>

以下是FormPage.vue

<template>
  <div class="container">
    <FormItemComp :formState="root"></FormItemComp>
  </div>
</template>

<script>
import FormItemComp from '../components/FormItemComp.vue';
import root from './FormPageDatas';

export default {
  components: {
    FormItemComp
  },
  data() {
    return {
      root: root
    }
  }
}
</script>

<style scoped>
.container {
  width: 80%;
  margin: 1em auto;
}
</style>

以下是FormItemComp.vue

<template>
    <el-form>
      <template v-if="formState">
        <el-form-item :label="formState.payload.label">
          <template v-if="formState.type === 'input'">
            <el-input v-model="formState.payload.value"/>
          </template>
          <template v-else-if="formState.type === 'checkbox'">
            <el-checkbox-group v-model="formState.payload.value">
              <el-checkbox v-for="option in formState.payload.options" :key="option.value" :label="option.value">{{ option.label }}</el-checkbox>
            </el-checkbox-group>
          </template>
          <template v-else-if="formState.type === 'radio'">
            <el-radio-group v-model="formState.payload.value">
              <el-radio v-for="option in formState.payload.options" :key="option.value" :label="option.value">{{ option.label }}</el-radio>
            </el-radio-group>
          </template>
          <template v-else-if="formState.type === 'select'">
            <el-select v-model="formState.payload.value">
              <el-option v-for="option in formState.payload.options" :key="option.value" :label="option.label" :value="option.value"/>
            </el-select>
          </template>
        </el-form-item>
        <FormItemComp :form-state="getNext()"/>
      </template>
    </el-form>
</template>

<script>
export default {
  name: 'FormItemComp',
  props: {
    formState: {
      type: Object,
      default: null
    }
  },
  methods: {
    getNext() {
      let current = this.formState;
      if (!current) {
        return null;
      }
      const ancestors = [];
      ancestors.unshift(current);
      while ((current = current.parent)) {
        ancestors.unshift(current);
      }
      return this.formState.next(this.formState, ancestors);
    }
  }
}
</script>

<style scoped>
.el-form-item__label {
  padding-right: 10px !important;
}
</style>

以下是FormItem.js

import Vue from 'vue';

/**
 * 创建表单项
 * @param formItemType string 表单项的类型
 * @param payload object 表单项的label、options、value
 * @param next function 当前选择的值
 * @param parent 上一个表当项
 * @return {{next: ((function(*=, *=): (null|null))|*), parent: null, payload, type}}
 */
export function createFormItem(formItemType, payload, next, parent) {
    if (!next) {
        next = () => null;
    }
    if (!parent) {
        parent = null;
    }
    const nextFunc = function(current, acients) {
        let nextItem = next(current, acients);
        if (!nextItem) {
            return null;
        }
        nextItem.parent = current;
        if (!Vue.observable(nextItem)) {
            nextItem = Vue.observable(nextItem);
        }
        return nextItem;
    };
    return Vue.observable({
        type: formItemType,
        payload: payload,
        next: nextFunc,
        parent: parent,
    });
}

以下是FormPageDatas.js

import {createFormItem} from '@/FormItem';

const item1 = createFormItem(
    'select',
    {
        label: 'test1',
        options: [
            {label: 'test1-1', value: 'test1-1'},
            {label: 'test1-2', value: 'test1-2'},
            {label: 'test1-3', value: 'test1-3'},
        ],
        value: 'test1-1',
    },
    (current) => {
        if (current.payload.value === 'test1-2') {
            return item2;
        } else if (current.payload.value === 'test1-3') {
            return item4;
        } else {
            return null;
        }
    }
);

const item2 = createFormItem('input', {
    label: 'test2',
    value: 'test'
}, (current) => (current.payload.value === 'test2' ? item3 : null));

const item3 = createFormItem(
    'checkbox',
    {
        label: 'test3',
        options: [
            {label: 'test3-1', value: 'test3-1'},
            {label: 'test3-2', value: 'test3-2'},
            {label: 'test3-3', value: 'test3-3'},
        ],
        value: ['test3-2', 'test3-3'],
    },
    (current) => (current.payload.value.includes('test3-1') ? item4 : null)
);

const item4 = createFormItem('radio', {
    label: 'test4',
    options: [
        {label: 'test4-1', value: 'test4-1'},
        {label: 'test4-2', value: 'test4-2'},
        {label: 'test4-3', value: 'test4-3'},
        {label: 'test4-4', value: 'test4-4'},
    ],
    value: 'test4-4',
});

export default item1;

vue3+ts动态表单优化

效果图
在这里插入图片描述

目录结构
在这里插入图片描述

五个文件的完整代码:

以下是App.vue

<template>
  <div>
    <Formpage />
  </div>
</template>

<script setup lang="ts">
import Formpage from './views/Formpage.vue';
</script>

以下是FormPage.vue

<template>
  <div class="container">
    <FormItemComp :form-state="root"></FormItemComp>
  </div>
</template>

<script setup lang="ts">
import FormItemComp from '../components/FormItemComp.vue';
import root from './FormPageDatas';
</script>

<style scoped>
.container {
  width: 80%;
  margin: 1em auto;
}
</style>

以下是FormItemComp.vue

<template>
  <template v-if="formState">
    <a-form-item :label="formState.payload.label">
      <template v-if="formState.type === 'input'">
        <a-input v-model:value="formState.payload.value" />
      </template>
      <template v-else-if="formState.type === 'checkbox'">
        <a-checkbox-group v-model:value="formState.payload.value">
          <a-checkbox v-for="option in formState.payload.options" :value="option.value">{{ option.label }}</a-checkbox>
        </a-checkbox-group>
      </template>
      <template v-else-if="formState.type === 'radio'">
        <a-radio-group v-model:value="formState.payload.value">
          <a-radio v-for="option in formState.payload.options" :value="option.value">{{ option.label }}</a-radio>
        </a-radio-group>
      </template>
      <template v-else-if="formState.type === 'select'">
        <a-select v-model:value="formState.payload.value">
          <a-select-option v-for="option in formState.payload.options" :value="option.value">{{ option.label }}</a-select-option>
        </a-select>
      </template>
    </a-form-item>
    <FormItemComp :form-state="getNext()"></FormItemComp>
  </template>
</template>

<script setup lang="ts">
import { FormItem } from '../FormItem';

const props = defineProps<{
  formState: FormItem | null;
}>();

function getNext(): FormItem | null {
  let current: FormItem | null = props.formState;
  if (!current) {
    return null;
  }
  const acients = [];
  acients.unshift(current);
  while ((current = current.parent)) {
    acients.unshift(current);
  }
  return props.formState!.next(props.formState!, acients);
}
</script>

<style>
.ant-form-item-label {
  padding-right: 10px !important;
}
</style>

以下是FormItem.ts

import { isReactive, reactive } from 'vue';

export type FormItemType = 'input' | 'select' | 'checkbox' | 'radio';

export interface FormItem {
  type: FormItemType;
  payload: any;
  next: (current: FormItem, acients: FormItem[]) => FormItem | null;
  parent: FormItem | null;
}

export function createFormItem(
  formItemType: FormItem['type'],
  payload: FormItem['payload'],
  next?: FormItem['next'],
  parent?: FormItem['parent']
): FormItem {
  if (!next) {
    next = () => null;
  }
  if (!parent) {
    parent = null;
  }
  const nextFunc: FormItem['next'] = (current, acients) => {
    let nextItem = next!(current, acients);
    if (!nextItem) {
      return null;
    }
    nextItem.parent = current;
    if (!isReactive(nextItem)) {
      nextItem = reactive(nextItem);
    }
    return nextItem;
  };
  const formItem: FormItem = reactive({
    type: formItemType,
    payload,
    next: nextFunc,
    parent,
  });

  return formItem;
}

以下是FormPageDatas.ts

import { createFormItem } from '../FormItem';

const item1 = createFormItem(
  'select',
  {
    label: 'test1',
    options: [
      { label: 'test1-1', value: 'test1-1' },
      { label: 'test1-2', value: 'test1-2' },
      { label: 'test1-3', value: 'test1-3' },
    ],
    value: 'test1-1',
  },
  (current) => {
    if (current.payload.value === 'test1-2') {
      return item2;
    } else if (current.payload.value === 'test1-3') {
      return item4;
    } else {
      return null;
    }
  }
);

const item2 = createFormItem(
    'input',
    { label: 'test2', value: 'test' },
    (current) => (current.payload.value === 'test2' ? item3 : null)
);

const item3 = createFormItem(
  'checkbox',
  {
    label: 'test3',
    options: [
      { label: 'test3-1', value: 'test3-1' },
      { label: 'test3-2', value: 'test3-2' },
      { label: 'test3-3', value: 'test3-3' },
    ],
    value: ['test3-2', 'test3-3'],
  },
  (current) => (current.payload.value.includes('test3-1') ? item4 : null)
);

const item4 = createFormItem('radio', {
  label: 'test4',
  options: [
    { label: 'test4-1', value: 'test4-1' },
    { label: 'test4-2', value: 'test4-2' },
    { label: 'test4-3', value: 'test4-3' },
    { label: 'test4-4', value: 'test4-4' },
  ],
  value: 'test4-4',
});

export default item1;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/78381.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

jenkins 安装nodejs 14

参考&#xff1a; jenkins容器安装nodejs-前端问答-PHP中文网

在ubuntu+cpolar+rabbitMQ环境下,实现mq服务端远程访问

文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基…

LangChain手记 Agent 智能体

整理并翻译自DeepLearning.AILangChain的官方课程&#xff1a;Agent&#xff08;源代码可见&#xff09; “人们有时会将LLM看作是知识库&#xff0c;因为它被训练所以记住了来自互联网或其他地方的海量信息&#xff0c;因而当你向它提问时&#xff0c;它可以回答你的问题。有一…

网络

mcq Java 传输层&#xff1a;拆分和组装&#xff0c;完成端到端的消息传递&#xff0c;流量控制&#xff0c;差错控制等 网络层&#xff1a; 寻址、路由&#xff0c;复用&#xff0c;拥塞控制&#xff0c;完成源到宿的传递。 显然A选项是错误的&#xff0c;有流量控制的是传输层…

JavaWeb框架:Spring MVC介绍

Spring MVC 概述 概述 MVC&#xff08;Model View Controller&#xff0c;模型-视图-控制器&#xff09;&#xff0c;作为一种设计模式&#xff0c;用于应用程序的分层开发。 Spring MVC&#xff0c;由 Spring 框架提供的基于 MVC 设计模式的一个轻量级 Web 开发框架。Spring…

基于CentOS 7 部署社区版Haproxy

HAProxy是法国开发者 威利塔罗(Willy Tarreau) 在2000年使用C语言开发的一个开源软件&#xff0c;是一款具 备高并发(一万以上)、高性能的TCP和HTTP负载均衡器&#xff0c;支持基于cookie的持久性&#xff0c;自动故障切换&#xff0c;支 持正则表达式及web状态统计。 目录 1…

微服务-Fegin

在之前我们两服务之间调用的时候用的是restTemplate,但是这个方式调用存在很多的问题 String url "http://userservice/user/" order.getUserId(); 代码可读性差&#xff0c;编码体验不统一参数复杂的url难以维护 所以我们大力推出我们今天的主角--Fegin Feign是…

解决“warning: #223-D: function “xPortSysTickHandler“ declared implicitly“告警提示

继上篇文章发布已有时隔两个月之久&#xff0c;今天就把这两个月遇到的一些问题解决分享一下&#xff0c;首先&#xff0c;我们来看今天分享的这个关于我在学习freertos遇到的一个告警。如图所示&#xff1a; 告警提示原句为&#xff1a; warning: #223-D: function "xP…

Offset Explorer

Offset Explorer 简介下载安装 简介 Offset Explorer&#xff08;以前称为Kafka Tool&#xff09;是一个用于管理和使Apache Kafka 集群的GUI应用程序。它提供了一个直观的UI&#xff0c;允许人们快速查看Kafka集群中的对象以及存储在集群主题中的消息。它包含面向开发人员和管…

【自用】云服务器 docker 环境下 HomeAssistant 安装 HACS 教程

一、进入 docker 中的 HomeAssistant 1.查找 HomeAssistant 的 CONTAINER ID 连接上云服务器&#xff08;宿主机&#xff09;后&#xff0c;终端内进入 root &#xff0c;输入&#xff1a; docker ps找到了 docker 的 container ID 2.config HomeAssistant 输入下面的命令&…

PLUS操作流程、应用与实践,多源不同分辨率数据的处理、ArcGIS的应用、PLUS模型的应用、InVEST模型的应用

PLUS模型是由中国地质大学&#xff08;武汉&#xff09;地理与信息工程学院高性能空间计算智能实验室开发&#xff0c;是一个基于栅格数据的可用于斑块尺度土地利用/土地覆盖(LULC)变化模拟的元胞自动机(CA)模型。PLUS模型集成了基于土地扩张分析的规则挖掘方法和基于多类型随机…

ARM02汇编指令

文章目录 一、keil软件介绍1.1 创建工程1.2 解析start.s文件(重点)1.3 乱码解决1.4 更换背景颜色1.5 C语言内存分布1.6 解析map.lds文件(重点)1.7 常见错误信息1.8 仿真 二、汇编三种符号2.1 汇编指令2.2 伪指令2.3 伪操作 三、汇编指令格式3.1 格式3.2 注意事项 四、数据操作指…

SpringBoot复习:(34)@EnableWebMvc注解为什么让@WebMvcAutoconfiguration失效?

它导入了DelegatingWebMvcConfiguration 它会把容器中的类型为WebMvcConfigurer的bean注入到类型为WebMvcConfigurerComposite的成员变量configurers中。 可以看到它继承了WebMvcConfigurerSupport类 而WebMvcConfigureAutoConfiguration类定义如下 可以看到一个Conditional…

Tesseract用OpenCV进行文本检测

我没有混日子&#xff0c;只是辛苦的时候没人看到罢了 一、什么是Tesseract Tesseract是一个开源的OCR&#xff08;Optical Character Recognition&#xff09;引擎&#xff0c;OCR是一种技术&#xff0c;它可以识别和解析图像中的文本内容&#xff0c;使计算机能够理解并处理…

求解方程sympy.solve

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 求解方程 sympy.solve [太阳]选择题 下列代码最后一次输出的结果是&#xff1f; import sympy x sympy.symbols(x) y x**2 2*x - 3 print("【执行】sympy.solve(y, x)") print(s…

网络通信基础

1.网络结构模式&#xff08;C/S和B/S&#xff09; (1)C/S结构模式 服务器 - 客户机&#xff0c;即 Client - Server&#xff08;C/S&#xff09;结构。 优点&#xff1a; 能充分发挥客户端 PC 的处理能力&#xff0c;很多工作可以在客户端处理后再提交给服务器&#xff…

GitKraken保姆级图文使用指南

前言 写这篇文章的原因是组内的产品和美术同学&#xff0c;开始参与到git工作流中&#xff0c;但是网上又没有找到一个比较详细的使用教程&#xff0c;所以干脆就自己写了一个[doge]。文章的内容比较基础&#xff0c;介绍了Git内的一些基础概念和基本操作&#xff0c;适合零基…

CSS变形与动画(三):animation帧动画详解(用法 + 四个例子)

文章目录 animation 帧动画使用定义例子1 字母例子2 水滴例子3 会动的边框例子4 旋转木马 animation 帧动画 定义好后作用于需要变化的标签上。 使用 animation-name 设置动画名称 animation-duration: 设置动画的持续时间 animation-timing-function 设置动画渐变速度 anim…

做好需求分析的4大关键认知

探索如何正确的需求分析&#xff1f;本文详细介绍了4大关键点&#xff0c;帮助您明确用户与产品需求、深入挖掘用户动机&#xff0c;并为产品经理提供筛选需求的实用建议。 一、什么是需求分析以及重要性 需求分析指的是在建立一个新的或改变一个现存的产品时&#xff0c;确定新…

docker run 命令30个常用参数详解

文章目录 0.前言docker run 命令示例 2.Docker run 多种用法知其然知其所以然1. 基本用法2. 启动交互式容器3. 映射端口4. 挂载文件/目录5. 设置环境变量6. 指定容器名称7. 后台运行容器8. 重启策略9. 其他参数 2. docker run 命令参数详解1. -d&#xff1a;以后台模式&#xf…