基於vue,一個簡單實用的樹形穿梭框

前言

做者在作一個後臺管理項目時,有遇到過一個需求, 要求實用穿梭框,實現樹形結構上的數據操做 組件有引用網上的樹形框,在此基礎上對其進行了一些數據優化.node

樹形穿梭框組件代碼

樹形穿梭框組件
  /*
*使用前提
第一步:安裝組件
npm install el-tree-transfer --save
第二部:引入
import treeTransfer from 'el-tree-transfer'
*實現原理
樹形穿梭框,第一層的pid按index從0開始 ,依次1,2,3,4....便可, 核心在與子級中的pid的值為其父級id的值
後臺請求數據只需保證id不重複,以及有用於顯示對應項名稱的label便可, 此組件內已使用遞歸為每一個層級的元素添加pid,
不須要後臺傳入用於識別樹形的id或字段.

*使用聲明
引用組件 傳入 options集合  options集合中,包含 title:字符串數組,長度為2,  用於設置兩個穿梭框的標題文本,

mode為字符串, 用於設置穿梭框的模式, 不傳默認為'tansfer'樹形結構, 'addressList' 為通訊錄模式,

暫不支持通訊錄模式, 因為還沒有對數據進行處理及斷定

傳入API, 做爲請求數據源信息的地址,返回參數須要有 children label屬性

設置@add函數 接收向右添加選擇數據的結果, 返回四個參數,(fromData, toData, obj, arr)  , fromData為移動後數據源列表數據,
toData為移動後數據添加的目標列表的數據, obj為移動的節點keys、nodes、halfKeys、halfNodes對象. arr爲移動後右側數據添加
的目標列表的最終子節點的數組,(也就是說,該數組中的元素是沒有children節點的子元素,其沒有children屬性)

設置@remove函數,接收數據添加的目標列表移除的數據,參數同@add

*其餘功能: defaultCheckedKeys 屬性對應默認選中,傳入Data集合數組,做爲已選擇數組項,集合數組中必須有id屬性,
對應fromData中的最終子元素節點的id,便可..,
*其餘功能:defaultTransfer, 默認選中的穿梭一次.配合defaultCheckedKeys使用.
*/
<template>
<div>
  <tree-transfer :title="options.title" :from_data="fromData" :to_data="toData"
                 v-if="showT"
                 :defaultTransfer="TransGet"
                 :defaultProps="{label:'label'}"
                 :defaultCheckedKeys="editData"
                 @addBtn="add" @removeBtn="remove" :mode="options.mode" height='540px' filter openAll>
  </tree-transfer>
</div>
</template>

<script>
import treeTransfer from 'el-tree-transfer'

export default {
components: {treeTransfer},
name: 'transfer-tree',
props: {
  options: Object,
  API: String,
  Data: Array,
  deT: Boolean
},
data () {
  return {
    TransGet: false, // 當頁面加載完成後,再將該值變爲true,進行默認穿梭.
    showT: false,
    toData: [],
    fromData: [],
    editData: this.Data || []
    // checkedList: [  // 測試defaultCheckedKeys原理
    //   {
    //     id: 39,
    //     label: '12we'
    //   },
    //   {
    //     id: 40,
    //     label: '12we'
    //   },
    //   {
    //     id: 41,
    //     label: '12we'
    //   }
    // ]
  }
},
methods: {
  // 監聽穿梭框組件添加
  add (fromData, toData, obj) {
    // 樹形穿梭框模式transfer時,返回參數爲左側樹移動後數據、右側樹移動後數據、移動的{keys,nodes,halfKeys,halfNodes}對象
    // 通信錄模式addressList時,返回參數爲右側收件人列表、右側抄送人列表、右側密送人列表
    let arr = this.getTbs(toData)
    this.$emit('add', fromData, toData, obj, arr)
  },
  // 監聽穿梭框組件移除
  remove (fromData, toData, obj) {
    // 樹形穿梭框模式transfer時,返回參數爲左側樹移動後數據、右側樹移動後數據、移動的{keys,nodes,halfKeys,halfNodes}對象
    // 通信錄模式addressList時,返回參數爲右側收件人列表、右側抄送人列表、右側密送人列表
    let arr = this.getTbs(toData)
    this.$emit('remove', fromData, toData, obj, arr)
  },
  // 使用遞歸爲請求到的後臺數據的每一項添加一個對應樹形結構的pid
  setPid (item) {
    let that = this
    if (item.children) {
      item.children.map(e => {
        // 子級中的pid等於其父級中的id
        e['pid'] = item.id
        that.setPid(e)
      })
    } else {
      return false
    }
  },
  // 使用遞歸,設置全部id,保留最底層id不變
  setId (item) {
    let that = this
    if (item.children) {
      item.children.map((e, index) => {
        // 子級中的pid等於其父級中的id
        e.id = item.id + '-' + e.id
        that.setId(e)
      })
    } else {
      item.id = item.id.split('-')[item.id.split('-').length - 1]
      return false
    }
  },
  // 使用遞歸查找最終子元素
  getTarget (item, arr) {
    let that = this
    if (item.children) {
      item.children.map(e => {
        that.getTarget(e, arr)
      })
    } else {
      arr.push(item)
    }
  },
  // 使用遞歸,獲取到每一次添加或移除後toData中的最終子元素(沒有children的元素)的集合
  getTbs (toData) {
    let arr = []
    toData.map(item => {
      if (item.children) {
        this.getTarget(item, arr)
      } else {
        return false
      }
    })
    return arr
  }
  // // 使用遞歸獲取對應fromData中的元素.併爲元素添加選中狀態[研究defaultCheckedKeys原理實現]
  // getTree (item, id) {
  //   let that = this
  //   if (item.id !== id) {
  //     if (item.children) {
  //       item.children.map(e => {
  //         that.getTree(e, id)
  //       })
  //     } else {
  //       return false
  //     }
  //   } else {
  //     // 把找到的元素的選項變爲已選擇,
  //     item.indeterminate = true
  //     console.log(item)
  //   }
  // },
},
mounted () {
  // 因爲在created階段改變了數據,致使在有editData且ID有重複時,對數據進行處理後,樹形穿梭框沒法 獲取到正確的已選擇列表,
  // 因此使用延時,讓整個樹形框在數據處理完成後進行顯示.
  let that = this
  setTimeout(function () {
    that.showT = true
    that.TransGet = true
  }, 500)// 如依舊沒法顯示,可將延時時間加長,此處爲當前使用測試最短期.
  // this.$nextTick(() => { // 使用沒法達到效果, 數據更新先後.
  //   that.showT = true
  // })
},
async created () {
  if (this.options.mode === 'addressList') {
    this.$message('暫時未對通訊錄模式數據進行處理')
  } else {
    // 當爲樹形模式下
    let res = await this.$axios.get(this.API)
    let a = []
    // 判斷數據源res.data是否爲數組,不爲數組則要求其children屬性爲數組
    if (!Array.isArray(res.data)) {
      a = res.data.children
    } else {
      a = res.data
    }
    // 從新定義全部層級id,保證樹形層級之間id都不重複
    a.map((item, index) => {
      item.id = index + 1 + '-' + item.id
      this.setId(item)
    })
    // 將全部pid使用遞歸進行重定義,爲其父級id
    a.map((item, index) => {
      item['pid'] = 0
      this.setPid(item)
    })
    this.fromData = a
    // 當已選部分集合時,editData數組長度不爲0
    if (this.editData.length !== 0) {
      // 當爲修改界面展現時,經過editData中數組的各項id肯定toData中的數據結構.
      // 若是Data數組爲id元素,則不做處理, 若是爲集合元素,則進行提取id處理
      if (this.Data[0].id) {
        let arr = []
        this.Data.forEach(item => arr.push(item.id))
        this.editData = arr
      }
      // 測試defaultCheckedKeys原理
      // if (this.checkedList.length !== 0) {
      //   this.checkedList.forEach(item => {
      //     this.fromData.map(e => {
      //       this.getTree(e, item.id)
      //     })
      //   })
      //   console.log(this.fromData)
      // }
    }
  }
}
}
</script>

<style scoped>

</style>

  
複製代碼
操做實用組件
<template>
<div>
  <bread-crumb :items="items"></bread-crumb>
  <transfer-tree
    :options="options"
    API="/sys/brands/1/dealers/tree"
    @add="add"
    @remove="remove"
  ></transfer-tree>
</div>
</template>

<script>
import transferTree from '../../common/tranfer-tree'
export default {
components: {transferTree},
name: 'dashBoard',
data () {
  return {
    items: [
      {
        name: 'dashBoard'
      }
    ],
    options: {
      title: [
        '選擇車型',
        '已選車型'
      ]
    },
    Data: []
  }
},
methods: {
  add (fromData, toData, obj, arr) {
  },
  remove (fromData, toData, obj, arr) {
  }
}
}
</script>

<style scoped>

</style>

複製代碼

相關文章
相關標籤/搜索