原本计划通过递归实现,发现在小程序开发者工具中只能展示一级。末了接纳了另外一种思绪。把所有数据全部拍平根据是否有children自动缩进形成层级结果。该组件能实现勾选操作展开折叠的底子交互功能:
结果:
- <template>
- <view class="tree-container">
- <view
- v-for="(node, index) in flatTreeData"
- :key="node.label + index"
- :style="{ marginLeft: node.level * 20 + 'px' }"
- class="tree-node"
- >
- <!-- 当前节点 -->
- <view class="node-content">
- <!-- 展开/收起图标 -->
- <image
- v-if="node.children && node.children.length > 0"
- :src="node.expanded ? expandedIcon : collapsedIcon"
- class="expand-icon"
- @click.stop="toggleExpand(node)"
- />
- <!-- 节点名称 -->
- <text class="node-label" @click="toggleExpand(node)">{{ node.label }}</text>
- <!-- 自定义选择框 -->
- <image :src="node.checked ? checkedIcon : uncheckedIcon" class="checkbox-icon" @click="toggleCheck(node)" />
- </view>
- </view>
- </view>
- </template>
- <script setup lang="ts">
- import { ref, computed, watch } from 'vue'
- // 定义树节点接口
- interface TreeNode {
- label: string
- checked?: boolean
- expanded?: boolean
- children?: TreeNode[]
- level?: number // 添加层级信息
- }
- // 定义 props
- const props = defineProps<{
- treeList: TreeNode[]
- }>()
- // 图标路径
- const checkedIcon = '/static/checkbox_checked.png' // 选中状态图标
- const uncheckedIcon = '/static/checkbox_unchecked.png' // 未选中状态图标
- const expandedIcon = '/static/arr_up.png' // 展开状态图标
- const collapsedIcon = '/static/arr_down.png' // 收起状态图标
- // 记录所有勾选的节点
- const checkedNodes = ref<TreeNode[]>([])
- // 扁平化树形数据
- const flatTreeData = computed(() => {
- const flatten = (nodes: TreeNode[], level = 0): TreeNode[] => {
- let result: TreeNode[] = []
- nodes.forEach((node) => {
- // 添加层级信息
- node.level = level
- result.push(node)
- // 如果节点展开且有子节点,递归处理子节点
- if (node.expanded && node.children) {
- result = result.concat(flatten(node.children, level + 1))
- }
- })
- return result
- }
- let v = flatten(props.treeList)
- console.log('v---', v)
- return v
- })
- // 切换节点选中状态
- const toggleCheck = (node: TreeNode) => {
- // 切换当前节点的选中状态
- node.checked = !node.checked
- // 如果当前节点是父节点,则勾选所有子节点
- if (node.children && node.children.length > 0) {
- toggleChildren(node, node.checked)
- }
- // 更新 checkedNodes
- updateCheckedNodes(node)
- }
- // 递归切换子节点状态
- const toggleChildren = (node: TreeNode, checked: boolean) => {
- if (node.children) {
- node.children.forEach((child) => {
- child.checked = checked
- toggleChildren(child, checked) // 递归处理子节点
- })
- }
- }
- // 更新 checkedNodes
- const updateCheckedNodes = (node: TreeNode) => {
- if (node.checked) {
- checkedNodes.value.push(node)
- } else {
- checkedNodes.value = checkedNodes.value.filter((n) => n !== node)
- }
- console.log('当前勾选的节点:', checkedNodes.value)
- }
- // 切换节点展开状态
- const toggleExpand = (node: TreeNode) => {
- if (node.children && node.children.length > 0) {
- node.expanded = !node.expanded
- }
- }
- // 递归为所有节点添加 checked 和 expanded 属性
- const initTreeData = (nodes: TreeNode[]) => {
- nodes.forEach((node) => {
- node.checked = false // 默认不选中
- node.expanded = false // 默认不展开
- if (node.children) {
- initTreeData(node.children) // 递归处理子节点
- }
- })
- }
- // 监听 treeList 的变化,初始化数据
- watch(
- () => props.treeList,
- (newVal) => {
- if (newVal && newVal.length > 0) {
- initTreeData(newVal) // 初始化 checked 和 expanded 属性
- }
- },
- { immediate: true }
- )
- </script>
- <style scoped>
- .tree-container {
- padding: 20px;
- }
- .tree-node {
- margin-bottom: 8px;
- }
- .node-content {
- display: flex;
- align-items: center;
- }
- .checkbox-icon {
- width: 20px;
- height: 20px;
- margin-right: 8px;
- }
- .node-label {
- flex: 1;
- }
- .expand-icon {
- width: 16px;
- height: 16px;
- margin-left: 8px;
- }
- </style>
复制代码 在父组件中使用:
- <Tree :treeList="treeList" />
- const treeList = ref<TreeNode[]>([
- {
- label: 'Node 1',
- checked: false,
- expanded: false,
- children: [
- {
- label: 'Node 1.1',
- checked: false,
- expanded: false,
- children: [
- {
- label: 'Node 1.1.1',
- checked: false,
- expanded: false,
- children: [
- {
- label: 'Node 1.1.1.1',
- checked: false,
- expanded: false,
- children: [{ label: 'Node 1.1.1', checked: false }]
- }
- ]
- },
- { label: 'Node 1.1.2', checked: false }
- ]
- },
- { label: 'Node 1.2', checked: false }
- ]
- },
- {
- label: 'Node 2',
- checked: false,
- expanded: false,
- children: [
- { label: 'Node 2.1', checked: false },
- { label: 'Node 2.2', checked: false }
- ]
- }
- ])
复制代码 注意
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |