vue 中手动生成树型结构DOM

392 阅读1分钟

需求是:通过手动add生成json数据,包括树形结构数据,value的类型有三种可以选择,String、Number、Object。有可以改进的地方还希望大家不吝赐教

image.png

DOM结构递归

<a-tabs v-if="paramsType === 1" @change="tabCallback">
        <a-tab-pane  key="1" tab="模板">
          <div class="params-model" v-if="currentTab === '1'">
            <ul class="params-list">
              <li class="params-item">
                <div class="input-wrap">
                  <span>key</span>
                  <span>value类型</span>
                  <span>value</span>
                </div>
                <div class="tools-wrap">
                  <span>增加</span>
                  <span>删除</span>
                </div>
              </li>
              <li v-for="item in paramsList" :key="item.id">
                <div class="params-item">
                  <div class="input-wrap">
                    <span><a-input v-model="item.key" placeholder="请输入key"></a-input></span><!--key-->
                    <span>
                      <a-select  v-model="item.type" style="width: 192px" default-value="String">
                        <a-select-option value="String">
                          String
                        </a-select-option>
                        <a-select-option value="Number">
                          Number
                        </a-select-option>
                        <a-select-option value="Object">
                          Object
                        </a-select-option>
                      </a-select>
                    </span><!--value type-->
                    <span><a-input :disabled="item.type === 'Object'" v-model="item.value" placeholder="请输入value"></a-input></span><!--value-->
                  </div>
                  <div class="tools-wrap">
                    <span class="add-wrap blue">
                      <a-icon class="add-item" @click="addJsonBtn(item)" type="plus" />
                      <div v-if="item.type === 'Object'" class="add-type-wrap">
                        <p @click="addObjectBtn(item, '1')" class="item">兄弟节点</p>
                        <p @click="addObjectBtn(item, '2')" class="item">子节点</p>
                      </div>
                    </span>
                    <span v-if="item.id !== 0" @click="deleteBtn(item)" class="red"><a-icon type="close" /></span>
                  </div>
                </div>
                <ul class="params-list" v-if="item.children && item.children.length">
                  <dialog-params-node :paramsList="item.children"></dialog-params-node>
                </ul>
              </li>
            </ul>
          </div>
        </a-tab-pane>
        <a-tab-pane key="2" tab="预览">
          <div>
            <textarea v-if="currentTab === '2'" rows="5" cols="100" v-html="previewObj" />
            <p v-else>暂无数据</p>
          </div>
        </a-tab-pane>
      </a-tabs>

子组件

<li v-for="item in paramsList" :key="item.id">
      <div class="params-item">
        <div class="input-wrap">
          <span :style="'padding-left:' + item.style * 10 + 'px'" ><a-input v-model="item.key" placeholder="请输入key"></a-input></span><!--key-->
          <span>
            <a-select v-model="item.type" style="width: 192px" default-value="String">
              <a-select-option value="String">
              String
              </a-select-option>
              <a-select-option value="Number">
              Number
              </a-select-option>
              <a-select-option value="Object">
              Object
              </a-select-option>
            </a-select>
          </span><!--value type-->
          <span><a-input :disabled="item.type === 'Object'" v-model="item.value" placeholder="请输入value"></a-input></span><!--value-->
        </div>
        <div class="tools-wrap">
          <span class="add-wrap blue">
            <a-icon class="add-item" @click="addJsonBtn(item)" type="plus" />
            <div v-if="item.type === 'Object'" class="add-type-wrap">
              <p @click="addObjectBtn(item, '1')" class="item">兄弟节点</p>
              <p @click="addObjectBtn(item, '2')" class="item">子节点</p>
            </div>
          </span>
          <span v-if="item.id !== 0" @click="deleteBtn(item)" class="red"><a-icon type="close" /></span>
        </div>
      </div>
      <ul class="params-list" v-if="item.children && item.children.length">
        <dialog-params :paramsList="item.children"></dialog-params>
      </ul>
    </li>

js

methods: {
    paramsDataOk () {
      if (this.paramsType === 1) {
        // 手动输入
        this.previewJson()
        this.$emit('paramsOk', this.previewObj)
      } else {
        // 导入json
        this.$emit('paramsOk', JSON.parse(this.paramsText))
      }
      this.$emit('update:showParams', false)
    },
    tabCallback (key) {
      if (key === '2') {
        this.previewJson()
      }
      this.currentTab = key
    },
    previewJson () {
      // 预览
      const json = {}
      this.paramsList.forEach(item => {
        if (item.type === 'Number') {
          json[item.key] = Number(item.value)
        } else if (item.type === 'Object') {
          json[item.key] = {}
          if (item.hasOwnProperty('children')) {
            item.children.forEach(element => {
              if (element.type === 'Number') {
                json[item.key][element.key] = Number(element.value)
              } else if (element.type === 'Object') {
                json[item.key][element.key] = {}
              } else {
                json[item.key][element.key] = element.value
              }
              // json[item.key][element.key] = element.value
              if (element.hasOwnProperty('children')) {
                this.parsingJson(json[item.key][element.key], element.children)
              }
            })
          }
        } else {
          json[item.key] = item.value
        }
      })
      this.previewObj = json
    },
    parsingJson (json, array) {
      for (let index = 0; index < array.length; index++) {
        const element = array[index]
        if (element.type === 'Number') {
          json[element.key] = Number(element.value)
        } else if (element.type === 'Object') {
          json[element.key] = {}
        } else {
          json[element.key] = element.value
        }
        if (element.hasOwnProperty('children') === false) {
          if (element.type === 'Number') {
            json[element.key] = Number(element.value)
          } else if (element.type === 'Object') {
            json[element.key] = {}
          } else {
            json[element.key] = element.value
          }
          break
        } else {
          this.parsingJson(json[element.key], element.children)
        }
      }
    },
    addJsonBtn (row) {
      if (row.type !== 'Object') {
        this.addItem(row)
      }
    },
    addItem (row) {
      const obj = { id: this.getID(3), value: '', key: '', type: 'String', style: 1 }
      this.paramsList.forEach((item, index) => {
        if (item.id === row.id) {
          this.paramsList.splice(index + 1, 0, obj)
        }
      })
    },
    addObjectBtn (row, type) {
      // type 1-兄弟节点 2-子节点
      switch (type) {
        case '1':
          this.addItem(row)
          break
        case '2': {
          const obj = { id: this.getID(3), parentId: row.id, value: '', key: '', type: 'String', style: row.style + 1 }
          const arr = JSON.parse(JSON.stringify(this.paramsList))
          arr.forEach((item, index) => {
            if (item.id === row.id) {
              if (item.hasOwnProperty('children') === false) {
                item.children = []
              }
              item.children.push(obj)
              // this.paramsList.splice(index + 1, 0, obj)
            }
          })
          this.paramsList = arr
        }
          break
      }
    },
    deleteBtn (row) {
      this.paramsList.forEach((item, index) => {
        if (item.id === row.id) {
          this.paramsList.splice(index, 1)
        }
      })
    },
    cancelBtn () {
      this.$emit('update:showParams', false)
    },
    getID (length) {
      return Number(Math.random().toString().substr(3, length) + Date.now()).toString(36)
    }
  },