Files
WAI_Project_UNIX/uni_modules/cool-ui/components/cl-tree-item/cl-tree-item.uvue

220 lines
5.1 KiB
Plaintext
Raw Normal View History

2025-09-01 01:23:29 +08:00
<template>
<view class="cl-tree-item-wrapper" :class="[pt.itemWrapper?.className]">
2025-09-01 01:23:29 +08:00
<view
class="cl-tree-item"
:class="[
{
'is-expand': hover,
'is-dark': isDark,
2025-09-03 19:03:39 +08:00
'is-checked':
item.isChecked == true &&
ClTree?.checkable == true &&
ClTree?.multiple == false,
'is-half-checked': item.isHalfChecked,
'is-disabled': item.disabled,
'is-multiple': ClTree?.multiple
2025-09-01 01:23:29 +08:00
},
pt.item?.className,
item.isChecked == true ? pt.itemChecked?.className : ''
2025-09-01 01:23:29 +08:00
]"
:style="{
paddingLeft: `${level * 50 + 16}rpx`
}"
2025-09-01 01:23:29 +08:00
@touchstart="onTouchStart"
@touchend="onTouchEnd"
@touchcancel="onTouchEnd"
>
<view class="cl-tree-item__expand" :class="[pt.expand?.className]">
<cl-icon
:name="icon"
:size="pt.expandIcon?.size ?? 34"
2025-09-01 01:23:29 +08:00
:color="pt.expandIcon?.color"
:pt="{
className: pt.expandIcon?.className
}"
v-if="hasChildren"
></cl-icon>
</view>
<cl-text
:pt="{
className: parseClass(['flex-1 mx-1', pt.label?.className])
}"
>{{ item.label }}</cl-text
>
<template v-if="showCheckbox">
2025-09-01 01:23:29 +08:00
<view
class="cl-tree-item__checkbox"
:class="[pt.checkbox?.className]"
@touchstart.stop="toChecked"
>
<cl-icon
v-if="item.isChecked"
:name="pt.checkedIcon?.name ?? 'checkbox-circle-fill'"
:size="pt.checkedIcon?.size ?? 38"
:color="pt.checkedIcon?.color ?? 'primary'"
></cl-icon>
<cl-icon
v-else-if="item.isHalfChecked"
:name="pt.halfCheckedIcon?.name ?? 'indeterminate-circle-line'"
:size="pt.halfCheckedIcon?.size ?? 38"
:color="pt.halfCheckedIcon?.color ?? 'primary'"
></cl-icon>
<cl-icon
v-else
:name="pt.uncheckedIcon?.name ?? 'checkbox-blank-circle-line'"
:size="pt.uncheckedIcon?.size ?? 38"
:color="pt.uncheckedIcon?.color ?? 'info'"
></cl-icon>
</view>
</template>
</view>
<template v-if="hasChildren && item.isExpand == true">
<cl-tree-item
v-for="item in item.children"
:key="item.id"
:item="item"
:level="level + 1"
:pt="props.pt"
></cl-tree-item>
</template>
</view>
</template>
<script lang="ts" setup>
import { computed, ref, type PropType } from "vue";
import { isDark, parseClass, parsePt, useParent } from "@/cool";
import type { ClTreeItem, PassThroughProps } from "../../types";
import type { ClIconProps } from "../cl-icon/props";
defineOptions({
name: "cl-tree-item"
});
const props = defineProps({
pt: {
type: Object,
default: () => ({})
},
item: {
type: Object as PropType<ClTreeItem>,
default: () => ({})
},
level: {
type: Number,
default: 0
}
});
// 透传属性类型定义,支持自定义各部分样式和图标
type PassThrough = {
item?: PassThroughProps; // 自定义类名
itemChecked?: PassThroughProps; // 选中状态属性
itemWrapper?: PassThroughProps; // 外层包裹属性
2025-09-01 01:23:29 +08:00
expand?: PassThroughProps; // 展开区域属性
expandIcon?: ClIconProps; // 展开图标属性
checkbox?: PassThroughProps; // 复选框区域属性
checkedIcon?: ClIconProps; // 选中图标属性
halfCheckedIcon?: ClIconProps; // 半选图标属性
uncheckedIcon?: ClIconProps; // 未选中图标属性
label?: PassThroughProps; // 标签属性
};
// 解析pt透传属性便于自定义样式和图标
const pt = computed(() => parsePt<PassThrough>(props.pt));
// 获取父级cl-tree组件实例用于调用树的相关方法
const ClTree = useParent<ClTreeComponentPublicInstance>("cl-tree");
// 判断当前节点是否有子节点
const hasChildren = computed(() => props.item.children != null && props.item.children.length > 0);
// 判断当前节点是否显示复选框
const showCheckbox = computed(() => {
2025-09-02 15:41:02 +08:00
if (ClTree == null) {
return false;
}
return ClTree.checkable == true && ClTree.multiple == true;
});
2025-09-01 01:23:29 +08:00
// 计算当前节点应显示的图标(展开/收起)
const icon = computed(() => {
if (ClTree == null) {
return "";
}
return props.item.isExpand == true ? ClTree.expandIcon : ClTree.icon;
});
// 切换当前节点的展开状态
function toExpand() {
ClTree!.setExpanded(props.item.id, !(props.item.isExpand ?? false));
}
// 切换当前节点的选中状态
function toChecked() {
if (props.item.disabled == true) {
return;
}
2025-09-01 01:23:29 +08:00
ClTree!.setChecked(props.item.id, !(props.item.isChecked ?? false));
}
// 控制节点按下时的hover状态
const hover = ref(false);
// 触摸开始时触发设置hover并展开/收起
function onTouchStart() {
hover.value = true;
toExpand();
2025-09-02 15:41:02 +08:00
if (ClTree != null) {
if (ClTree.checkable == true && ClTree.multiple != true && props.item.disabled != true) {
toChecked();
}
}
2025-09-01 01:23:29 +08:00
}
// 触摸结束时触发取消hover
function onTouchEnd() {
hover.value = false;
}
</script>
<style lang="scss" scoped>
.cl-tree-item {
@apply flex flex-row items-center w-full rounded-lg;
padding: 16rpx;
2025-09-01 01:23:29 +08:00
&__expand {
@apply w-6 flex items-center justify-center;
}
&.is-expand {
@apply bg-surface-50;
&.is-dark {
@apply bg-surface-700;
}
}
&.is-disabled {
@apply opacity-50;
}
&.is-checked {
@apply bg-primary-100;
&.is-multiple {
@apply bg-transparent;
}
&.is-dark {
@apply bg-primary-500;
}
2025-09-01 01:23:29 +08:00
}
}
</style>