mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-22 03:26:38 +08:00
refactor(components): 去除packages的soybean-layout,通过npm的方式引入
This commit is contained in:
parent
7ba332cd6a
commit
c1182fef0a
19
package.json
19
package.json
@ -34,10 +34,11 @@
|
|||||||
"dayjs": "^1.10.7",
|
"dayjs": "^1.10.7",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"naive-ui": "^2.25.2",
|
"naive-ui": "^2.25.3",
|
||||||
"pinia": "^2.0.11",
|
"pinia": "^2.0.11",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
"qs": "^6.10.3",
|
"qs": "^6.10.3",
|
||||||
|
"soybean-admin-layout": "^1.0.3",
|
||||||
"swiper": "^8.0.6",
|
"swiper": "^8.0.6",
|
||||||
"ua-parser-js": "^1.0.2",
|
"ua-parser-js": "^1.0.2",
|
||||||
"vditor": "^3.8.11",
|
"vditor": "^3.8.11",
|
||||||
@ -50,15 +51,15 @@
|
|||||||
"@amap/amap-jsapi-types": "^0.0.8",
|
"@amap/amap-jsapi-types": "^0.0.8",
|
||||||
"@commitlint/cli": "^16.2.1",
|
"@commitlint/cli": "^16.2.1",
|
||||||
"@commitlint/config-conventional": "^16.2.1",
|
"@commitlint/config-conventional": "^16.2.1",
|
||||||
"@iconify/json": "^2.1.3",
|
"@iconify/json": "^2.1.4",
|
||||||
"@iconify/vue": "^3.1.3",
|
"@iconify/vue": "^3.1.3",
|
||||||
"@types/bmapgl": "^0.0.5",
|
"@types/bmapgl": "^0.0.5",
|
||||||
"@types/crypto-js": "^4.1.1",
|
"@types/crypto-js": "^4.1.1",
|
||||||
"@types/node": "^17.0.18",
|
"@types/node": "^17.0.19",
|
||||||
"@types/qs": "^6.9.7",
|
"@types/qs": "^6.9.7",
|
||||||
"@types/ua-parser-js": "^0.7.36",
|
"@types/ua-parser-js": "^0.7.36",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.12.0",
|
"@typescript-eslint/eslint-plugin": "^5.12.1",
|
||||||
"@typescript-eslint/parser": "^5.12.0",
|
"@typescript-eslint/parser": "^5.12.1",
|
||||||
"@vitejs/plugin-vue": "^2.2.2",
|
"@vitejs/plugin-vue": "^2.2.2",
|
||||||
"@vue/eslint-config-prettier": "^7.0.0",
|
"@vue/eslint-config-prettier": "^7.0.0",
|
||||||
"@vue/eslint-config-typescript": "^10.0.0",
|
"@vue/eslint-config-typescript": "^10.0.0",
|
||||||
@ -71,7 +72,7 @@
|
|||||||
"eslint-config-prettier": "^8.4.0",
|
"eslint-config-prettier": "^8.4.0",
|
||||||
"eslint-plugin-import": "^2.25.4",
|
"eslint-plugin-import": "^2.25.4",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"eslint-plugin-vue": "^8.4.1",
|
"eslint-plugin-vue": "^8.5.0",
|
||||||
"husky": "^7.0.4",
|
"husky": "^7.0.4",
|
||||||
"lint-staged": "^12.3.4",
|
"lint-staged": "^12.3.4",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
@ -82,13 +83,13 @@
|
|||||||
"sass": "^1.49.8",
|
"sass": "^1.49.8",
|
||||||
"typescript": "^4.5.5",
|
"typescript": "^4.5.5",
|
||||||
"unplugin-icons": "^0.13.2",
|
"unplugin-icons": "^0.13.2",
|
||||||
"unplugin-vue-components": "^0.17.18",
|
"unplugin-vue-components": "^0.17.19",
|
||||||
"vite": "2.8.4",
|
"vite": "2.8.4",
|
||||||
"vite-plugin-html": "^3.0.6",
|
"vite-plugin-html": "^3.0.6",
|
||||||
"vite-plugin-mock": "^2.9.6",
|
"vite-plugin-mock": "^2.9.6",
|
||||||
"vite-plugin-windicss": "^1.7.1",
|
"vite-plugin-windicss": "^1.7.1",
|
||||||
"vue-tsc": "^0.31.4",
|
"vue-tsc": "^0.31.4",
|
||||||
"vueuc": "^0.4.25",
|
"vueuc": "^0.4.26",
|
||||||
"windicss": "^3.4.3"
|
"windicss": "^3.4.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1238
pnpm-lock.yaml
1238
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<soybean-layout
|
<soybean-admin-layout
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
:min-width="theme.layout.minWidth"
|
:min-width="theme.layout.minWidth"
|
||||||
:fixed-header-and-tab="theme.fixedHeaderAndTab"
|
:fixed-header-and-tab="theme.fixedHeaderAndTab"
|
||||||
@ -25,14 +25,15 @@
|
|||||||
<template #footer>
|
<template #footer>
|
||||||
<global-footer />
|
<global-footer />
|
||||||
</template>
|
</template>
|
||||||
</soybean-layout>
|
</soybean-admin-layout>
|
||||||
<setting-drawer />
|
<setting-drawer />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import SoybeanAdminLayout from 'soybean-admin-layout';
|
||||||
|
import 'soybean-admin-layout/dist/style.css';
|
||||||
import { useAppStore, useThemeStore } from '@/store';
|
import { useAppStore, useThemeStore } from '@/store';
|
||||||
import { useBasicLayout } from '@/composables';
|
import { useBasicLayout } from '@/composables';
|
||||||
import { SoybeanLayout } from '@/package';
|
|
||||||
import { SettingDrawer, GlobalHeader, GlobalTab, GlobalSider, GlobalContent, GlobalFooter } from '../common';
|
import { SettingDrawer, GlobalHeader, GlobalTab, GlobalSider, GlobalContent, GlobalFooter } from '../common';
|
||||||
|
|
||||||
const app = useAppStore();
|
const app = useAppStore();
|
||||||
|
@ -13,7 +13,11 @@
|
|||||||
</span>
|
</span>
|
||||||
</n-dropdown>
|
</n-dropdown>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<component :is="breadcrumb.icon" v-if="theme.header.crumb.showIcon" class="inline-block mr-4px text-16px" />
|
<component
|
||||||
|
:is="breadcrumb.icon"
|
||||||
|
v-if="theme.header.crumb.showIcon"
|
||||||
|
class="inline-block align-text-bottom mr-4px text-16px"
|
||||||
|
/>
|
||||||
<span>{{ breadcrumb.label }}</span>
|
<span>{{ breadcrumb.label }}</span>
|
||||||
</template>
|
</template>
|
||||||
</n-breadcrumb-item>
|
</n-breadcrumb-item>
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
import SoybeanLayout from './src/index.vue';
|
|
||||||
|
|
||||||
export default SoybeanLayout;
|
|
@ -1,42 +0,0 @@
|
|||||||
<template>
|
|
||||||
<main :style="style" class="soybean-layout__main">
|
|
||||||
<slot></slot>
|
|
||||||
</main>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
/** 顶部内边距 */
|
|
||||||
paddingTop?: number;
|
|
||||||
/** 底部内边距 */
|
|
||||||
paddingBottom?: number;
|
|
||||||
/** 左侧内边距 */
|
|
||||||
paddingLeft?: number;
|
|
||||||
/** 动画过渡时间 */
|
|
||||||
transitionDuration?: number;
|
|
||||||
/** 动画过渡时间 */
|
|
||||||
transitionTimingFunction?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
|
||||||
paddingTop: 0,
|
|
||||||
paddingBottom: 0,
|
|
||||||
paddingLeft: 0,
|
|
||||||
transitionDuration: 300,
|
|
||||||
transitionTimingFunction: 'ease-in-out'
|
|
||||||
});
|
|
||||||
|
|
||||||
const style = computed(() => {
|
|
||||||
const { paddingTop, paddingBottom, paddingLeft, transitionDuration, transitionTimingFunction } = props;
|
|
||||||
return `padding-top: ${paddingTop}px;padding-bottom: ${paddingBottom}px;padding-left: ${paddingLeft}px;transition-duration: ${transitionDuration}ms;transition-timing-function: ${transitionTimingFunction};`;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
.soybean-layout__main {
|
|
||||||
flex-grow: 1;
|
|
||||||
width: 100%;
|
|
||||||
transition-property: padding-left;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,51 +0,0 @@
|
|||||||
<template>
|
|
||||||
<footer class="soybean-layout__footer" :style="style">
|
|
||||||
<slot></slot>
|
|
||||||
</footer>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
/** 开启fixed布局 */
|
|
||||||
fixed?: boolean;
|
|
||||||
/** fixed布局的层级 */
|
|
||||||
zIndex?: number;
|
|
||||||
/** 最小宽度 */
|
|
||||||
minWidth?: number;
|
|
||||||
/** 高度 */
|
|
||||||
height?: number;
|
|
||||||
/** 左侧内边距 */
|
|
||||||
paddingLeft?: number;
|
|
||||||
/** 动画过渡时间 */
|
|
||||||
transitionDuration?: number;
|
|
||||||
/** 动画过渡时间 */
|
|
||||||
transitionTimingFunction?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
|
||||||
fixed: true,
|
|
||||||
zIndex: 999,
|
|
||||||
minWidth: 1200,
|
|
||||||
height: 56,
|
|
||||||
paddingLeft: 0,
|
|
||||||
transitionDuration: 300,
|
|
||||||
transitionTimingFunction: 'ease-in-out'
|
|
||||||
});
|
|
||||||
|
|
||||||
const style = computed(() => {
|
|
||||||
const { fixed, zIndex, minWidth, height, paddingLeft, transitionDuration, transitionTimingFunction } = props;
|
|
||||||
const position = fixed ? 'fixed' : 'static';
|
|
||||||
return `position: ${position};z-index: ${zIndex};min-width: ${minWidth}px;height: ${height}px;padding-left: ${paddingLeft}px;transition-duration: ${transitionDuration}ms;transition-timing-function: ${transitionTimingFunction};`;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
.soybean-layout__footer {
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 100%;
|
|
||||||
transition-property: padding-left;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,51 +0,0 @@
|
|||||||
<template>
|
|
||||||
<header class="soybean-layout__header" :style="style">
|
|
||||||
<slot></slot>
|
|
||||||
</header>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
/** 开启fixed布局 */
|
|
||||||
fixed?: boolean;
|
|
||||||
/** fixed布局的层级 */
|
|
||||||
zIndex?: number;
|
|
||||||
/** 最小宽度 */
|
|
||||||
minWidth?: number;
|
|
||||||
/** 高度 */
|
|
||||||
height?: number;
|
|
||||||
/** 左侧内边距 */
|
|
||||||
paddingLeft?: number;
|
|
||||||
/** 动画过渡时间 */
|
|
||||||
transitionDuration?: number;
|
|
||||||
/** 动画过渡时间 */
|
|
||||||
transitionTimingFunction?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
|
||||||
fixed: true,
|
|
||||||
zIndex: 1001,
|
|
||||||
minWidth: 1200,
|
|
||||||
height: 56,
|
|
||||||
paddingLeft: 0,
|
|
||||||
transitionDuration: 300,
|
|
||||||
transitionTimingFunction: 'ease-in-out'
|
|
||||||
});
|
|
||||||
|
|
||||||
const style = computed(() => {
|
|
||||||
const { fixed, zIndex, minWidth, height, paddingLeft, transitionDuration, transitionTimingFunction } = props;
|
|
||||||
const position = fixed ? 'fixed' : 'static';
|
|
||||||
return `position: ${position};z-index: ${zIndex};min-width: ${minWidth}px;height: ${height}px;padding-left: ${paddingLeft}px;transition-duration: ${transitionDuration}ms;transition-timing-function: ${transitionTimingFunction};`;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
.soybean-layout__header {
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 100%;
|
|
||||||
transition-property: padding-left;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,44 +0,0 @@
|
|||||||
<template>
|
|
||||||
<aside class="soybean-layout__sider" :style="style">
|
|
||||||
<slot></slot>
|
|
||||||
</aside>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
/** fixed布局的层级 */
|
|
||||||
zIndex?: number;
|
|
||||||
/** 宽度 */
|
|
||||||
width?: number;
|
|
||||||
/** 顶部内边距 */
|
|
||||||
paddingTop?: number;
|
|
||||||
/** 动画过渡时间 */
|
|
||||||
transitionDuration?: number;
|
|
||||||
/** 动画过渡时间 */
|
|
||||||
transitionTimingFunction?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
|
||||||
zIndex: 1002,
|
|
||||||
width: 200,
|
|
||||||
paddingTop: 0,
|
|
||||||
transitionDuration: 300,
|
|
||||||
transitionTimingFunction: 'ease-in-out'
|
|
||||||
});
|
|
||||||
|
|
||||||
const style = computed(() => {
|
|
||||||
const { zIndex, width, paddingTop, transitionDuration, transitionTimingFunction } = props;
|
|
||||||
return `z-index: ${zIndex};width: ${width}px;padding-top: ${paddingTop}px;transition-duration: ${transitionDuration}ms;transition-timing-function: ${transitionTimingFunction};`;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
.soybean-layout__sider {
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
|
||||||
transition-property: all;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,53 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="soybean-layout__tab" :style="style">
|
|
||||||
<slot></slot>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
/** 开启fixed布局 */
|
|
||||||
fixed?: boolean;
|
|
||||||
/** fixed布局的top距离 */
|
|
||||||
top?: number;
|
|
||||||
/** fixed布局的层级 */
|
|
||||||
zIndex?: number;
|
|
||||||
/** 最小宽度 */
|
|
||||||
minWidth?: number;
|
|
||||||
/** 高度 */
|
|
||||||
height?: number;
|
|
||||||
/** 左侧内边距 */
|
|
||||||
paddingLeft?: number;
|
|
||||||
/** 动画过渡时间 */
|
|
||||||
transitionDuration?: number;
|
|
||||||
/** 动画过渡时间 */
|
|
||||||
transitionTimingFunction?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
|
||||||
fixed: true,
|
|
||||||
top: 56,
|
|
||||||
zIndex: 999,
|
|
||||||
minWidth: 1200,
|
|
||||||
height: 56,
|
|
||||||
paddingLeft: 0,
|
|
||||||
transitionDuration: 300,
|
|
||||||
transitionTimingFunction: 'ease-in-out'
|
|
||||||
});
|
|
||||||
|
|
||||||
const style = computed(() => {
|
|
||||||
const { fixed, top, zIndex, minWidth, height, paddingLeft, transitionDuration, transitionTimingFunction } = props;
|
|
||||||
const position = fixed ? 'fixed' : 'static';
|
|
||||||
return `position: ${position};top: ${top}px;z-index: ${zIndex};min-width: ${minWidth}px;height: ${height}px;padding-left: ${paddingLeft}px;transition-duration: ${transitionDuration}ms;transition-timing-function: ${transitionTimingFunction};`;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
.soybean-layout__tab {
|
|
||||||
left: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 100%;
|
|
||||||
transition-property: padding-left;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,7 +0,0 @@
|
|||||||
import LayoutHeader from './LayoutHeader.vue';
|
|
||||||
import LayoutTab from './LayoutTab.vue';
|
|
||||||
import LayoutSider from './LayoutSider.vue';
|
|
||||||
import LayoutContent from './LayoutContent.vue';
|
|
||||||
import LayoutFooter from './LayoutFooter.vue';
|
|
||||||
|
|
||||||
export { LayoutSider, LayoutHeader, LayoutTab, LayoutContent, LayoutFooter };
|
|
@ -1,53 +0,0 @@
|
|||||||
import { ref, computed, watch, onUnmounted } from 'vue';
|
|
||||||
import type { Ref, ComputedRef } from 'vue';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用了固定定位的布局元素添加translateX
|
|
||||||
* @param isFixed - 是否是fixed布局
|
|
||||||
*/
|
|
||||||
export function useFixedTransformStyle(isFixed: Ref<boolean> | ComputedRef<boolean>) {
|
|
||||||
const scrollLeft = ref(0);
|
|
||||||
const transformStyle = computed(() => `transform: translateX(${-scrollLeft.value}px);`);
|
|
||||||
|
|
||||||
function setScrollLeft(sLeft: number) {
|
|
||||||
scrollLeft.value = sLeft;
|
|
||||||
}
|
|
||||||
function scrollHandler() {
|
|
||||||
const sLeft = document.scrollingElement?.scrollLeft || 0;
|
|
||||||
setScrollLeft(sLeft);
|
|
||||||
}
|
|
||||||
function initScrollLeft() {
|
|
||||||
scrollHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
function addScrollEventListener() {
|
|
||||||
document.addEventListener('scroll', scrollHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeScrollEventListener() {
|
|
||||||
document.removeEventListener('scroll', scrollHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
initScrollLeft();
|
|
||||||
addScrollEventListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
|
||||||
isFixed,
|
|
||||||
newValue => {
|
|
||||||
if (newValue) {
|
|
||||||
init();
|
|
||||||
} else {
|
|
||||||
removeScrollEventListener();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
removeScrollEventListener();
|
|
||||||
});
|
|
||||||
|
|
||||||
return transformStyle;
|
|
||||||
}
|
|
@ -1,174 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="soybean-layout" :style="{ minWidth: minWidth + 'px' }">
|
|
||||||
<layout-header
|
|
||||||
v-if="headerVisible"
|
|
||||||
v-bind="commonProps"
|
|
||||||
:fixed="fixedHeaderAndTab"
|
|
||||||
:z-index="headerZIndex"
|
|
||||||
:min-width="minWidth"
|
|
||||||
:height="headerHeight"
|
|
||||||
:padding-left="headerPaddingLeft"
|
|
||||||
:style="headerAndTabTransform"
|
|
||||||
>
|
|
||||||
<slot name="header"></slot>
|
|
||||||
</layout-header>
|
|
||||||
<layout-tab
|
|
||||||
v-if="tabVisible"
|
|
||||||
v-bind="commonProps"
|
|
||||||
:fixed="fixedHeaderAndTab"
|
|
||||||
:z-index="tabZIndex"
|
|
||||||
:min-width="minWidth"
|
|
||||||
:top="headerHeight"
|
|
||||||
:height="tabHeight"
|
|
||||||
:padding-left="siderWidth"
|
|
||||||
:style="headerAndTabTransform"
|
|
||||||
>
|
|
||||||
<slot name="tab"></slot>
|
|
||||||
</layout-tab>
|
|
||||||
<layout-sider
|
|
||||||
v-if="siderVisible"
|
|
||||||
v-bind="commonProps"
|
|
||||||
:z-index="siderZIndex"
|
|
||||||
:width="siderWidth"
|
|
||||||
:padding-top="siderPaddingTop"
|
|
||||||
>
|
|
||||||
<slot name="sider"></slot>
|
|
||||||
</layout-sider>
|
|
||||||
<layout-content
|
|
||||||
v-bind="commonProps"
|
|
||||||
:padding-top="contentPaddingTop"
|
|
||||||
:padding-bottom="contentPaddingBottom"
|
|
||||||
:padding-left="siderWidth"
|
|
||||||
>
|
|
||||||
<slot></slot>
|
|
||||||
</layout-content>
|
|
||||||
<layout-footer
|
|
||||||
v-if="footerVisible"
|
|
||||||
v-bind="commonProps"
|
|
||||||
:fixed="fixedFooter"
|
|
||||||
:z-index="footerZIndex"
|
|
||||||
:min-width="minWidth"
|
|
||||||
:height="footerHeight"
|
|
||||||
:padding-left="siderWidth"
|
|
||||||
:style="footerTransform"
|
|
||||||
>
|
|
||||||
<slot name="footer"></slot>
|
|
||||||
</layout-footer>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue';
|
|
||||||
import { LayoutHeader, LayoutTab, LayoutSider, LayoutContent, LayoutFooter } from './components';
|
|
||||||
import { useFixedTransformStyle } from './hooks';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
/** 布局模式 */
|
|
||||||
mode?: 'vertical' | 'horizontal';
|
|
||||||
/** 最小宽度 */
|
|
||||||
minWidth?: number;
|
|
||||||
/** 头部可见 */
|
|
||||||
headerVisible?: boolean;
|
|
||||||
/** 头部高度 */
|
|
||||||
headerHeight?: number;
|
|
||||||
/** 标签可见 */
|
|
||||||
tabVisible?: boolean;
|
|
||||||
/** 标签页高度 */
|
|
||||||
tabHeight?: number;
|
|
||||||
/** 固定头部和标签 */
|
|
||||||
fixedHeaderAndTab?: boolean;
|
|
||||||
/** 底部可见 */
|
|
||||||
footerVisible?: boolean;
|
|
||||||
/** 底部高度 */
|
|
||||||
footerHeight?: number;
|
|
||||||
/** 固定底部 */
|
|
||||||
fixedFooter?: boolean;
|
|
||||||
/** 侧边可见 */
|
|
||||||
siderVisible?: boolean;
|
|
||||||
/** 侧边栏高度 */
|
|
||||||
siderWidth?: number;
|
|
||||||
/** 侧边栏折叠状态的高度 */
|
|
||||||
siderCollapsedWidth?: number;
|
|
||||||
/** 侧边栏折叠状态 */
|
|
||||||
siderCollapse?: boolean;
|
|
||||||
/** 动画过渡时间 */
|
|
||||||
transitionDuration?: number;
|
|
||||||
/** 动画过渡时间 */
|
|
||||||
transitionTimingFunction?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
|
||||||
mode: 'vertical',
|
|
||||||
minWidth: 1200,
|
|
||||||
headerVisible: true,
|
|
||||||
headerHeight: 56,
|
|
||||||
tabVisible: true,
|
|
||||||
tabHeight: 44,
|
|
||||||
fixedHeaderAndTab: true,
|
|
||||||
footerVisible: true,
|
|
||||||
footerHeight: 48,
|
|
||||||
fixedFooter: true,
|
|
||||||
siderVisible: true,
|
|
||||||
siderWidth: 200,
|
|
||||||
siderCollapsedWidth: 64,
|
|
||||||
siderCollapse: false,
|
|
||||||
transitionDuration: 300,
|
|
||||||
transitionTimingFunction: 'ease-in-out'
|
|
||||||
});
|
|
||||||
|
|
||||||
// fixed布局时,应用translateX样式(水平方向出现滚动条,拖动滚动条时,fixed元素跟着滚动)
|
|
||||||
const hasFixedEl = computed(() => props.fixedHeaderAndTab || props.fixedFooter);
|
|
||||||
const transformStyle = useFixedTransformStyle(hasFixedEl);
|
|
||||||
const headerAndTabTransform = computed(() => (props.fixedHeaderAndTab ? transformStyle.value : ''));
|
|
||||||
const footerTransform = computed(() => (props.fixedFooter ? transformStyle.value : ''));
|
|
||||||
|
|
||||||
/** 各个子组件的公共属性 */
|
|
||||||
const commonProps = computed(() => {
|
|
||||||
const { transitionDuration, transitionTimingFunction } = props;
|
|
||||||
return {
|
|
||||||
transitionDuration,
|
|
||||||
transitionTimingFunction
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
/** 水平布局 */
|
|
||||||
const isVertical = computed(() => props.mode === 'vertical');
|
|
||||||
|
|
||||||
// fixed布局时的层级
|
|
||||||
const headerZIndex = 1001;
|
|
||||||
const tabZIndex = 999;
|
|
||||||
const siderZIndex = computed(() => (isVertical.value ? 1002 : 1000));
|
|
||||||
const footerZIndex = 999;
|
|
||||||
|
|
||||||
/** 侧边宽度 */
|
|
||||||
const siderWidth = computed(() => {
|
|
||||||
const { siderCollapse, siderWidth, siderCollapsedWidth } = props;
|
|
||||||
const width = siderCollapse ? siderCollapsedWidth : siderWidth;
|
|
||||||
return props.siderVisible ? width : 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 各子组件的属性
|
|
||||||
const headerPaddingLeft = computed(() => (isVertical.value ? siderWidth.value : 0));
|
|
||||||
const siderPaddingTop = computed(() => (!isVertical.value && props.headerVisible ? props.headerHeight : 0));
|
|
||||||
const contentPaddingTop = computed(() => {
|
|
||||||
let height = 0;
|
|
||||||
if (props.fixedHeaderAndTab) {
|
|
||||||
if (props.headerVisible) {
|
|
||||||
height += props.headerHeight;
|
|
||||||
}
|
|
||||||
if (props.tabVisible) {
|
|
||||||
height += props.tabHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return height;
|
|
||||||
});
|
|
||||||
const contentPaddingBottom = computed(() => (props.fixedFooter && props.footerVisible ? props.footerHeight : 0));
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
.soybean-layout {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,3 +0,0 @@
|
|||||||
import SoybeanLayout from './SoybeanLayout';
|
|
||||||
|
|
||||||
export { SoybeanLayout };
|
|
Loading…
Reference in New Issue
Block a user