今天实现一个客户单位组织树的功能,不限层级,数据量巨大,采用vue-treeselect 实现懒加载 + 远程搜索

这是vue+ iview组件   element的需要改一下tooltip的写法

这个支持对选择的单位全部层级进行悬浮提示(也无法在下面下拉回显,下拉需要触发懒加载,只有远程搜索才能回显层级)

代码详细解释:

tooltip 设置了最大宽度 没有选择项  或者 下拉框弹开  会disabled禁用

limit是多选展示的最大数量,我这里设置1个

 :limitText="count => '更多' + count + '个'"          是  xxx  更多x个     对提示文字修改

flat是多选时候不设置这个回显会把 给出id的所有父级也勾选 

multiple是多选

:class="{ treeClass: isEdit }"   这个是开始想通过设置placeholder 来回显层级,后面作废

:options="product_map"    下拉框的数据源

:appendToBody="appendToBody"   相当于transfer   把组件渲染到最外层,不受父级样式影响

:value-consists-of="valueConsistsOf"   选择后@select 方法获取的数据类型(id还是node层级)

:disabled="disabled"   禁用

:placeholder="placeholder"  默认提示语

  :async="isAsync"   是否开启远程搜索模式

:load-options="isAsync ? asyncOptions : loadOptions"    懒加载和远程搜索触发的方法

  :defaultExpandLevel="expandLevel"  默认展开的层级  

  :cacheOptions="false"  是否缓存搜索的数据    这里缓存会有问题

v-model="checkRroduct"   绑定的数据id

一些为空的提示语

noChildrenText="没有数据"

noOptionsText="没有数据"

noResultsText="没有搜索结果"     

 控制打开搜索模式还是懒加载

@search-change="searchChange"

 @keydown.native="treeKeydown($event)"

@keyup.native="treeKeyup($event)"

@open="itemopen"

@close="itemClose"

下拉选项的自定义展示处理

因为选项的每一项 配置 disabled在远程搜索模式有问题,所以自己重写这个了

disabled是因为项目搜索后   一些选项要禁用 

(这个气死我了)  写的破大防

[
  {id: 151,  group_id : "150,151", group_name : "xxx,xxx" },
 {id: 152,  group_id : "150,151,152", group_name : "xxx,xxx,xxx" },
{id: 162,  group_id : "160,161,162" , group_name : "xxx,xxx,xxx"},
]

如上数据 group_id 是父级到它本身 我要把这个聚合为一条树,并且 根据id去禁用   上面的150,160,161  就需要禁用,也就是没有返回id和group_id 最后一位相同的选项 

<div slot="option-label" slot-scope="{ node }">
          <div :title="node.raw.label" v-if="node.raw.disabled" @click.prevent @click.stop :class="['labelClass', 'is-disabled']">
            {{ node.raw.label }}
          </div>
          <div :title="node.raw.label" v-else class="labelClass">
            {{ node.raw.label }}
          </div>
        </div>

选中项的自定义展示处理

<div slot="value-label" slot-scope="{ node }">{{ node.raw.longTitle }}</div>

接口讲解

queryTenantByLevel    传空查询所有一级客户    传parent_id查询用户子级(懒加载使用)

queryTenantByLike   传 staff_id查询这个id的用户信息   传company_name远程模糊搜索

方法讲解

handleEditTreeDataT   修改回显时候使用这个方法   handleEditTreeData是客户中心的特殊处理

handleEditTreeDataMuti  是多选的的回显

               上面三个都做了权限控制,queryTenantByLevel返回空证明这个客户权限低,使用登录客户的staff_id请求数据

clear()    这个是对页面重置时候要调用的  清空选择项    this.$refs.cusTree.clear()             

initTreeData   是新增和页面条件查询时候用的

toSelectProduct  选中选项后触发这个方法,返回node层级

asyncOptions  远程搜索  这里面做了一个时间控制,用户输入停止后1秒才会调接口  而且这个有  bug,必须callback(null, [])  后才能正常搜索,我这里控制第一次搜索结果为空,存在问题,后续研究吧

loadOptions 懒加载方法

后端返回数据需要这些字段

company_name  客户单位的名称

group_id   顶级到当前级别的id  如果当前是一级这个取当前用户的id

group_name  顶级到当前级别的company_name拼接

parent_id  当前用户的父级id  这个结合handleEditTreeData   客户中心是新增修改父级客户

                  所以this.checkRroduct = formData.parent_id    其他地方是staff_id

staff_id  当前用户的id

如何调用

首先全局注册一下这个组件

新建js文件

import Vue from 'vue'

import CusTree from './vue-treeselect/index.vue'

Vue.component('CusTree', CusTree)

在查询条件里面使用

<FormItem>
<CusTree style="width: 200px;" ref="cusTree" placeholder="客户单位" type="A" @getCheckRroduct="getCheckRroduct"></CusTree>
</FormItem>
//  重置 
resetData() {
      this.$refs.cusTree.clear()
      this.condition = JSON.parse(JSON.stringify(this.conditionInitCache))
      this.queryData() 
    },
//   这个是获取  checkRroduct是id     label是中文名(防止后端让你传中文搜索)
getCheckRroduct(formData) {
      this.condition.customer_id = formData.checkRroduct        //  formData.label
    },

在新增修改数据里面使用

type为A是新增  其他类型需要在下面触发handleEditTreeDataT修改回显

queryTenantByLike传staff_id是查这个用户的具体信息
<CusTree :type="params.type" ref="cusTree" placeholder="客户单位" @getCheckRroduct="getCheckRroduct"></CusTree>
if (this.params.type == 'M') {
      // console.log('params', this.params)
      this.formValidate.customerId = this.params.customer_id
      this.$http.operation.queryTenantByLike({ staff_id: this.formValidate.customerId }).then(resp => {
        if (resp && resp.result_code == '0') {
          this.$refs.cusTree.handleEditTreeDataT(resp.data[0])
        } else {
          this.$Message.error(resp.result_msg)
        }
      })
    }

在多选时候 

<CusTree flat multiple :type="params.type" ref="cusTree" placeholder="请选择通知人员" @getCheckRroduct="getCheckRroduct"></CusTree>
if (this.params.type == 'M') {
      // console.log('params', this.params)
      this.formValidate.customerId = this.params.customer_id
      this.$http.operation.queryTenantByLike({ staff_id: this.formValidate.customerId }).then(resp => {
        if (resp && resp.result_code == '0') {
          this.$refs.cusTree.handleEditTreeDataMuti(resp.data)
        } else {
          this.$Message.error(resp.result_msg)
        }
      })
    }

完整代码  

<template>
  <div>
    <Tooltip max-width="200" :disabled="tooltipDisabled" :content="formData.longTitle">
      <treeselect
        :limit="1"
        :clearable="clearable"
        :limitText="count => '更多' + count + '个'"
        :flat="flat"
        :multiple="multiple"
        :class="{ treeClass: isEdit }"
        :options="product_map"
        :appendToBody="appendToBody"
        :value-consists-of="valueConsistsOf"
        :disabled="disabled"
        :placeholder="placeholder"
        @select="toSelectProduct"
        :async="isAsync"
        :defaultExpandLevel="expandLevel"
        :cacheOptions="false"
        :disableFuzzyMatching="false"
        :load-options="isAsync ? asyncOptions : loadOptions"
        v-model="checkRroduct"
        noChildrenText="没有数据"
        noOptionsText="没有数据"
        noResultsText="没有搜索结果"
        @search-change="searchChange"
        @keydown.native="treeKeydown($event)"
        @keyup.native="treeKeyup($event)"
        @open="itemopen"
        @close="itemClose"
      >
        <div slot="option-label" slot-scope="{ node }">
          <div :title="node.raw.label" v-if="node.raw.disabled" :class="['labelClass', 'is-disabled']">
            {{ node.raw.label }}
          </div>
          <div :title="node.raw.label" v-else class="labelClass">
            {{ node.raw.label }}
          </div>
        </div>
        <div slot="value-label" slot-scope="{ node }">{{ node.raw.longTitle }}</div>
      </treeselect>
    </Tooltip>
  </div>
</template>

<script>
export default {
  components: {},
  props: {
    placeholder: {
      type: String,
      default: '请选择'
    },
    indexTTT: {
      type: Number,
      default: 0
    },
    type: {
      type: String,
      default: 'A'
    },
    valueConsistsOf: {
      type: String,
      default: 'ALL_WITH_INDETERMINATE'
    },
    isEdit: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    appendToBody: {
      type: Boolean,
      default: false
    },
    multiple: {
      type: Boolean,
      default: false
    },
    flat: {
      type: Boolean,
      default: false
    },
    clearT: {
      type: Boolean,
      default: false
    },
    clearable: {
      type: Boolean,
      default: true
    },
    khzx: {
      type: Boolean,
      default: false
    },
    tooltipShow: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      isAsync: false,
      checkRroductT: null,
      userInfo: JSON.parse(this.$libs.getSessionStorage('user-info')),
      tooltipDisabled: true,
      checkRroduct: null,
      expandLevel: 0,
      product_map: [],
      product_mapTemp: [],
      formData: {},
      searchQuery: '',
      timer: null,
      dataT: [],
      formDataID: ''
    }
  },
  watch: {
    checkRroduct(val) {
      this.formData.checkRroduct = val || ''
      this.tooltipDisabled = this.tooltipShow ? true : !val
      if (!val) {
        this.formData.label = ''
        this.formData.longTitle = ''
      }
      if (!(this.clearT && this.type != 'A')) {
        this.$emit('getCheckRroduct', this.formData, this.indexTTT)
      }
    }
  },
  mounted() {
    // console.log(this.type)
    if (this.type == 'A') {
      this.initTreeData()
    }
  },
  methods: {
    clear() {
      this.checkRroduct = null
      this.tooltipDisabled = true
    },
    // 客户中心显示父级
    handleEditTreeData(formData) {
      this.formDataID = formData.staff_id
      if (!this.isEdit) {
        this.$http.operation.queryTenantByLevel().then(resp => {
          if (resp && resp.result_code == '0') {
            if (resp.data.length == 0) {
              this.$http.operation.queryTenantByLike({ staff_id: this.userInfo.staff_id }).then(resp => {
                if (resp && resp.result_code == '0') {
                  resp.data.map(item => {
                    item.id = item.staff_id
                    item.label = item.company_name
                    item.longTitle = item.company_name
                    item.children = null
                    item.disabled = this.khzx && this.type == 'M' ? (item.staff_id == formData.staff_id ? true : false) : false
                  })
                  if (!formData.group_id) {
                    this.product_map = resp.data
                    this.product_mapTemp = resp.data
                  } else {
                    const parentIds = formData.group_id.split('/')
                    this.arrInsert(parentIds, resp.data).then(finalData => {
                      // 在这里,finalData 就是 arrInsert 方法返回的最终 dataT
                      resp.data = this.addLongTitle(finalData, formData.staff_id)
                      this.formData.longTitle = formData.group_name
                      this.formData.label = formData.company_name
                      this.formData.group_id = formData.group_id
                      this.checkRroduct = formData.parent_id
                      this.product_map = resp.data
                      this.product_mapTemp = resp.data
                    })
                  }
                  this.product_mapTemp = resp.data
                } else {
                  this.$Message.error(resp.result_msg)
                }
              })
            } else {
              resp.data.map(item => {
                item.id = item.staff_id
                item.label = item.company_name
                item.longTitle = item.company_name
                item.children = null
                item.disabled = this.khzx && this.type == 'M' ? (item.staff_id == formData.staff_id ? true : false) : false
              })
              if (!formData.group_id) {
                this.product_map = resp.data
                this.product_mapTemp = resp.data
              } else {
                const parentIds = formData.group_id.split('/')
                this.arrInsert(parentIds, resp.data).then(finalData => {
                  // 在这里,finalData 就是 arrInsert 方法返回的最终 dataT
                  resp.data = this.addLongTitle(finalData, formData.staff_id)
                  this.formData.longTitle = formData.group_name
                  this.formData.label = formData.company_name
                  this.formData.group_id = formData.group_id
                  this.checkRroduct = formData.parent_id
                  this.product_map = resp.data
                  this.product_mapTemp = resp.data
                })
              }
            }
          } else {
            this.$Message.error(resp.result_msg)
          }
        })
      } else {
        this.formData.longTitle = formData
        this.tooltipDisabled = this.tooltipShow ? true : false
      }
    },
    // 其他页面修改
    handleEditTreeDataT(formData) {
      this.$http.operation.queryTenantByLevel().then(resp => {
        if (resp && resp.result_code == '0') {
          if (resp.data.length == 0) {
            this.$http.operation.queryTenantByLike({ staff_id: this.userInfo.staff_id }).then(resp => {
              if (resp && resp.result_code == '0') {
                resp.data.map(item => {
                  item.id = item.staff_id
                  item.label = item.company_name
                  item.longTitle = item.company_name
                  item.children = null
                })
                const parentIds = formData.group_id.split('/')
                this.arrInsert(parentIds, resp.data).then(finalData => {
                  // 在这里,finalData 就是 arrInsert 方法返回的最终 dataT
                  resp.data = this.addLongTitle(finalData, formData.staff_id)
                  this.formData.longTitle = formData.group_name
                  this.formData.label = formData.company_name
                  this.formData.group_id = formData.group_id
                  this.checkRroduct = formData.staff_id
                  this.checkRroductT = formData.staff_id
                  this.product_map = resp.data
                  this.product_mapTemp = resp.data
                })
              } else {
                this.$Message.error(resp.result_msg)
              }
            })
          } else {
            resp.data.map(item => {
              item.id = item.staff_id
              item.label = item.company_name
              item.longTitle = item.company_name
              item.children = null
            })
            const parentIds = formData.group_id.split('/')
            this.arrInsert(parentIds, resp.data).then(finalData => {
              // 在这里,finalData 就是 arrInsert 方法返回的最终 dataT
              resp.data = this.addLongTitle(finalData, formData.staff_id)
              this.formData.longTitle = formData.group_name
              this.formData.label = formData.company_name
              this.formData.group_id = formData.group_id
              this.checkRroduct = formData.staff_id
              this.checkRroductT = formData.staff_id
              this.product_map = resp.data
              this.product_mapTemp = resp.data
            })
          }
        } else {
          this.$Message.error(resp.result_msg)
        }
      })
    },
    addLongTitle(treeData, staff_id) {
      // 从根节点开始,不需要前缀
      return treeData.map(node => addNodeLongTitle(node, ''))

      function addNodeLongTitle(node, prefix) {
        // 如果没有提供title,则使用company_name作为默认title
        const title = node.company_name
        // 拼接前缀和当前节点的title
        node.longTitle = (prefix ? prefix + ' / ' : '') + title
        node.isDefaultExpanded = staff_id == node.id ? true : false

        // 如果存在子节点,递归地为它们添加longTitle,并传递更新后的前缀
        if (node.children && node.children.length > 0) {
          node.children = node.children.map(child => addNodeLongTitle(child, node.longTitle))
        }

        return node
      }
    },
    async arrInsert(parentIds, data) {
      let dataT = JSON.parse(JSON.stringify(data))
      const findNodeById = (id, nodes, data) => {
        let nodesT = nodes
        for (let i = 0; i < nodesT.length; i++) {
          if (nodesT[i].id == id) {
            nodesT[i].children = data
          }
          if (nodesT[i].children && nodesT[i].children.length > 0) {
            findNodeById(id, nodesT[i].children, data)
          }
        }
        return nodesT
      }
      for (let i = 0; i < parentIds.length; i++) {
        let respT = await this.$http.operation.queryTenantByLevel({ parent_id: parentIds[i] })
        respT.data.map(item => {
          item.id = item.staff_id
          item.label = item.company_name
          item.children = null
        })
        dataT = findNodeById(parentIds[i], dataT, respT.data.length == 0 ? null : respT.data)
      }
      return dataT
    },
    // 多选逻辑
    handleEditTreeDataMuti(formData) {
      this.$http.operation.queryTenantByLevel().then(resp => {
        if (resp && resp.result_code == '0') {
          if (resp.data.length == 0) {
            this.$http.operation.queryTenantByLike({ staff_id: this.userInfo.staff_id }).then(resp => {
              if (resp && resp.result_code == '0') {
                resp.data.map(item => {
                  item.id = item.staff_id
                  item.label = item.company_name
                  item.longTitle = item.company_name
                  item.children = null
                })
                const dataT = JSON.parse(JSON.stringify(this.handleTreeById(formData, true)))
                this.product_map = dataT
                this.checkRroduct = formData.map(item => item.staff_id)
                this.formData.longTitle = formData.map(item => item.group_name).join(',')
                this.product_mapTemp = resp.data
              } else {
                this.$Message.error(resp.result_msg)
              }
            })
          } else {
            resp.data.map(item => {
              item.id = item.staff_id
              item.label = item.company_name
              item.longTitle = item.company_name
              item.children = null
            })
            const dataT = JSON.parse(JSON.stringify(this.handleTreeById(formData, true)))
            this.product_map = dataT
            this.checkRroduct = resp.data.map(item => item.staff_id)
            this.formData.longTitle = resp.data.map(item => item.group_name)
            this.product_mapTemp = resp.data
          }
        } else {
          this.$Message.error(resp.result_msg)
        }
      })
    },
    initTreeData() {
      this.$http.operation.queryTenantByLevel().then(resp => {
        if (resp && resp.result_code == '0') {
          if (resp.data.length == 0) {
            this.$http.operation.queryTenantByLike({ staff_id: this.userInfo.staff_id }).then(resp => {
              if (resp && resp.result_code == '0') {
                resp.data.map(item => {
                  item.id = item.staff_id
                  item.label = item.company_name
                  item.longTitle = item.company_name
                  item.children = null
                })
                this.product_map = resp.data
                this.product_mapTemp = resp.data
              } else {
                this.$Message.error(resp.result_msg)
              }
            })
          } else {
            resp.data.map(item => {
              item.id = item.staff_id
              item.label = item.company_name
              item.longTitle = item.company_name
              item.children = null
            })
            this.product_map = resp.data
            this.product_mapTemp = resp.data
          }
        } else {
          this.$Message.error(resp.result_msg)
        }
      })
    },
    toSelectProduct(val) {
      if (this.clearT && this.type != 'A') {
        this.$Modal.confirm({
          title: '确认',
          content: '是否要改变客户单位,后续数据将被清空?',
          onOk: () => {
            if (val.disabled) {
              this.$nextTick(() => {
                this.checkRroduct = null
              })
              return
            }
            if (val.group_id) {
              this.formData.group_id = val.group_id + '/' + val.id
              this.formData.parent_id = val.id
            } else {
              this.formData.group_id = val.id
              this.formData.parent_id = val.id
            }
            this.formData.label = val.label
            this.formData.longTitle = val.longTitle
            this.$emit('getCheckRroduct', this.formData, this.indexTTT)
          },
          onCancel: () => {
            this.checkRroduct = this.checkRroductT
            this.$Message.info('取消 ')
          }
        })
      } else {
        if (val.disabled) {
          this.$nextTick(() => {
            this.checkRroduct = null
          })
          return
        }
        if (val.group_id) {
          this.formData.group_id = val.group_id + '/' + val.id
          this.formData.parent_id = val.id
        } else {
          this.formData.group_id = val.id
          this.formData.parent_id = val.id
        }
        this.formData.label = val.label
        this.formData.longTitle = val.longTitle
        this.$emit('getCheckRroduct', this.formData, this.indexTTT)
      }
    },
    asyncOptions({ action, parentNode, searchQuery, callback }) {
      // console.log(action, 1)
      // console.log('isAsync1', this.isAsync)
      if (action == 'ASYNC_SEARCH') {
        this.searchQuery = searchQuery
        clearTimeout(this.timer)
        this.timer = setTimeout(() => {
          this.$http.operation.queryTenantByLike({ company_name: this.searchQuery }).then(resp => {
            if (resp && resp.result_code == '0') {
              resp.data.map(item => {
                item.id = item.staff_id
                item.label = item.company_name
              })
              const dataT = JSON.parse(JSON.stringify(this.handleTreeById(resp.data)))
              this.dataT = dataT
              callback(null, dataT)
            } else {
              this.$Message.error(resp.result_msg)
            }
          })
          this.timer = null
        }, 1000)
      } else {
        callback(null, this.dataT)
      }
    },
    loadOptions({ action, parentNode, searchQuery, callback }) {
      // console.log(action, 2)
      // console.log('isAsync2', this.isAsync)
      if (action == 'LOAD_CHILDREN_OPTIONS') {
        this.$http.operation.queryTenantByLevel({ parent_id: parentNode.id }).then(resp => {
          if (resp && resp.result_code == '0') {
            resp.data.map(item => {
              item.id = item.staff_id
              item.label = item.company_name
              item.longTitle = parentNode.longTitle + ' / ' + item.company_name
              item.children = null
              item.disabled = this.khzx && this.type == 'M' ? (item.staff_id == this.formDataID ? true : false) : false
            })
            parentNode.children = resp.data
            callback()
          } else {
            this.$Message.error(resp.result_msg)
          }
        })
      }
    },
    handleTreeById(data, flag) {
      const tree = []
      let dataT = data.map(item => String(item.staff_id))
      if (this.khzx && this.type == 'M') {
        dataT.push(this.formDataID)
      }
      // console.log('dataT: ', dataT)

      data.forEach(item => {
        const groupId = item.group_id.split('/')
        const groupName = item.group_name.split('/')

        let currentLevel = tree

        groupId.forEach((id, index) => {
          const existingNode = currentLevel.find(node => node.id === id)
          if (existingNode) {
            currentLevel = existingNode.children
          } else {
            const newNode = {
              id,
              label: groupName[index],
              group_id: groupId.slice(0, index).join('/'),
              longTitle: groupName.slice(0, index + 1).join('/'),
              children: [],
              disabled: flag ? false : !dataT.includes(id)
            }
            currentLevel.push(newNode)
            currentLevel = newNode.children
          }
        })
      })
      // 遍历tree并删除children为空数组的项
      function pruneEmptyChildren(nodes) {
        return nodes.filter(node => {
          if (node.children && node.children.length === 0) {
            delete node.children // 删除children属性
            return true // 保留这个节点,因为它可能还有其他有用的属性
          }
          if (node.children) {
            pruneEmptyChildren(node.children) // 递归处理子节点
          }
          return true // 保留这个节点
        })
      }

      // 在完成树的构建后,调用pruneEmptyChildren函数
      pruneEmptyChildren(tree)
      return tree
    },
    searchChange(val) {
      if (!val) {
        this.isAsync = false
        this.expandLevel = 0
        this.product_map = JSON.parse(JSON.stringify(this.product_mapTemp))
      } else {
        this.isAsync = true
        this.expandLevel = Infinity
      }
    },
    // 输入时打开异步,下拉open/close关闭异步
    treeKeydown() {
      // console.log('treeKeydown')
      this.isAsync = true
      this.expandLevel = Infinity
    },
    treeKeyup(e) {
      // if (!e.target.value) {
      //   this.isAsync = false
      //   this.expandLevel = 0
      // }
    },
    itemopen() {
      // console.log('itemopen')
      this.tooltipDisabled = true
      this.isAsync = false
      this.expandLevel = 0
      this.product_map = JSON.parse(JSON.stringify(this.product_mapTemp))
    },
    itemClose() {
      // console.log('itemclose')
      this.isAsync = false
      this.tooltipDisabled = this.tooltipShow ? true : !this.checkRroduct
      this.expandLevel = 0
    },
    transformData(groupId, groupName, staff_id, name, flag) {
      const groups = groupId.split('/')
      const names = groupName.split('/')

      // 检查groupId和groupName的分割是否匹配
      if (groups.length !== names.length) {
        throw new Error('groupId和groupName的分割不匹配')
      }

      // 递归函数来构建树形结构
      function buildTree(index) {
        if (flag && index >= groups.length) {
          // 当到达叶子节点时,添加额外的staff信息
          return {
            id: staff_id,
            label: name,
            longTitle: `${names.slice(0, index).join(' / ')} / ${name}`,
            children: []
          }
        } else if (index >= groups.length) {
          return null
        }
        const currentGroupId = groups[index]
        const currentGroupName = names[index]
        const longTitle = index === 0 ? currentGroupName : `${names.slice(0, index + 1).join(' / ')}`

        const child = buildTree(index + 1) // 递归构建子节点

        return {
          id: Number(currentGroupId),
          label: currentGroupName,
          longTitle: longTitle,
          children: child ? [child] : flag ? null : [] // 如果有子节点,则放入数组中
        }
      }

      // 从根节点开始构建树
      const root = buildTree(0)

      return root
    }
  }
}
</script>

<style lang="scss" scoped>
.vue-treeselect {
  font-size: 14px;
}
.labelClass {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  color: #333;
}
.treeClass {
  ::v-deep .vue-treeselect__placeholder {
    color: black;
    font-size: 14px;
  }
}
.is-disabled {
  /* 设置禁用选项的样式 */
  color: #ccc;
  cursor: not-allowed;
  /* 可以添加更多样式 */
}
</style>

后记: 附上vue-treeselect的组件样式修改

// 选择框的样式
::v-deep .vue-treeselect__control {
  background-color: rgb(10, 19, 33) !important;
  border: rgb(10, 19, 33);
}
// 下拉框的样式
// ::v-deep .vue-treeselect__option {
//   color: #2d8cf0;
// }
// 选中项的样式
::v-deep .vue-treeselect__single-value {
  color: #2d8cf0;
}
// 默认提示语的样式
::v-deep .vue-treeselect__placeholder {
  color: #2d8cf0;
}