您的位置:首页 > 健康 > 美食 > 开发区人力资源服务中心_在线logo设计生成器_百度有人工客服吗_广州网络推广公司有哪些

开发区人力资源服务中心_在线logo设计生成器_百度有人工客服吗_广州网络推广公司有哪些

2025/3/22 9:43:25 来源:https://blog.csdn.net/qq_52526079/article/details/146413327  浏览:    关键词:开发区人力资源服务中心_在线logo设计生成器_百度有人工客服吗_广州网络推广公司有哪些
开发区人力资源服务中心_在线logo设计生成器_百度有人工客服吗_广州网络推广公司有哪些

 动态加载之前已经发过一次,有想了解的的可在本人主页找下

一.效果展示

1.打开弹框默认展开

2.展示不全的节点才出现鼠标悬浮效果

 3.选中查询的节点并展开各级

例如:选中节点第一条节点

 备注:当前可选中的数据只是当下一级下的所有二三四级(避免卡顿,就没有实现所有的一级下的二三四级),当切换一级,更新下拉数据,因此只实现了当前被选中的一级下的子级展开

 选中后自动展开对应的三四级(因为默认已经展开了某个一级下的所有二级)

 功能总结:

  • 可点击父级展开下一个子级(效果同elementPlus中的级联面板)
  • 可在下拉中输入要查找的节点(边输入边更新与输入内容匹配的节点,与elementPlus中select可查询组件效果一致)
  • 可在下拉选中某一条数据,并展开对应的三四级,并且自动滚动到顶部
  • 部分节点展示不全,有鼠标悬浮展示这一条全部信息

 二.默认展开节点

1.监听弹框打开,展开默认一级下的二级节点

watch(

  () => props.visible,

  (val) => {

    searchData.value = ''       // 清空搜索框

    if (val) {

      time2.value = setTimeout(() => {

        const index = collectOptions.value.findIndex((item) => item.name === 'US')  // 默认选中US,通过US去当下一级的option去获取对应的的index

        toClickSecondCascaderCollect(index, 0)  //将index传给toClickSecondCascaderCollect,0代表级联第一级数据,1代表第二级数据,2代表第三级数据

      }, 1000)

    }

  }

)

 2.通过操作dom,js实现点击对应的某一级

//触发点击事件,index 节点位置,number 级联面板四级中的一级

const toClickSecondCascaderCollect = (index, number?) => {

  const el = document.querySelectorAll(`.el-cascader-menu`)[number].querySelectorAll(`.el-cascader-node`)

  if (el && el[index]) {

    return new Promise((resolve) => {

      el[index].click()   // 触发点击事件,展开传过来的index对应的节点

      time.value = setTimeout(() => {

        resolve()     // 延迟1秒执行,防止执行过快,防止上一级没有展示出来就点击而导致找不到click报错

      }, 1000)

    })

  }

  return Promise.resolve()

}

  三.鼠标悬浮效果

1.使用el-tooltip组件展示所有的节点的提示效果

<el-cascader-panel

        ref="cascaderCollect"

        v-model="collectValue"

        :props="address"

        :options="collectOptions"

        @expandChange="handleExpandChange"

      >

        <template #default="{ node, data }">

//v-if为真,展示悬浮效果

          <el-tooltip

            v-if="isTextTruncated(data.name)"

            effect="dark"

            :content="data.name"

            placement="top-start"

          >

            <span class="truncated-text">{{ data.name }}</span>

          </el-tooltip>

//v-if为假,不展示悬浮效果,只展示纯文本

          <span v-else class="regular-text">{{ data.name }}</span>

        </template>

      </el-cascader-panel>

//对应css

.truncated-text {

  display: inline-block;

  max-width: 213px; /* 设置你希望的宽度 */

  white-space: nowrap;

  overflow: hidden;

  text-overflow: ellipsis;

  vertical-align: middle;

}

.regular-text {

  white-space: normal; /* 显示完整文本,没有省略 */

}

 2.判断当下节点文本长度,判断是否展示鼠标悬浮效果

const isTextTruncated = (text) => {

  // 你可以实现逻辑检查文本是否超过某个长度

  const maxLength = 28 // 可根据需要调整最大长度

  return text.length > maxLength

}

四.展开选中节点

1.select下拉添加@change事件

<el-select-v2

                v-model="searchData"

                filterable

                clearable

                :options="searchDataOptions"

                placeholder="请输入"

                style="width: 700px"

                @change="searchChange"

              />

2.select选中改变,就循环遍历选中节点,实现一级级逐层点击,以选择这一条为例"Health & Household,Food Wrap, Foils"

const searchChange = async (changeData) => {

  // 点击后获取的changeData数据分3段数据,分别是对应二三四级要展开的节点

  if (!changeData) return

  const currdata = changeData?.split(',')

  console.log('currdata', currdata)   // ["Health & Household","Food Wrap", "Foils"]

  for (let i = 0; i < 2; i++) {

    let index = -1

    if (i === 0) {

//先拿“Health & Household”去当前已经展开的第二级的options中去遍历,获取到index

      index = optionSecond.value.findIndex((item) => item.name === currdata[0])

    } else if (i === 1) {

//再拿“Food Wrap”去当前已经展开的第三级的options中去遍历,获取到index

      let secondParams = optionSecond.value.find((item) => item.name === currdata[0])

      console.log('secondParams', secondParams)

      const res = await ApiBusiType.marketDataCollection.queryGraduallyCollectionConfig(secondParams)

      optionThird.value = res.result || []

      console.log('res1111', res)

      index = optionThird.value.findIndex((item) => item.name === currdata[1])

    }else if(i === 2){

//这一层判断仅仅是用来让第四级滚动到顶部

//再拿“Foils”去当前已经展开的第三级的options中去遍历,获取到index,

      index = optionFourth.value.findIndex((item) => item.name === currdata[2])

    }

    if (index !== -1) {

      await nextTick()  // 等待数据渲染完成

      await toClickSecondCascaderCollect(index, i + 1)  执行点击事件

    }

  }

}

//第一次index就是“Health & Household”在第二级所在的index,number是1,表示要点击第二级,展示出第三级别。

//第二次index就是“Food Wrap”在第二级所在的index,number是2,表示要点击刚展示的第三级,展示出第四级。此时就完成了展示一二三四级

const toClickSecondCascaderCollect = (index, number?) => {

  const el = document.querySelectorAll(`.el-cascader-menu`)[number].querySelectorAll(`.el-cascader-node`)

  if (el && el[index]) {

    return new Promise((resolve) => {

      el[index].click()   // 触发点击事件,展开传过来的index对应的节点

      time.value = setTimeout(() => {

        resolve()     // 延迟1秒执行,防止执行过快,防止上一级没有展示出来就点击而导致找不到click报错

      }, 1000)

    })

  }

  return Promise.resolve()

}

五.选中节点自动滚动到顶部

//触发点击事件,index 节点位置,number 级联面板四级中的一级

const toClickSecondCascaderCollect = (index, number?) => {

  const el = document.querySelectorAll(`.el-cascader-menu`)[number].querySelectorAll(`.el-cascader-node`)

  if (el && el[index]) {

    return new Promise((resolve) => {

      el[index].click()   // 触发点击事件,展开传过来的index对应的节点

      el[index].scrollIntoView({ behavior: 'smooth', block: 'start' })  //自动滚到顶部

      time.value = setTimeout(() => {

        resolve()     // 延迟1秒执行,防止执行过快,防止上一级没有展示出来就点击而导致找不到click报错

      }, 1000)

    })

  }

  return Promise.resolve()

}

六.组件源码

<template><div><Dialog title="添加采集" :visible.sync="isShow" width="1030px" @close="handleClose"><div class="header-title"><div class="add-header"><el-form :inline="true"><el-form-item label="关键词搜索"><el-select-v2v-model="searchData"filterableclearable:options="searchDataOptions"placeholder="请输入"style="width: 700px"@change="searchChange"/></el-form-item><el-form-item><!-- <el-button type="primary" @click="searchAddData">搜索</el-button> --></el-form-item></el-form></div></div><div class="selection-container"><div class="selection-column"><h3>商店名称</h3><!-- <el-checkbox-group v-model="ruleForm.collectSite"><el-checkbox v-for="item in collectSiteOptions" :key="item" :label="item">{{ item }}</el-checkbox></el-checkbox-group> --></div><div class="selection-column"><h3>类别</h3><!-- <el-checkbox-group v-model="ruleForm.category"><el-checkbox v-for="item in categoryOptions" :key="item" :label="item">{{ item }}</el-checkbox></el-checkbox-group> --></div><div class="selection-column"><h3>商品类型</h3><!-- <el-checkbox-group v-model="ruleForm.productType"><el-checkbox v-for="item in productTypeOption" :key="item" :label="item">{{ item }}</el-checkbox></el-checkbox-group> --></div><div class="selection-column"><h3>商品类型关键词</h3><!-- <el-checkbox-group v-model="ruleForm.productTypeKeyword"><el-checkbox v-for="item in keywordOption" :key="item" :label="item">{{ item }}</el-checkbox></el-checkbox-group> --></div></div><el-cascader-panelref="cascaderCollect"v-model="collectValue":props="address":options="collectOptions"@expandChange="handleExpandChange"><template #default="{ node, data }"><el-tooltipv-if="isTextTruncated(data.name)"effect="dark":content="data.name"placement="top-start"><span class="truncated-text">{{ data.name }}</span></el-tooltip><span v-else class="regular-text">{{ data.name }}</span></template></el-cascader-panel><template #footer><div class="footer"><el-button @click="handleClose" plain>取消</el-button><el-button type="primary" @click="handleSumit">确认添加</el-button></div></template></Dialog></div>
</template>
<script lang="ts" setup>
import { ref, reactive, defineProps, computed, watch, nextTick, onMounted, onUnmounted } from 'vue'
import { ApiBusiType } from '@/api/index'
import { ElMessage } from 'element-plus'
import dayjs from 'dayjs'
import { convertLegacyProps } from 'ant-design-vue/es/button/buttonTypes'
import { deepCopy } from '@/utils/helper'
const props = defineProps({visible: {type: Boolean,default: false},data: {type: Object || Array,default: () => {return {}}}
})
const ruleForm = reactive({collectSite: '',category: '',productType: '',productTypeKeyword: ''
})
const cascaderCollect = ref()
const collectOptions = ref([])
const currentOptions = ref([])
const otherOptions = ref([])
const searchData = ref('')
const selectData = ref([])
// 我是选中的值
const checkData = ref([])
const currentPathNode = ref('')
const currentPathNode2 = ref('')
const currentPathNode1 = ref('')
const searchDataOptions = ref([])
const secondNode = ref('')
const fourCollectOptions = ref([])
const loading = ref(false)
const secondParams = reactive({})
const productTypeOption = ref([])
const keywordOption = ref([])
const collectValue = ref([])
const optionFirst = ref([])
const optionSecond = ref([])
const optionThird = ref([])
const optionFourth = ref([])
const optionAll = ref([])
const oneOptions = ref([])
const twoOptions = ref([])
const time = ref()
const time2 = ref()
const $emit = defineEmits(['update:visible', 'close'])
let address = {value: 'name',label: 'name',children: 'children',multiple: true,leaf: 'leaf',lazy: true, // 开启懒加载// checkStrictly: true, //可选择任意节点/*** 异步懒加载节点数据的函数* @param {Object} node - 当前被点击的节点对象* @param {Function} resolve - 数据加载完成后的回调函数,必须调用* 该函数根据当前节点的信息构造查询条件,调用接口获取下一级节点数据。* 当节点层级达到 4 级时,不再请求接口。获取到的数据经过处理后通过 resolve 返回。*/async lazyLoad(node, resolve) {console.log('node', node)const { level } = node// level 节点层级console.log('level', level)const nodes = []const params = {managerCombination: node.pathLabels?.join(',') || '',code: node.data.code || '',name: node.data.name || '',note: node.data.note || '',parentCode: node.data.parentCode || ''}const res = await ApiBusiType.marketDataCollection.queryGraduallyCollectionConfig(params)currentOptions.value = res.result || []switch (level) {case 0:optionFirst.value = res.result || []breakcase 1:optionSecond.value = res.result || []twoOptions.value.push(res.result)breakcase 2:optionThird.value = res.result || []breakcase 3:optionFourth.value = res.result || []breakdefault:break}if (level === 0) {collectOptions.value = res.result || []resolve(collectOptions.value)} else {res.result.map((item) => {let obj = {code: item?.code,name: item?.name,note: item?.note,disabled: item.disabled,parentCode: item?.parentCode,leaf: node?.level >= 3}nodes.push(obj)})resolve(nodes)}}
}
const isShow = computed({get() {return props.visible},set(val: boolean) {$emit('update:visible', val)}
})
//触发点击事件,index 节点位置,number 级联面板四级中的一级
const toClickSecondCascaderCollect = (index, number?) => {const el = document.querySelectorAll(`.el-cascader-menu`)[number].querySelectorAll(`.el-cascader-node`)if (el && el[index]) {return new Promise((resolve) => {el[index].click()   // 触发点击事件,展开传过来的index对应的节点el[index].scrollIntoView({ behavior: 'smooth', block: 'start' })time.value = setTimeout(() => {resolve()     // 延迟1秒执行,防止执行过快,防止上一级没有展示出来就点击而导致找不到click报错}, 1000)})}return Promise.resolve()
}
const isTextTruncated = (text) => {// 你可以实现逻辑检查文本是否超过某个长度const maxLength = 28 // 可根据需要调整最大长度return text.length > maxLength
}const handleSumit = async () => {console.log('collectValue', collectValue.value)if (collectValue.value.length === 0) {ElMessage.warning('无可添加采集节点,请重新选择')return}const params = {categoryList: collectValue.value.map((item) => item?.join(',')) || []}console.log('params', params)const res = await ApiBusiType.marketDataRelationship.marketCollection(params)if (res.code === '1') {ElMessage.success('操作成功!')$emit('close', 'refresh')}
}
// 转换数据结构的函数
const transformToArray = (data) => {return data.map((item) => {const keyName = Object.keys(item)[0] // 获取每个对象的第一个属性名return {value: keyName,label: keyName // 将 value 和 label 都设置为同一个属性名}})
}
const searchChange = async (changeData) => {// 点击后获取的数据分3段数据// 第一段数据返回后触发 toClickSecondCascaderCollect 第一段数据在2里面的位置 2// 第二段数据返回后触发 toClickSecondCascaderCollect 第二段数据在3里面的位置 3// 第三段数据返回后触发 toClickSecondCascaderCollect 第三段数据在4里面的位置 4if (!changeData) returnconst currdata = changeData?.split(',')console.log('currdata', currdata)for (let i = 0; i < 3; i++) {let index = -1if (i === 0) {index = optionSecond.value.findIndex((item) => item.name === currdata[0])} else if (i === 1) {let secondParams = optionSecond.value.find((item) => item.name === currdata[0])console.log('secondParams', secondParams)const res = await ApiBusiType.marketDataCollection.queryGraduallyCollectionConfig(secondParams)optionThird.value = res.result || []console.log('res1111', res)index = optionThird.value.findIndex((item) => item.name === currdata[1])}else if(i === 2){index = optionFourth.value.findIndex((item) => item.name === currdata[2])}if (index !== -1) {await nextTick() // 等待数据渲染完成await toClickSecondCascaderCollect(index, i + 1)}}
}
const searchAddData = async () => {// loading.value = trueconst params = {name: currentPathNode.value,search: searchData.value}const res = await ApiBusiType.marketDataRelationship.queryLikeConfig(params)if (res.code === '1') {const result = transformToArray(res.result)searchDataOptions.value = result || []}
}
// 获取第二级当前点击的节点
// 遍历二级的数据拿到这一集的参数,去调用第三级
const handleExpandChange = (val) => {console.log('展开节点触发了', val)if (val.length === 1) {currentPathNode.value = val[0]}if (val.length > 1) secondNode.value = val[1]
}
const handleClose = () => {isShow.value = falsecollectValue.value = []$emit('close')
}
watch(() => currentPathNode.value,(val) => {if (val) {let isupdate=oneOptions.value.includes(val)if (oneOptions.value.length > 1 && isupdate) {console.log('oneOptions.value312', oneOptions.value)console.log('twoOptions.value213', twoOptions.value)let index = oneOptions.value.findIndex((item) => item === val)optionSecond.value = twoOptions.value[index]}isupdate ? '' : oneOptions.value.push(val)searchData.value = ''searchAddData()}}
)
watch(() => props.visible,(val) => {searchData.value = ''       // 清空搜索框if (val) {time2.value = setTimeout(() => {const index = collectOptions.value.findIndex((item) => item.name === 'US')  // 默认选中US,通过US去当下一级的option去获取对应的的indextoClickSecondCascaderCollect(index, 0)  //将index传给toClickSecondCascaderCollect,0代表级联第一级数据,1代表第二级数据,2代表第三级数据}, 1000)}}
)
onUnmounted(() => {time.value && clearTimeout(time.value)time2.value && clearTimeout(time2.value)
})
</script>
<style scoped lang="less">
.selection-container {display: flex;
}.selection-column {flex: 1;margin-left: 10px;
}.footer {float: right;
}
::v-deep(.el-cascader-menu:nth-child(1) .el-checkbox),
::v-deep(.el-cascader-menu:nth-child(2) .el-checkbox) {display: none;
}
::v-deep(.el-cascader-menu:nth-child(1)) {min-width: 135px;
}.truncated-text {display: inline-block;max-width: 213px; /* 设置你希望的宽度 */white-space: nowrap;overflow: hidden;text-overflow: ellipsis;vertical-align: middle;
}.regular-text {white-space: normal; /* 显示完整文本,没有省略 */
}
</style>

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com