| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- <template>
- <view class="knowledge-tree">
- <knowledge-tree-node v-for="item in initializedData" :key="item.id" :node-data="item"
- @node-click="handleNodeClick" @start-practice="handleStartPractice">
- <template #default>
- <slot></slot>
- </template>
- </knowledge-tree-node>
- </view>
- </template>
- <script lang="ts" setup>
- import * as Study from '@/types/study';
- import KnowledgeTreeNode from './knowledge-tree-node.vue';
- // 定义 emits
- const emit = defineEmits(['nodeClick', 'startPractice']);
- // 定义 props
- const props = defineProps({
- treeData: {
- type: Array as PropType<Study.KnowledgeNode[]>,
- default: () => []
- },
- });
- // 初始化后的数据
- const initializedData = ref<Study.KnowledgeNode[]>([]);
- // 确保单个项目的必要属性存在
- const ensureItemProperties = (item: Study.KnowledgeNode) => {
- if (item.isExpanded === undefined) {
- item.isExpanded = false;
- }
- if (item.isLeaf === undefined) {
- item.isLeaf = !item.children || item.children.length === 0;
- }
- // 递归处理子项
- item.children?.forEach(child => ensureItemProperties(child));
- }
- // 初始化数据
- const initializeData = (sourceData: Study.KnowledgeNode[]): Study.KnowledgeNode[] => {
- return sourceData.map((item, index) => {
- const oldItem = initializedData.value[index];
- const children = initializeData(item.children || []);
- return {
- ...item,
- isExpanded: item.id === oldItem?.id ? oldItem?.isExpanded ?? false : false,
- isLeaf: !item.children || item.children.length === 0,
- children
- };
- });
- }
- // 处理节点点击事件
- const handleNodeClick = (eventData: { node: Study.KnowledgeNode; parent: Study.KnowledgeNode | null }) => {
- // 向上传递点击事件
- emit('nodeClick', eventData);
- };
- // 处理开始练习事件
- const handleStartPractice = (node: Study.KnowledgeNode) => {
- emit('startPractice', node);
- };
- // 监听 props.treeData 变化,重新初始化数据
- watch(() => props.treeData, (newTreeData) => {
- initializedData.value = initializeData(newTreeData);
- }, {
- immediate: true,
- deep: true
- });
- </script>
- <style lang="scss" scoped></style>
|