前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >antdv动态表单组件

antdv动态表单组件

作者头像
阿超
发布2022-08-21 12:59:22
8100
发布2022-08-21 12:59:22
举报
文章被收录于专栏:快乐阿超快乐阿超

分享一个自己写的antdv动态表单组件

代码语言:javascript
复制
<!-- 动态表单组件 -->
<template>
  <div>
    <div v-for="(item, index) in value" :key="item[rowKey] || index">
      <a-row>
        <a-col :span="24">
          <slot :item="item">
            <a-row v-if="column.length" v-bind="flex">
              <a-col
                :span="24 / column.length - 1"
                v-for="(columnItem, columnIndex) in column"
                :key="item.title || columnIndex"
              >
                <a-form-model-item :label="showLabel && columnItem.label" v-bind="showLabel && formItemLayout">
                  <div v-if="!isPreview">
                    <a-select
                      v-if="columnItem.select"
                      v-model="item[columnItem.title]"
                      :options="columnItem.select"
                      :placeholder="columnItem.placeholder"
                      @change="selectChange($event, index, columnItem)"
                      @blur="blur"
                      allow-clear
                      show-search
                    />
                    <a-tooltip v-else>
                      <template slot="title"> {{ item[columnItem.title] || columnItem.placeholder }} </template>
                      <a-input
                        @blur="blur"
                        v-model="item[columnItem.title]"
                        :placeholder="columnItem.placeholder"
                        allow-clear
                      />
                    </a-tooltip>
                  </div>
                  <div v-else>
                    <div v-if="columnItem.select">
                      {{ (columnItem.select.find(({ value }) => value == item[columnItem.title]) || {}).label }}
                    </div>
                    <div v-else>{{ item[columnItem.title] }}</div>
                  </div>
                </a-form-model-item>
              </a-col>
            </a-row>
          </slot>
        </a-col>
        <div v-if="!isPreview" class="item-btns">
          <a-button class="item-btn" shape="circle" icon="minus" @click="delItem(index)" />
          <a-button class="item-btn" shape="circle" icon="plus" @click="addItem(index)" />
        </div>
      </a-row>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      flex: {
        type: 'flex',
        justify: 'space-between',
      },
    }
  },
  props: {
    /**
     * 指定vue中的key,建议指定为id
     */
    rowKey: {
      type: String,
      default: () => '_key',
    },
    /**
     * 指定动态表单表头和列
     */
    column: {
      type: Array,
      default: () => [
        { title: 'name', label: 'name', placeholder: 'Please input name' },
        { title: 'value', label: 'value', placeholder: 'Please input value' },
      ],
    },
    /**
     * 显示label
     */
    showLabel: {
      type: Boolean,
      default: () => false,
    },
    /**
     * 是否预览模式
     */
    isPreview: {
      type: Boolean,
      default: () => false,
    },
    /**
     * 数据,非受控组件可用v-model或者value绑定,传入的数据会随着用户操作而更新
     */
    value: {
      type: Array,
      default: () => [],
    },
    /**
     * 表单元素布局式样
     */
    formItemLayout: {
      type: Object,
      default: () => ({
        labelCol: { span: 6 },
        wrapperCol: { span: 18 },
        colon: false,
      }),
    },
    /**
     * 表单blur事件
     */
    blur: {
      type: Function,
      default: () => () => {},
    },
  },
  mounted() {
    if (!this.value || !this.value.length) {
      this.$emit('input', [this.genItem(Math.random())])
    }
  },
  computed: {
    /**
     * 获取过滤后的items
     */
    getItems() {
      return this.value.filter((item) =>
        this.column.some(({ title }) => item[title] != null && item[title] != undefined && item[title] != '')
      )
    },
  },
  methods: {
    addItem(index) {
      let item = this.genItem()
      let itemList
      if (index != null && index != undefined) {
        itemList = [...this.value]
        itemList.splice(index + 1, 0, item)
      } else {
        itemList = [...this.value, item]
      }
      this.$emit('input', itemList)
      this.$emit('addItem', index)
    },
    delItem(index) {
      let itemList = [...this.value]
      if (itemList.length == 1) {
        let item = {
          ...itemList[index],
          ...Object.fromEntries(this.column.map(({ title }) => [title, undefined])),
        }
        itemList.splice(index, 1, item)
      } else {
        itemList.splice(index, 1)
        this.$emit('delItem', index)
      }
      this.$emit('input', itemList)
    },
    selectChange(value, index, column) {
      let list = [...this.value]
      let item = { ...list[index], [column.title]: value }
      list.splice(index, 1, item)
      this.$emit('input', list)
      column.change && column.change(value, index)
    },
    genItem(key) {
      return Object.fromEntries(
        [...this.column, { title: this.rowKey, value: key || Math.random() }].map(({ title, value }) => [
          title,
          value || undefined,
        ])
      )
    },
    watchValue() {
      this.$emit('change', this.getItems)
    },
  },
  watch: {
    value: {
      deep: true,
      handler: 'watchValue',
    },
  },
}
</script>

<style lang="stylus" scoped>
.item-btns {
  display: flex;
  margin-top: 4px;

  .item-btn {
    margin-left: 10px;
  }
}
</style>

使用方式:

代码语言:javascript
复制
<dynamic-form-item
            :blur="() => $refs.storyTheme.onFieldBlur()"
            :is-preview="!isEditProduction"
            v-model="formData.storyTheme"
            :column="[
              {
                label: '标签',
                title: 'tag',
                select: [
                  { value: '0', label: '门派' },
                  { value: '1', label: '武侠' },
                  { value: '2', label: '玄幻' },
                ],
                placeholder: '请选择标签',
              },
              { label: '补充说明', title: 'desc', placeholder: '请填入补充说明' },
            ]"
          ></dynamic-form-item>

效果:

image-20220401135829218
image-20220401135829218

支持动态增减表单行

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档