commit
1fc3e3c411
138
example/docs/zh-CN/components/splitPanel.md
Normal file
138
example/docs/zh-CN/components/splitPanel.md
Normal file
@ -0,0 +1,138 @@
|
||||
::: anchor
|
||||
:::
|
||||
|
||||
::: title 基础使用
|
||||
:::
|
||||
|
||||
|
||||
::: demo
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<lay-split-panel style="height: 300px">
|
||||
<lay-split-panel-item>A</lay-split-panel-item>
|
||||
<lay-split-panel-item>B</lay-split-panel-item>
|
||||
<lay-split-panel-item>C</lay-split-panel-item>
|
||||
</lay-split-panel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
::: title 自定义比例
|
||||
:::
|
||||
|
||||
|
||||
::: demo
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<lay-split-panel style="height: 300px">
|
||||
<lay-split-panel-item :space="30">1</lay-split-panel-item>
|
||||
<lay-split-panel-item :space="20">2</lay-split-panel-item>
|
||||
<lay-split-panel-item :space="50">3</lay-split-panel-item>
|
||||
</lay-split-panel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
::: title 垂直布局
|
||||
:::
|
||||
|
||||
|
||||
::: demo
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<lay-split-panel :vertical="true" style="height: 600px; width: 100%">
|
||||
<lay-split-panel-item>1</lay-split-panel-item>
|
||||
<lay-split-panel-item>2</lay-split-panel-item>
|
||||
<lay-split-panel-item>3</lay-split-panel-item>
|
||||
</lay-split-panel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
::: title 组合用法
|
||||
:::
|
||||
|
||||
|
||||
::: demo
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<lay-split-panel style="height: 600px;">
|
||||
<lay-split-panel-item :space="60">
|
||||
<lay-split-panel :vertical="true" style="height: 600px; width: 100%">
|
||||
<lay-split-panel-item :space="40">1</lay-split-panel-item>
|
||||
<lay-split-panel-item :space="40">2</lay-split-panel-item>
|
||||
</lay-split-panel>
|
||||
</lay-split-panel-item>
|
||||
<lay-split-panel-item :space="40">2</lay-split-panel-item>
|
||||
</lay-split-panel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
::: title splitPanel属性
|
||||
:::
|
||||
|
||||
::: table
|
||||
|
||||
| 属性 | 描述 | 类型 |可选值 | 默认值|
|
||||
| ----- | ---- | ------ | ---| ---|
|
||||
| vertical | 是否垂直布局 | Boolean |`true` `false`| false |
|
||||
| minSize | 块拉动最小范围(按像素 `px`) | number | - | 50 |
|
||||
:::
|
||||
|
||||
::: title splitPanelItem属性
|
||||
:::
|
||||
|
||||
::: table
|
||||
|
||||
| 属性 | 描述 | 类型 |可选值 | 默认值|
|
||||
| ----- | ---- | ------ | ---| ---|
|
||||
| space | 默认每个站多大比例(`%`), 设置一个,<br/> 其他的都需要设置,合计为(`100` ) | number | - | 按照个数平分 |
|
||||
:::
|
||||
|
||||
|
||||
::: comment
|
||||
:::
|
||||
|
||||
::: previousNext splitPanel
|
||||
:::
|
@ -76,6 +76,12 @@ const zhCN = [
|
||||
component: Component,
|
||||
meta: { title: "组件" },
|
||||
children: [
|
||||
{
|
||||
path: "/zh-CN/components/splitPanel",
|
||||
component: () =>
|
||||
import("../../docs/zh-CN/components/splitPanel.md"),
|
||||
meta: { title: "分割面板" },
|
||||
},
|
||||
{
|
||||
path: "/zh-CN/components/skeleton",
|
||||
component: () => import("../../docs/zh-CN/components/skeleton.md"),
|
||||
|
14
src/index.ts
14
src/index.ts
@ -71,9 +71,13 @@ import LaySkeleton from "./module/skeleton/index";
|
||||
import LaySkeletonItem from "./module/skeletonItem/index";
|
||||
import LayStep from "./module/step/index";
|
||||
import LayStepItem from "./module/stepItem/index";
|
||||
import LaySubMenu from "./module/subMenu/index"
|
||||
import LaySubMenu from "./module/subMenu/index";
|
||||
import LaySplitPanel from "./module/splitPanel/index";
|
||||
import LaySplitPanelItem from "./module/splitPanelItem/index";
|
||||
|
||||
export const components: Record<string, IDefineComponent> = {
|
||||
const components: Record<string, IDefineComponent> = {
|
||||
LaySplitPanel,
|
||||
LaySplitPanelItem,
|
||||
LayRadio,
|
||||
LayButton,
|
||||
LayIcon,
|
||||
@ -139,7 +143,7 @@ export const components: Record<string, IDefineComponent> = {
|
||||
LayCountUp,
|
||||
LayStep,
|
||||
LayStepItem,
|
||||
LaySubMenu
|
||||
LaySubMenu,
|
||||
};
|
||||
|
||||
const install = (app: App, options?: InstallOptions): void => {
|
||||
@ -152,6 +156,8 @@ const install = (app: App, options?: InstallOptions): void => {
|
||||
};
|
||||
|
||||
export {
|
||||
LaySplitPanel,
|
||||
LaySplitPanelItem,
|
||||
LayRadio,
|
||||
LayButton,
|
||||
LayIcon,
|
||||
@ -217,7 +223,7 @@ export {
|
||||
LayCountUp,
|
||||
LayStep,
|
||||
LayStepItem,
|
||||
LaySubMenu
|
||||
LaySubMenu,
|
||||
};
|
||||
|
||||
export { layer };
|
||||
|
63
src/module/splitPanel/index.less
Normal file
63
src/module/splitPanel/index.less
Normal file
@ -0,0 +1,63 @@
|
||||
.lay-split-panel{
|
||||
height: 100%;
|
||||
display: flex;
|
||||
position: relative;
|
||||
.lay-split-panel-item {
|
||||
height: 100%;
|
||||
flex-grow: 1;
|
||||
border: 1px #eeeeee solid;
|
||||
}
|
||||
.lay-split-panel-item-move{
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
cursor: col-resize;
|
||||
}
|
||||
.lay-split-panel-line{
|
||||
height: 100%;
|
||||
width: 3px;
|
||||
border: 1px #eeeeee solid;
|
||||
background-color: #fafafa;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
cursor: col-resize;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&:before{
|
||||
content: "";
|
||||
height: 6px;
|
||||
width: 100%;
|
||||
border: 2px solid #dcdee2;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lay-split-panel-vertical{
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
.lay-split-panel-item-move{
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
cursor: row-resize;
|
||||
}
|
||||
.lay-split-panel-line{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
cursor: row-resize;
|
||||
border: 1px #eeeeee solid;
|
||||
background-color: #fafafa;
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
&:before{
|
||||
content: "";
|
||||
height: 100%;
|
||||
width: 6px;
|
||||
border: 2px solid #dcdee2;
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
9
src/module/splitPanel/index.ts
Normal file
9
src/module/splitPanel/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import type { App } from "vue";
|
||||
import Component from "./index.vue";
|
||||
import type { IDefineComponent } from "../type/index";
|
||||
|
||||
Component.install = (app: App) => {
|
||||
app.component(Component.name || "laySplitPanel", Component);
|
||||
};
|
||||
|
||||
export default Component as IDefineComponent;
|
128
src/module/splitPanel/index.vue
Normal file
128
src/module/splitPanel/index.vue
Normal file
@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<div
|
||||
ref="target"
|
||||
:class="['lay-split-panel', vertical ? 'lay-split-panel-vertical' : '']"
|
||||
:style="{
|
||||
cursor: domStatus ? (!vertical ? 'col-resize' : 'row-resize') : '',
|
||||
}"
|
||||
v-on="{ mouseup: mouseup }"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="laySplitPanel" lang="ts">
|
||||
import { ref, watch, provide, defineProps, withDefaults, onMounted } from "vue";
|
||||
import "./index.less";
|
||||
|
||||
// 属性接口定义
|
||||
export interface LayStepProps {
|
||||
vertical?: boolean;
|
||||
minSize?: number;
|
||||
}
|
||||
// props初始化数据定义
|
||||
const props = withDefaults(defineProps<LayStepProps>(), {
|
||||
vertical: false,
|
||||
minSize: 50,
|
||||
});
|
||||
let domEvent = ref();
|
||||
let domStatus = ref(false);
|
||||
const target = ref();
|
||||
|
||||
onMounted(() => {
|
||||
const boxWidth = target.value.offsetWidth;
|
||||
const boxHeight = target.value.offsetHeight;
|
||||
window.addEventListener("scroll", (event) => {
|
||||
console.log(event);
|
||||
});
|
||||
target.value.addEventListener(
|
||||
"mousemove",
|
||||
(event: { layerX: any; layerY: any }) => {
|
||||
if (domStatus.value) {
|
||||
const prevDom = domEvent.value.target.previousElementSibling;
|
||||
const nextDom = domEvent.value.target.nextElementSibling;
|
||||
if (!props.vertical) {
|
||||
const prevDomLeft =
|
||||
domEvent.value.target.previousElementSibling.offsetLeft;
|
||||
const prevDomWidth =
|
||||
domEvent.value.target.previousElementSibling.offsetWidth;
|
||||
const nextDomWidth =
|
||||
domEvent.value.target.nextElementSibling.offsetWidth;
|
||||
const otherWidth = boxWidth - (prevDomWidth + nextDomWidth + 5);
|
||||
const otherWidthPercentage =
|
||||
((prevDomWidth + nextDomWidth + 5) / boxWidth) * 100;
|
||||
if (
|
||||
event.layerX - prevDomLeft < props.minSize ||
|
||||
boxWidth - (event.layerX - prevDomLeft) - otherWidth < props.minSize
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
prevDom.style.width =
|
||||
((event.layerX - prevDomLeft) / (prevDomWidth + nextDomWidth + 5)) *
|
||||
otherWidthPercentage +
|
||||
"%";
|
||||
nextDom.style.width =
|
||||
((boxWidth - (event.layerX - prevDomLeft) - otherWidth) /
|
||||
(prevDomWidth + nextDomWidth + 5)) *
|
||||
otherWidthPercentage +
|
||||
"%";
|
||||
} else {
|
||||
const prevDomTop =
|
||||
domEvent.value.target.previousElementSibling.offsetTop;
|
||||
const prevDomHeight =
|
||||
domEvent.value.target.previousElementSibling.offsetHeight;
|
||||
const nextDomHeight =
|
||||
domEvent.value.target.nextElementSibling.offsetHeight;
|
||||
const otherHeight = boxHeight - (prevDomHeight + nextDomHeight + 5);
|
||||
const otherHeightPercentage =
|
||||
((prevDomHeight + nextDomHeight + 5) / boxHeight) * 100;
|
||||
if (
|
||||
event.layerY - prevDomTop < props.minSize ||
|
||||
boxHeight - (event.layerY - prevDomTop) - otherHeight <
|
||||
props.minSize
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
prevDom.style.height =
|
||||
((event.layerY - prevDomTop) /
|
||||
(prevDomHeight + nextDomHeight + 5)) *
|
||||
otherHeightPercentage +
|
||||
"%";
|
||||
nextDom.style.height =
|
||||
((boxHeight - (event.layerY - prevDomTop) - otherHeight) /
|
||||
(prevDomHeight + nextDomHeight + 5)) *
|
||||
otherHeightPercentage +
|
||||
"%";
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const moveChange = (event: any, status: boolean) => {
|
||||
domEvent.value = event;
|
||||
domStatus.value = status;
|
||||
};
|
||||
|
||||
const mouseup = () => {
|
||||
domStatus.value = false;
|
||||
};
|
||||
|
||||
// 定义初始化个数数组
|
||||
const steps = ref([]);
|
||||
// 监听有几个lay-split-panel-item
|
||||
watch(steps, () => {
|
||||
steps.value.forEach(
|
||||
(instance: { setIndex: (arg0: any) => void }, index: any) => {
|
||||
instance.setIndex(index);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// 向lay-split-panel-item传递参数
|
||||
provide("laySplitPanel", {
|
||||
props,
|
||||
steps,
|
||||
moveChange,
|
||||
});
|
||||
</script>
|
9
src/module/splitPanelItem/index.ts
Normal file
9
src/module/splitPanelItem/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import type { App } from "vue";
|
||||
import Component from "./index.vue";
|
||||
import type { IDefineComponent } from "../type/index";
|
||||
|
||||
Component.install = (app: App) => {
|
||||
app.component(Component.name || "laySplitPanelItem", Component);
|
||||
};
|
||||
|
||||
export default Component as IDefineComponent;
|
96
src/module/splitPanelItem/index.vue
Normal file
96
src/module/splitPanelItem/index.vue
Normal file
@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="!isStart"
|
||||
:class="[!isStart ? 'lay-split-panel-line' : '']"
|
||||
ref="el"
|
||||
v-on="{ mousedown: mousedown, mouseup: mouseup }"
|
||||
></div>
|
||||
<div
|
||||
v-if="isVertical"
|
||||
:class="['lay-split-panel-item']"
|
||||
:style="{ height: `${space ? space : (100 + space) / stepsCount}%` }"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
:class="['lay-split-panel-item']"
|
||||
:style="{ width: `${space ? space : (100 + space) / stepsCount}%` }"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="laySplitPanelItem" lang="ts">
|
||||
import {
|
||||
ref,
|
||||
inject,
|
||||
onMounted,
|
||||
computed,
|
||||
getCurrentInstance,
|
||||
onBeforeUnmount,
|
||||
reactive,
|
||||
defineProps,
|
||||
withDefaults,
|
||||
watch,
|
||||
} from "vue";
|
||||
|
||||
import type { ComputedRef } from "vue";
|
||||
|
||||
export interface LayStepItemProps {
|
||||
space?: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<LayStepItemProps>(), {
|
||||
space: 0,
|
||||
});
|
||||
const index = ref(-1);
|
||||
const parents: any = inject("laySplitPanel");
|
||||
const currentInstance: any = getCurrentInstance();
|
||||
const moveStatus = ref(false);
|
||||
const setIndex = (val: number) => {
|
||||
index.value = val;
|
||||
};
|
||||
|
||||
const mousedown = (event: any) => {
|
||||
moveStatus.value = true;
|
||||
parents.moveChange(event, true);
|
||||
};
|
||||
|
||||
const mouseup = (event: any) => {
|
||||
moveStatus.value = false;
|
||||
};
|
||||
|
||||
const stepsCount = computed(() => {
|
||||
return parents.steps.value.length;
|
||||
});
|
||||
|
||||
const isVertical = computed(() => {
|
||||
return parents.props.vertical;
|
||||
});
|
||||
|
||||
const isLast: ComputedRef<boolean> = computed(() => {
|
||||
return (
|
||||
parents.steps.value[stepsCount.value - 1]?.itemId === currentInstance.uid
|
||||
);
|
||||
});
|
||||
|
||||
const isStart: ComputedRef<boolean> = computed(() => {
|
||||
return parents.steps.value[0]?.itemId === currentInstance.uid;
|
||||
});
|
||||
const stepItemState = reactive({
|
||||
itemId: computed(() => currentInstance?.uid),
|
||||
setIndex,
|
||||
width: [],
|
||||
});
|
||||
|
||||
parents.steps.value = [...parents.steps.value, stepItemState];
|
||||
|
||||
onMounted(() => {});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
parents.steps.value = parents.steps.value.filter(
|
||||
(instance: { itemId: any }) => instance.itemId !== currentInstance.uid
|
||||
);
|
||||
});
|
||||
</script>
|
Loading…
x
Reference in New Issue
Block a user