This website requires JavaScript.
原创

Vue之智能动态表单组件

2020.07.07 10:37 

1 人喜欢
811 次阅读
0 条评论

父组件

<template>
  <div>
    <dynamic-form :data.sync="data" />
  </div>
</template>
<script>
import DynamicForm from '@/components/public/DynamicForm.vue'
export default {
  name: 'test',
  components: {
    'dynamic-form': DynamicForm
  },
  data () {
    const data = {
      str: '123123',
      num: 111,
      strAry: ['isis', 'wddd', '23sdfsdfs', 'wclgdj'],
      isOn: true,
      isNb: false,
      isC: true,
      daa: {
        num: 12312,
        ary: [
          {
            nb: 1,
            wc: ['nb', 'xdnb', '兄弟牛逼'],
            nbb: {
              strr: 'nbnbnb'
            }
          },
          {
            nb: 2,
            wc: ['nb222', 'xdnb2222', '兄弟牛逼2222'],
            nbb: {
              strr: 'nbnbnb22222',
              ary: [
                {
                  nb: 1,
                  wc: ['nb', 'xdnb', '兄弟牛逼'],
                  nbb: {
                    strr: 'nbnbnb'
                  }
                }
              ]
            }
          }
        ]
      }
    }
    return {
      data
    }
  }
}
</script>

动态表单组件DynamicForm

<template>
  <div class="recursive_form">
    <!--别挡我测试!-->
    <el-form ref="form" label-width="100px">
      <el-form-item v-for="(item,i) in dataKeyAry" :key="i" :label="item">
        <el-card shadow="hover" v-if="verifType(data[item]) === 'String'">
          <el-input v-model="data[item]"></el-input>
        </el-card>
        <el-card shadow="hover" v-if="verifType(data[item]) === 'Number'">
          <el-input v-model.number="data[item]"></el-input>
        </el-card>
        <el-card shadow="hover" v-if="verifType(data[item]) === 'Boolean'">
          <el-switch v-model="data[item]" active-color="#13ce66" inactive-color="#ff4949"></el-switch>
        </el-card>
        <el-card shadow="hover" v-if="verifType(data[item]) === 'Array'">
          <div
            v-if="verifType(data[item][0]) === 'String' || verifType(data[item][0]) === 'Number' || data[item].length === 0"
          >
            <el-tag
              :key="tag"
              style="margin:5px;"
              v-for="tag in data[item]"
              closable
              :disable-transitions="false"
              @close="handleClose(data[item],tag)"
            >{{tag}}</el-tag>
            <el-input
              class="input-new-tag"
              v-if="tagInputJson['inputVisible' + i]"
              v-model="tagInputJson['inputValue' + i]"
              :ref="'saveTagInput' + i"
              size="small"
              @keyup.enter.native="handleInputConfirm(data[item],i)"
              @blur="handleInputConfirm(data[item],i)"
            ></el-input>
            <el-button v-else class="button-new-tag" size="small" @click="showInput(i)">新增</el-button>
          </div>
          <div v-else>
            <DynamicForm
              :data.sync="item_"
              :isAryObj="true"
              :ItemAry.sync="data[item]"
              :itemIndex.sync="ii"
              v-for="(item_,ii) in data[item]"
              :key="ii"
            />
          </div>
        </el-card>
        <el-card shadow="hover" v-if="verifType(data[item]) === 'Object'">
          <DynamicForm :data.sync="data[item]" />
        </el-card>
      </el-form-item>
      <el-row
        type="flex"
        justify="center"
        style="margin-top: 5px;"
        v-if="verifType(data) === 'Object' && isAryObj === true"
      >
        <el-button type="warning" @click="removeItem()" icon="el-icon-minus" circle></el-button>
        <el-button
          type="primary"
          @click="addItem()"
          v-if="itemIndex === ItemAry.length - 1"
          icon="el-icon-plus"
          circle
        ></el-button>
      </el-row>
    </el-form>
  </div>
</template>

<script>
export default {
  name: 'DynamicForm',
  components: {},
  props: {
    data: Object,
    isAryObj: {
      type: Boolean,
      deafult: false
    },
    ItemAry: Array,
    itemIndex: Number
  },
  data () {
    return {
      dataKeyAry: [],
      tagInputJson: {
        inputVisible1: false, // 这里的会自动增加 inputVisible或inputValue,以此类推往下+,变成inputValue2、inputValue3等等
        inputValue1: ''
      }
    }
  },
  mounted () {
    this.dataKeyAry = Object.keys(this.data)
  },
  methods: {
    addItem () {
      let j = this.extend(this.ItemAry[0])
      this.kInitData(j)
      this.ItemAry.push(j)
    },
    removeItem () {
      if (this.ItemAry.length === 1) return this.$message.warning('不可清空!')
      this.ItemAry.splice(this.itemIndex, 1)
    },
    extend (source) {
      // 深拷贝数据
      let target
      if (typeof source === 'object') {
        target = Array.isArray(source) ? [] : {}
        for (let key in source) {
          if (source.hasOwnProperty(key)) {
            if (typeof source[key] !== 'object') target[key] = source[key]
            else target[key] = this.extend(source[key])
          }
        }
      } else target = source
      return target
    },
    kInitData (j) {
      // 将这个json中的所有值初始化一遍
      const keys = Object.keys(j)
      keys.forEach(e => {
        let v = j[e]
        if (this.verifType(v) === 'String') j[e] = ''
        if (this.verifType(v) === 'Number') j[e] = 0
        if (this.verifType(v) === 'Boolean') j[e] = true
        if (this.verifType(v) === 'Array') {
          if (this.verifType(v[0]) === 'Object') j[e] = [this.kInitData(v[0])]
          else j[e] = []
        }
        if (this.verifType(v) === 'Object') j[e] = this.kInitData(v)
      })
      return j
    },
    verifType (obj) {
      if (obj === undefined) return 'undefined'
      if (obj.constructor === Object) return 'Object'
      if (obj.constructor === Array) return 'Array'
      if (obj.constructor === Number) return 'Number'
      if (obj.constructor === String) return 'String'
      if (obj.constructor === Boolean) return 'Boolean'
    },
    handleClose (ary, tag) {
      ary.splice(ary.indexOf(tag), 1)
    },
    showInput (i) {
      this.$set(this.tagInputJson, `inputVisible${i}`, true)
      this.$nextTick(_ => {
        this.$refs[`saveTagInput${i}`][0].$refs.input.focus()
      })
    },
    handleInputConfirm (ary, i) {
      const val = this.tagInputJson[`inputValue${i}`]
      if (val) ary.push(val)
      this.$set(this.tagInputJson, `inputValue${i}`, '')
      this.$set(this.tagInputJson, `inputVisible${i}`, false)
    }
  },
  computed: {},
  created () {
    setInterval((_this = this) => {
      _this.$emit('update:data', _this.data)
    }, 1000)
  },

  watch: {}
}
</script>

<style lang="scss">
.recursive_form {
  margin-bottom: 10px;
  .el-form-item {
    position: relative;
  }
  .el-form-item__label {
    position: absolute;
    text-align: justify;
    word-break: break-all;
    top: 50%;
    transform: translate(0px, -50%);
  }
}
</style>

  • 😃
  • 😂
  • 😅
  • 😉
  • 😌
  • 😔
  • 😓
  • 😘
  • 😡
  • 😭
  • 😱
  • 😳
  • 😵
  • 🌚
  • 👍
  • 👎
  • 💪
  • 🌹
  • 💊
  • 🇨🇳
  • 🇺🇸