| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- <template>
- <view
- class="uni-tree-view-container"
- :style="{ '--theme-color': props.themeColor }">
- <scroll-view
- class="scroll-view-container"
- :scroll-y="true"
- :scroll-top="virtualEnabled ? virtualScrollCommandTop : undefined"
- :scroll-into-view="scrollIntoView"
- :style="scrollViewStyle"
- @scroll="handleVirtualScroll">
- <view v-if="visibleTreeList.length === 0" class="utv-tree-empty">
- <template v-if="hasFilterValue">
- <slot name="empty-filter" :filter-value="props.filterValue">
- <slot name="empty" :filter-value="props.filterValue">
- {{ props.emptyText }}
- </slot>
- </slot>
- </template>
- <slot v-else name="empty" :filter-value="props.filterValue">
- {{ props.emptyText }}
- </slot>
- </view>
- <view
- v-if="virtualEnabled && virtualTopPadding > 0"
- class="utv-tree-virtual-spacer"
- :style="{ height: `${virtualTopPadding}px` }"></view>
- <view
- v-for="item in renderedTreeList"
- :id="item.domId"
- :key="item.node.id"
- :style="{
- paddingLeft: `${item.node.level * props.indent}rpx`,
- height: virtualEnabled ? `${props.virtualItemHeight}px` : undefined,
- minHeight: virtualEnabled ? `${props.virtualItemHeight}px` : undefined
- }"
- class="utv-tree-item"
- :class="[
- props.nodeClass,
- {
- 'is-leaf': item.node.isLeaf,
- 'is-expanded': item.node.expanded,
- 'is-disabled': item.node.disabled,
- 'is-checked': props.selectable && item.node.checked === 'checked',
- 'is-virtual': virtualEnabled
- }
- ]"
- :hover-class="item.node.disabled ? 'none' : 'utv-tree-item--hover'"
- :hover-stay-time="80"
- @click="handleNodeClick(item.node)">
- <view class="utv-tree-item__state-layer"></view>
- <view
- v-if="isExpandable(item.node)"
- class="utv-tree-item__arrow-icon is-right"
- :class="{
- 'is-expand': item.node.expanded,
- 'is-loading': item.node.loading,
- 'is-load-error': Boolean(item.node.loadError)
- }"
- @click.stop="handleToggleExpand(item.node)"></view>
- <view v-else class="utv-tree-item__arrow-placeholder"></view>
- <view
- v-if="showSelectionControl && props.selectionPlacement === 'left'"
- class="utv-tree-item__checkbox"
- :class="{ 'is-disabled': item.node.disabled }"
- @click.stop="handleCheckChange(item.node)">
- <view
- class="utv-tree-item__checkbox-icon"
- :class="getSelectionIconClass(item.node)"></view>
- </view>
- <view class="utv-tree-node-content">
- <template v-if="slots.default">
- <slot
- name="default"
- :node="item.node"
- :data="item.node.source"
- :path="item.path"></slot>
- </template>
- <template v-else>
- <view v-if="item.node.icon || slots.icon" class="utv-tree-node-icon">
- <template v-if="slots.icon">
- <slot
- name="icon"
- :node="item.node"
- :data="item.node.source"
- :path="item.path"></slot>
- </template>
- <template v-else>{{ item.node.icon }}</template>
- </view>
- <view class="utv-tree-node-main">
- <view :class="['utv-tree-node-label',{'parent':item.node?.source?.children?.length > 0}]">
- <template v-if="slots.label">
- <slot
- name="label"
- :node="item.node"
- :data="item.node.source"
- :path="item.path"></slot>
- </template>
- <template v-else>
- <text
- v-for="(segment, segmentIndex) in getLabelSegments(item.node.label)"
- :key="segmentIndex"
- :class="{ 'utv-tree-node-label__match': segment.matched }">
- {{ segment.text }}
- </text>
- </template>
- </view>
- <view v-if="props.showPath && item.node.path.length > 1" class="utv-tree-node-path">
- {{ item.node.path.join(props.pathSeparator) }}
- </view>
- </view>
- <view v-if="item.node.append || slots.append" class="utv-tree-node-append">
- <template v-if="slots.append">
- <slot
- name="append"
- :node="item.node"
- :data="item.node.source"
- :path="item.path"></slot>
- </template>
- <template v-else>{{ item.node.append }}</template>
- </view>
- </template>
- </view>
- <view
- v-if="showSelectionControl && props.selectionPlacement === 'right'"
- class="utv-tree-item__checkbox"
- :class="{ 'is-disabled': item.node.disabled }"
- @click.stop="handleCheckChange(item.node)">
- <view
- class="utv-tree-item__checkbox-icon"
- :class="getSelectionIconClass(item.node)"></view>
- </view>
- </view>
- <view
- v-if="virtualEnabled && virtualBottomPadding > 0"
- class="utv-tree-virtual-spacer"
- :style="{ height: `${virtualBottomPadding}px` }"></view>
- </scroll-view>
- </view>
- </template>
- <script lang="ts" setup>
- import { computed, nextTick, shallowRef, watch } from "vue";
- import type {
- TreeCheckChangePayload,
- TreeKey,
- TreeNode,
- TreeScrollToOptions,
- UniTreeViewEmits,
- UniTreeViewExposed,
- UniTreeViewProps,
- UniTreeViewSlots
- } from "./types";
- import { useTreeViewState } from "./useTreeViewState";
- import { useVirtualTreeList } from "./useVirtualTreeList";
- defineOptions({
- name: "UniTreeView",
- options: {
- // #ifdef MP-WEIXIN || MP-ALIPAY
- virtualHost: true
- // #endif
- }
- });
- const props = withDefaults(defineProps<UniTreeViewProps>(), {
- modelValue: undefined,
- data: () => [],
- treeProps: undefined,
- filterValue: "",
- filterMethod: undefined,
- highlightFilter: true,
- themeColor: "#007aff",
- selectable: false,
- showRadioIcon: true,
- multiple: false,
- checkOnClickNode: false,
- checkOnClickLeaf: false,
- expandOnClickNode: false,
- accordion: false,
- checkStrictly: false,
- onlyRadioLeaf: false,
- defaultExpandAll: false,
- defaultExpandedKeys: () => [],
- defaultExpandParent: true,
- expandChecked: false,
- cacheExpandedKeys: false,
- defaultCheckedKeys: () => [],
- loadMode: false,
- loadApi: undefined,
- isLeafFn: undefined,
- alwaysFirstLoad: false,
- checkedDisabled: false,
- packDisabledKey: undefined,
- packDisabledkey: undefined,
- nodeClass: "",
- indent: 40,
- selectionPlacement: "left",
- emptyText: "暂无数据",
- showPath: false,
- pathSeparator: " / ",
- virtual: false,
- virtualItemHeight: 36,
- virtualHeight: 400,
- virtualOverscan: 8
- });
- const emit = defineEmits<UniTreeViewEmits>();
- const slots = defineSlots<UniTreeViewSlots>();
- const scrollIntoView = shallowRef("");
- const virtualScrollCommandTop = shallowRef<number>();
- const nodeDomIds = new Map<TreeKey, string>();
- let nextNodeDomId = 0;
- const {
- isMultiple,
- treeVersion,
- reconciledModelValue,
- pendingCheckChangePayload,
- visibleTreeList,
- toggleExpand,
- checkNode,
- isExpandable,
- getSelectionIconClass,
- loadNode: loadStateNode,
- setCheckedKeys: setStateCheckedKeys,
- getCheckedKeys,
- getHalfCheckedKeys,
- getUncheckedKeys,
- getCheckedNodes,
- getHalfCheckedNodes,
- getUncheckedNodes,
- setExpandedKeys,
- getExpandedKeys,
- getUnexpandedKeys,
- getVisibleKeys,
- getMatchedKeys,
- getExpandedNodes,
- getUnexpandedNodes,
- getVisibleNodes,
- getMatchedNodes,
- getNode,
- getNodePath,
- expandAll,
- collapseAll
- } = useTreeViewState(props);
- const showSelectionControl = computed(() => {
- return Boolean(props.selectable && (isMultiple.value || props.showRadioIcon));
- });
- const hasFilterValue = computed(() => String(props.filterValue ?? "").trim().length > 0);
- const {
- virtualEnabled,
- renderedItems: virtualRenderedTreeList,
- scrollTop: virtualScrollTop,
- topPadding: virtualTopPadding,
- bottomPadding: virtualBottomPadding,
- scrollViewStyle,
- handleScroll: handleVirtualScroll,
- scrollToIndex
- } = useVirtualTreeList({
- items: visibleTreeList,
- virtual: () => props.virtual,
- itemHeight: () => props.virtualItemHeight,
- height: () => props.virtualHeight,
- overscan: () => props.virtualOverscan
- });
- interface RenderedTreeItem {
- node: TreeNode;
- path: TreeNode[];
- domId: string;
- }
- const needsRenderedNodePath = computed(() => {
- return Boolean(slots.default || slots.icon || slots.label || slots.append);
- });
- const renderedTreeList = computed(() => {
- const includePath = needsRenderedNodePath.value;
- return virtualRenderedTreeList.value.map((node): RenderedTreeItem => ({
- node,
- path: includePath ? getNodePath(node) : [],
- domId: getNodeDomId(node)
- }));
- });
- async function handleToggleExpand(node: TreeNode) {
- if (node.loadError && !node.loading) {
- await retryLoadSafely(node);
- return;
- }
- const shouldLoad = !node.loaded;
- const payload = toggleExpand(node);
- if (!payload) {
- return;
- }
- emit("expand-change", payload);
- if (payload.expanded && shouldLoad) {
- await loadNodeSafely(node);
- }
- }
- function handleNodeClick(node: TreeNode) {
- emit("node-click", {
- id: node.id,
- node,
- path: getNodePath(node)
- });
- if (props.expandOnClickNode && isExpandable(node)) {
- void handleToggleExpand(node);
- }
- if (props.selectable && (props.checkOnClickNode || (props.checkOnClickLeaf && node.isLeaf))) {
- handleCheckChange(node);
- }
- }
- async function loadNode(node: TreeNode) {
- const wasLoaded = node.loaded;
- try {
- const children = await loadStateNode(node);
- if (!wasLoaded && node.loaded) {
- emit("load", { node, children });
- }
- return children;
- } catch (error) {
- emit("load-error", { node, error });
- throw error;
- }
- }
- async function loadNodeSafely(node: TreeNode) {
- try {
- await loadNode(node);
- } catch {
- // The load-error event carries the failure and the node remains retryable.
- }
- }
- async function retryLoad(keyOrNode: TreeKey | TreeNode) {
- const node = typeof keyOrNode === "object" ? keyOrNode : getNode(keyOrNode);
- if (!node) {
- return [];
- }
- return loadNode(node);
- }
- async function retryLoadSafely(node: TreeNode) {
- try {
- await retryLoad(node);
- } catch {
- // The load-error event carries the failure and another retry remains possible.
- }
- }
- async function scrollToKey(key: TreeKey, options: TreeScrollToOptions = {}) {
- const node = getNode(key);
- if (!node) {
- return false;
- }
- if (options.expandParents !== false && node.parentIds.length > 0) {
- setExpandedKeys(node.parentIds, true);
- }
- await nextTick();
- const visibleIndex = visibleTreeList.value.findIndex((item) => item.id === key);
- if (visibleIndex === -1) {
- return false;
- }
- if (virtualEnabled.value) {
- virtualScrollCommandTop.value = undefined;
- await nextTick();
- if (!scrollToIndex(visibleIndex)) {
- return false;
- }
- virtualScrollCommandTop.value = virtualScrollTop.value;
- return true;
- }
- scrollIntoView.value = "";
- await nextTick();
- scrollIntoView.value = getNodeDomId(node);
- return true;
- }
- function getNodeDomId(node: TreeNode) {
- const cachedDomId = nodeDomIds.get(node.id);
- if (cachedDomId) {
- return cachedDomId;
- }
- nextNodeDomId += 1;
- const domId = `utv-tree-node-${nextNodeDomId}`;
- nodeDomIds.set(node.id, domId);
- return domId;
- }
- function getLabelSegments(label: string) {
- const filterValue = String(props.filterValue ?? "").trim();
- if (!props.highlightFilter || !filterValue) {
- return [{ text: label, matched: false }];
- }
- const normalizedLabel = label.toLowerCase();
- const normalizedFilter = filterValue.toLowerCase();
- const segments: Array<{ text: string; matched: boolean }> = [];
- let startIndex = 0;
- let matchIndex = normalizedLabel.indexOf(normalizedFilter);
- while (matchIndex !== -1) {
- if (matchIndex > startIndex) {
- segments.push({ text: label.slice(startIndex, matchIndex), matched: false });
- }
- const endIndex = matchIndex + filterValue.length;
- segments.push({ text: label.slice(matchIndex, endIndex), matched: true });
- startIndex = endIndex;
- matchIndex = normalizedLabel.indexOf(normalizedFilter, startIndex);
- }
- if (startIndex < label.length) {
- segments.push({ text: label.slice(startIndex), matched: false });
- }
- return segments.length > 0 ? segments : [{ text: label, matched: false }];
- }
- function emitFilterChange() {
- emit("filter-change", {
- value: props.filterValue,
- keys: getVisibleKeys(),
- nodes: getVisibleNodes(),
- matchedKeys: getMatchedKeys(),
- matchedNodes: getMatchedNodes()
- });
- }
- // 过滤条件或状态树变化时对账:只要本次或上一次处于过滤中就同步结果,避免未过滤时的数据更新触发噪音事件。
- let previouslyHadFilterValue = false;
- watch(
- () => [props.filterValue, props.filterMethod, treeVersion.value] as const,
- () => {
- const currentlyHasFilterValue = hasFilterValue.value;
- const shouldEmit = currentlyHasFilterValue || previouslyHadFilterValue;
- previouslyHadFilterValue = currentlyHasFilterValue;
- if (!shouldEmit) {
- return;
- }
- emitFilterChange();
- },
- { flush: "post", immediate: true }
- );
- // 状态树重建或懒加载追加后回收已移除节点的 DOM id,保持 scrollToKey 的查询目标与渲染一致。
- watch(
- treeVersion,
- () => {
- for (const key of nodeDomIds.keys()) {
- if (!getNode(key)) {
- nodeDomIds.delete(key);
- }
- }
- },
- { flush: "sync" }
- );
- watch(
- reconciledModelValue,
- (payload) => {
- if (payload) {
- emit("update:modelValue", payload.value);
- }
- },
- { flush: "post" }
- );
- watch(
- pendingCheckChangePayload,
- (payload) => {
- if (payload) {
- commitSelectionChange(payload);
- }
- },
- { flush: "post" }
- );
- function handleCheckChange(node: TreeNode) {
- const payload = checkNode(node);
- if (!payload) {
- return;
- }
- commitSelectionChange(payload);
- }
- function commitSelectionChange(payload: TreeCheckChangePayload) {
- emit("update:modelValue", payload.value);
- emit("check-change", payload);
- }
- function setCheckedKeys(keys: TreeKey | TreeKey[], checked = true) {
- const payload = setStateCheckedKeys(keys, checked);
- if (payload) {
- commitSelectionChange(payload);
- return payload.value;
- }
- const checkedKeys = getCheckedKeys();
- return isMultiple.value ? checkedKeys : (checkedKeys[0] ?? null);
- }
- const exposed = {
- setCheckedKeys,
- getCheckedKeys,
- getHalfCheckedKeys,
- getUncheckedKeys,
- getCheckedNodes,
- getHalfCheckedNodes,
- getUncheckedNodes,
- setExpandedKeys,
- getExpandedKeys,
- getUnexpandedKeys,
- getVisibleKeys,
- getMatchedKeys,
- getExpandedNodes,
- getUnexpandedNodes,
- getVisibleNodes,
- getMatchedNodes,
- getNode,
- getNodePath,
- expandAll,
- collapseAll,
- loadNode,
- retryLoad,
- scrollToKey
- } satisfies UniTreeViewExposed;
- defineExpose(exposed);
- </script>
- <style lang="scss">
- @font-face {
- font-family: "uni-tree-iconfont";
- src: url('data:application/octet-stream;base64,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') format('truetype');
- }
- </style>
- <style lang="scss" scoped>
- @use "../../style/index.scss";
- .uni-tree-view-container {
- width: 100%;
- height: 100%;
- }
- </style>
|