This commit is contained in:
dap
2025-03-31 15:20:14 +08:00
21 changed files with 298 additions and 45 deletions

View File

@@ -68,10 +68,12 @@ exports[`defaultPreferences immutability test > should not modify the config obj
"sidebar": {
"autoActivateChild": false,
"collapsed": false,
"collapsedButton": true,
"collapsedShowTitle": false,
"enable": true,
"expandOnHover": true,
"extraCollapse": false,
"fixedButton": true,
"hidden": false,
"width": 224,
},

View File

@@ -68,10 +68,12 @@ const defaultPreferences: Preferences = {
sidebar: {
autoActivateChild: false,
collapsed: false,
collapsedButton: true,
collapsedShowTitle: false,
enable: true,
expandOnHover: true,
extraCollapse: false,
fixedButton: true,
hidden: false,
width: 224,
},

View File

@@ -132,6 +132,8 @@ interface SidebarPreferences {
autoActivateChild: boolean;
/** 侧边栏是否折叠 */
collapsed: boolean;
/** 侧边栏折叠按钮是否可见 */
collapsedButton: boolean;
/** 侧边栏折叠时是否显示title */
collapsedShowTitle: boolean;
/** 侧边栏是否可见 */
@@ -140,6 +142,8 @@ interface SidebarPreferences {
expandOnHover: boolean;
/** 侧边栏扩展区域是否折叠 */
extraCollapse: boolean;
/** 侧边栏固定按钮是否可见 */
fixedButton: boolean;
/** 侧边栏是否隐藏 - css */
hidden: boolean;
/** 侧边栏宽度 */

View File

@@ -1,10 +1,12 @@
<script setup lang="ts">
import type { CSSProperties } from 'vue';
import { VbenScrollbar } from '@vben-core/shadcn-ui';
import { useScrollLock } from '@vueuse/core';
import { computed, shallowRef, useSlots, watchEffect } from 'vue';
import { VbenScrollbar } from '@vben-core/shadcn-ui';
import { useScrollLock } from '@vueuse/core';
import { SidebarCollapseButton, SidebarFixedButton } from './widgets';
interface Props {
@@ -63,9 +65,14 @@ interface Props {
show?: boolean;
/**
* 显示折叠按钮
* @default false
* @default true
*/
showCollapseButton?: boolean;
/**
* 显示固定按钮
* @default true
*/
showFixedButton?: boolean;
/**
* 主题
*/
@@ -93,6 +100,7 @@ const props = withDefaults(defineProps<Props>(), {
paddingTop: 0,
show: true,
showCollapseButton: true,
showFixedButton: true,
zIndex: 0,
});
@@ -265,7 +273,7 @@ function handleMouseleave() {
@mouseleave="handleMouseleave"
>
<SidebarFixedButton
v-if="!collapse && !isSidebarMixed"
v-if="!collapse && !isSidebarMixed && showFixedButton"
v-model:expand-on-hover="expandOnHover"
/>
<div v-if="slots.logo" :style="headerStyle">

View File

@@ -106,6 +106,11 @@ interface VbenLayoutProps {
* @default false
*/
sidebarCollapse?: boolean;
/**
* 侧边菜单折叠按钮
* @default true
*/
sidebarCollapsedButton?: boolean;
/**
* 侧边菜单是否折叠时是否显示title
* @default true
@@ -121,6 +126,11 @@ interface VbenLayoutProps {
* @default 48
*/
sidebarExtraCollapsedWidth?: number;
/**
* 侧边菜单折叠按钮是否固定
* @default true
*/
sidebarFixedButton?: boolean;
/**
* 侧边栏是否隐藏
* @default false

View File

@@ -49,8 +49,10 @@ const props = withDefaults(defineProps<Props>(), {
headerVisible: true,
isMobile: false,
layout: 'sidebar-nav',
sidebarCollapsedButton: true,
sidebarCollapseShowTitle: false,
sidebarExtraCollapsedWidth: 60,
sidebarFixedButton: true,
sidebarHidden: false,
sidebarMixedWidth: 80,
sidebarTheme: 'dark',
@@ -487,6 +489,8 @@ const idMainContent = ELEMENT_ID_MAIN_CONTENT;
v-model:expand-on-hovering="sidebarExpandOnHovering"
v-model:extra-collapse="sidebarExtraCollapse"
v-model:extra-visible="sidebarExtraVisible"
:show-collapse-button="sidebarCollapsedButton"
:show-fixed-button="sidebarFixedButton"
:collapse-width="getSideCollapseWidth"
:dom-visible="!isMobile"
:extra-width="sidebarExtraWidth"

View File

@@ -20,7 +20,7 @@ const props = withDefaults(defineProps<VbenButtonGroupProps>(), {
showIcon: true,
size: 'middle',
});
const emit = defineEmits(['btnClick']);
const btnDefaultProps = computed(() => {
return {
...objectOmit(props, ['options', 'btnClass', 'size', 'disabled']),
@@ -90,6 +90,7 @@ async function onBtnClick(value: ValueType) {
innerValue.value = [value];
modelValue.value = value;
}
emit('btnClick', value);
}
</script>
<template>

View File

@@ -11,7 +11,6 @@ import { onMounted, ref, watchEffect } from 'vue';
import { ChevronRight, IconifyIcon } from '@vben-core/icons';
import { cn, get } from '@vben-core/shared/utils';
import { useVModel } from '@vueuse/core';
import { TreeItem, TreeRoot } from 'radix-vue';
import { Checkbox } from '../checkbox';
@@ -27,7 +26,6 @@ const props = withDefaults(defineProps<TreeProps>(), {
expanded: () => [],
iconField: 'icon',
labelField: 'label',
modelValue: () => [],
multiple: false,
showIcon: true,
transition: true,
@@ -38,7 +36,6 @@ const props = withDefaults(defineProps<TreeProps>(), {
const emits = defineEmits<{
expand: [value: FlattenedItem<Recordable<any>>];
select: [value: FlattenedItem<Recordable<any>>];
'update:modelValue': [value: Arrayable<Recordable<any>>];
}>();
interface InnerFlattenItem<T = Recordable<any>, P = number | string> {
@@ -76,11 +73,7 @@ function flatten<T = Recordable<any>, P = number | string>(
}
const flattenData = ref<Array<InnerFlattenItem>>([]);
const modelValue = useVModel(props, 'modelValue', emits, {
deep: true,
defaultValue: props.defaultValue ?? [],
passive: (props.modelValue === undefined) as false,
});
const modelValue = defineModel<Arrayable<number | string>>();
const expanded = ref<Array<number | string>>(props.defaultExpandedKeys ?? []);
const treeValue = ref();
@@ -105,9 +98,13 @@ function getItemByValue(value: number | string) {
function updateTreeValue() {
const val = modelValue.value;
treeValue.value = Array.isArray(val)
? val.map((v) => getItemByValue(v))
: getItemByValue(val);
if (val === undefined) {
treeValue.value = undefined;
} else {
treeValue.value = Array.isArray(val)
? val.map((v) => getItemByValue(v))
: getItemByValue(val);
}
}
function updateModelValue(val: Arrayable<Recordable<any>>) {
@@ -173,13 +170,6 @@ function onSelect(item: FlattenedItem<Recordable<any>>, isSelected: boolean) {
modelValue.value.push(p);
}
});
} else {
if (Array.isArray(modelValue.value)) {
const index = modelValue.value.indexOf(get(item.value, props.valueField));
if (index !== -1) {
modelValue.value.splice(index, 1);
}
}
}
updateTreeValue();
emits('select', item);
@@ -240,7 +230,7 @@ defineExpose({
@select="
(event) => {
if (event.detail.originalEvent.type === 'click') {
// event.preventDefault();
event.preventDefault();
}
onSelect(item, event.detail.isSelected);
}

View File

@@ -27,8 +27,6 @@ export interface TreeProps {
iconField?: string;
/** label字段 */
labelField?: string;
/** 当前值 */
modelValue?: Arrayable<number | string>;
/** 是否多选 */
multiple?: boolean;
/** 显示由iconField指定的图标 */