Skip to content

Commit

Permalink
feat(layouts): ✨ tabs
Browse files Browse the repository at this point in the history
- 标签页可拖拽

- 修改持久化标签配置参数名

- 优化useSortable hooks 逻辑

- 支持删除拖拽功能
  • Loading branch information
jsxiaosi committed Sep 2, 2023
1 parent 01911b2 commit 0c700ee
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 35 deletions.
3 changes: 2 additions & 1 deletion public/serverConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"colorWeaknessMode":false,
"hideNavbart": false,
"hideTabs": false,
"labelPersistent": true,
"closeTabDrag":false,
"tabPersistent": true,
"sidebarFold": "top",
"permissionMode": "REAREND",
"StorageConfig":{
Expand Down
53 changes: 42 additions & 11 deletions src/hooks/web/useSortable.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,54 @@
import { tryOnMounted } from '@vueuse/core';
import type { Options } from 'sortablejs';
import Sortable from 'sortablejs';
import { tryOnMounted } from '@vueuse/core';
import type { Ref } from 'vue';
import { unref } from 'vue';
import { isRef, ref, unref } from 'vue';

function useSortable(el: Ref<HTMLElement | null>, options?: Options) {
tryOnMounted(() => {
if (!unref(el)) {
console.error('SortableHooks Unable To Get HTML Element');
return;
}
Sortable.create(unref(el as Ref<HTMLElement>), {
group: 'name',
animation: 500,
/**
*
* @param options sortableJs配置项
* @param elRef Ref<HTMLElement | null>
* @returns
* - initSortable(el: Ref<HTMLElement | null> | (HTMLElement | null)): 初始化排序功能。
* - destroy: 销毁排序实例,并完全删除可排序功能。
* - sortableJs: SortableJS 实例。
*/

function useSortable(options?: Options, elRef?: Ref<HTMLElement | null>) {
const sortableJs = ref<Sortable | null>(null);

const createSortable = (el: HTMLElement) => {
sortableJs.value = new Sortable(el, {
animation: 300,
delay: 400,
delayOnTouchOnly: true,
...options,
});
};

const initSortable = (el: Ref<HTMLElement | null> | (HTMLElement | null)) => {
if (sortableJs.value) return;

let element: HTMLElement | null;
if (isRef(el)) {
element = unref(el);
} else {
element = el;
}

if (element) createSortable(element);
};

tryOnMounted(() => {
if (elRef) initSortable(elRef);
});

const destroy = () => {
sortableJs.value?.destroy();
sortableJs.value = null;
};

return { initSortable, destroy, sortableJs };
}

export default useSortable;
23 changes: 18 additions & 5 deletions src/layouts/page-layouts/components/AppTabs/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,7 @@
contextmenu(item, event);
};
const tabsEl = ref<HTMLElement | null>(null);
onMounted(() => {
tabsEl.value = document.querySelector('.tabs-container .el-tabs__nav');
});
useSortable(tabsEl, {
const { initSortable, destroy } = useSortable({
handle: '.tabs-view-item',
onEnd({ newIndex, oldIndex }) {
const oldMultiTabs = multiTabs.value;
Expand All @@ -80,6 +76,23 @@
MultiTabsDropReordering(oldMultiTabs);
},
});
const initTableDrag = () => {
if (!appConfig.value.closeTabDrag)
initSortable(document.querySelector<HTMLElement>('.tabs-container .el-tabs__nav'));
};
onMounted(() => {
initTableDrag();
});
watch(
() => appConfig.value.closeTabDrag,
(closeTabDrag) => {
if (closeTabDrag) destroy();
else initTableDrag();
},
);
</script>

<template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
const { persistent } = usePermissionStoreHook();
const labelPersistentRef = ref<boolean>(appConfig.value.labelPersistent);
const labelPersistentRef = ref<boolean>(appConfig.value.tabPersistent);
const labelPersistentChange = (e: string | number | boolean) => {
if (!e) _storage.removeStorage('multiTabsList');
else persistent();
setAppConfigMode({ labelPersistent: Boolean(e) });
setAppConfigMode({ tabPersistent: Boolean(e) });
};
const hidePublicChange = () => {
Expand All @@ -38,6 +38,10 @@
<span>{{ $t('layout.hideTabsConfig') }}</span>
<el-switch v-model="appConfig.hideTabsConfig" @change="hidePublicChange" />
</div>
<div class="options">
<span>{{ $t('layout.closeTabDrag') }}</span>
<el-switch v-model="appConfig.closeTabDrag" @change="hidePublicChange" />
</div>
<div class="options">
<span>{{ $t('layout.labelPersistent') }}</span>
<el-switch v-model="labelPersistentRef" @change="labelPersistentChange" />
Expand Down
3 changes: 2 additions & 1 deletion src/locales/modules/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@
"clearStorage": "Clear cache and return to login page",
"navbar": {
"fullScreen": "Full Screen"
}
},
"closeTabDrag": "Close tab drag"
},
"route": {
"pathName": {
Expand Down
3 changes: 2 additions & 1 deletion src/locales/modules/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@
"clearStorage": "清空缓存回到登录页",
"navbar": {
"fullScreen": "全屏"
}
},
"closeTabDrag": "关闭标签页拖拽"
},
"route": {
"pathName": {
Expand Down
2 changes: 1 addition & 1 deletion src/store/modules/permission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const usePermissionStore = defineStore({
// 持久化
persistent() {
const appConfig = useAppStoreHook();
if (appConfig.appConfigMode.labelPersistent)
if (appConfig.appConfigMode.tabPersistent)
_storage.setStorage('multiTabsList', this.multiTabs);
},
handleMultiTabs(type: 'add' | 'delete', value: MultiTabsType) {
Expand Down
4 changes: 3 additions & 1 deletion src/store/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ export interface AppConfig {
hideNavbart: boolean;
// 隐藏标签栏
hideTabs: boolean;
// 关闭标签页拖拽
closeTabDrag: boolean;
// 隐藏标签栏操作按钮
hideTabsConfig: boolean;
// 标签持久化
labelPersistent: boolean;
tabPersistent: boolean;
// 侧边栏按钮
sidebarFold: 'none' | 'top' | 'bottom';
// 路由模式 REAREND后端路由、ROLE角色权限控制路由
Expand Down
30 changes: 18 additions & 12 deletions src/views/components/drag/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,28 @@
}
const sortableEl = ref<HTMLElement | null>(null);
useSortable(sortableEl, {
handle: '.handle',
// chosenClass: '.sortable-chosen',
onEnd(e) {
console.log(e);
useSortable(
{
handle: '.handle',
group: 'name',
onEnd(e) {
console.log(e);
},
},
});
sortableEl,
);
const gridSortableEl = ref<HTMLElement | null>(null);
useSortable(gridSortableEl, {
handle: '.list-item',
// chosenClass: '.sortable-chosen',
onEnd(e) {
console.log(e);
useSortable(
{
handle: '.list-item',
group: 'name',
onEnd(e) {
console.log(e);
},
},
});
gridSortableEl,
);
</script>

<template>
Expand Down

0 comments on commit 0c700ee

Please sign in to comment.