动态表单

63 阅读2分钟

今天写了个动态表单,给大家看一看

当我们输入内容的时候根据,输入的内容判断下面展示什么表单

1725626722250.gif 上代码

<template>
  <div class="dynamicFrom">
    <pre>
    {{ from }}
   </pre
    >
    <div>
      <div v-for="(item, index) in formshow" :key="index" class="formItem">
        {{ item.name }}
        <component
          v-on="item.events"
          :model-value="item.value"
          :is="item.type"
        ></component>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { defineOptions } from "vue"
import { ElInput } from "element-plus"
defineOptions({
  name: "propsTable",
  components: {
    ElInput,
  },
})
const from = ref({
  name: {
    value: "",
    name: "名字",
    type: "ElInput",
    visibe: true,
    next(e) {
      if (e == "张三") {
        return {
          name: "age",
          visibe: true,
        }
      } else {
        return {
          name: "age",
          visibe: false,
        }
      }
    },
  },
  age: {
    value: 18,
    name: "年龄",
    visibe: false,
    type: "ElInput",
    next(e) {
      if (e == "1") {
        return {
          name: "nali",
          visibe: true,
        }
      } else {
        return {
          name: "nali",
          visibe: false,
        }
      }
    },
  },
  nex: {
    value: "张三",
    type: "ElInput",
    visibe: false,
    name: "南门",
  },
  nali: {
    value: "张三",
    visibe: false,
    type: "ElInput",
    name: "哪里",
  },
})
​
const formshow = computed(() => {
  const res = Object.keys(from.value).map((item) => {
    if (from.value[item].visibe) {
      return {
        ...from.value[item],
        events: {
          input: (e: any) => {
            UpdateComponent(item, e)
          },
        },
      }
    }
  })
  let filteredArr = res.filter((item) => item)
​
  return filteredArr
})
const UpdateComponent = (key, value) => {
  let bloke
  if (from.value[key].next) {
    bloke = from.value[key].next(value)
    from.value[bloke.name].visibe = bloke.visibe
  }
  if (from.value[key]?.visibe && bloke?.visibe == false) {
    Lun(from.value[key].next(value), value)
  }
  from.value[key].value = value
}
const Lun = (e, value) => {
  from.value[e.name].value = ""
  from.value[e.name].visibe = false
  if (from.value[e.name].next) {
    Lun(from.value[e.name].next(value), value)
  }
}
</script>
<style lang="scss" scoped>
.dynamicFrom {
  // height: 300px;
  width: 300px;
  display: flex;
}
</style>

这里通过一个原有对象,负责展示数据,还有个计算属性展示第一次要展示的内容。

/**
 * value: 绑定值
 * name: 表单名称
 * type: 组件类型
 * visibe: 是否显示
 * next: 下一个组件
 */
const from = ref({
  name: {
    value: "",
    name: "名字",
    type: "ElInput",
    visibe: true,
    next(e) {
      if (e == "张三") {
        return {
          name: "age",
          visibe: true,
        }
      } else {
        return {
          name: "age",
          visibe: false,
        }
      }
    },
  },
  age: {
    value: 18,
    name: "年龄",
    visibe: false,
    type: "ElInput",
    next(e) {
      if (e == "1") {
        return {
          name: "nali",
          visibe: true,
        }
      } else {
        return {
          name: "nali",
          visibe: false,
        }
      }
    },
  },
  nex: {
    value: "张三",
    type: "ElInput",
    visibe: false,
    name: "南门",
  },
  nali: {
    value: "张三",
    visibe: false,
    type: "ElInput",
    name: "哪里",
  },
})
​
​
/**
 * 因为有的表单是第一次展示
 * 所以需要过滤,
 * 这里面有个 events 是负责直接穿透 component 的事件,绑定他的修改值
 */
const formshow = computed(() => {
  const res = Object.keys(from.value).map((item) => {
    if (from.value[item].visibe) {
      return {
        ...from.value[item],
        events: {
          input: (e: any) => {
            UpdateComponent(item, e)
          },
        },
      }
    }
  })
  let filteredArr = res.filter((item) => item)
​
  return filteredArr
})
​
/**
 * 更新表单
 * @param key 表单key
 * @param value 表单值
 */
const UpdateComponent = (key, value) => {
  let bloke
  if (from.value[key].next) {
    bloke = from.value[key].next(value)
    from.value[bloke.name].visibe = bloke.visibe
  }
  if (from.value[key]?.visibe && bloke?.visibe == false) {
    Lun(from.value[key].next(value), value)
  }
  from.value[key].value = value
}
/**
 * 这里是,当一个值修改了,他的后续因为他要展示的表单都关闭,
 * 所有用递归组件,把有 next 的表单都滞空
 */
const Lun = (e, value) => {
  from.value[e.name].value = ""
  from.value[e.name].visibe = false
  if (from.value[e.name].next) {
    Lun(from.value[e.name].next(value), value)
  }
}