- split-drag-layout文件夹下 拖拽 index.vue
<template>
<div :class="['split-pane', props.isVertical ? 'vertical-pane' : 'level-pane']" :ref="`split${props.isVertical ? 'Vertical' : 'Level'}Ref`">
<div :class="[props.isVertical ? 'left-pane' : 'top-pane']" ref="topOrLeftRef">
<slot name="topOrleft" />
</div>
<div class="line-box">
<div :class="['split-line', props.isVertical ? 'vertical-line' : 'level-line']" ref="splitLineRef" @mousedown="onMouseDown($event)">
<div class="vertical-line-inner" />
</div>
<div v-if="!states.isLeft" alt="图标" class="icon-size icon-left" @click="clickToLeft" />
<div v-else alt="图标" class="icon-size icon-right" @click="clickToRight" />
</div>
<div :class="[props.isVertical ? 'right-pane' : 'bottom-pane']" ref="rightBottomRef">
<slot name="bottomOrRight" />
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive } from 'vue'
import { getProps } from './index'
const props = defineProps(getProps())
const states = reactive({
isLeft: false,
})
// 分割线
const splitLineRef = ref()
// 左侧
const topOrLeftRef = ref()
// 下侧
const rightBottomRef = ref()
// 鼠标拖动事件
const onMouseDown = e => {
tableMouse(e, props.isVertical, topOrLeftRef.value, rightBottomRef.value, splitLineRef.value)
}
const tableMouse = (event, isVertical: Boolean, topOrLeftDom: any, bottomOrRightDom: any, gDom: any) => {
event = event || window.event
//设置moveBox捕获所有鼠标按下的事件
event.target.setCapture && event.target.setCapture()
//记录鼠标相对于盒子的位移距离
const offsety = event.clientY
const offsetx = event.clientX
const topHOrLeftW = isVertical ? topOrLeftDom.offsetWidth : topOrLeftDom.offsetHeight
const bottomHOrRightW = isVertical ? bottomOrRightDom.offsetWidth : bottomOrRightDom.offsetHeight
document.onmousemove = function (event: any) {
event = event || window.event
//移动后的鼠标坐标
const y = event.clientY
const x = event.clientX
const num = isVertical ? x - offsetx : y - offsety
if (isVertical) {
topOrLeftDom.style.width = `${topHOrLeftW + num < 24 ? 24 : topHOrLeftW + num}px`
bottomOrRightDom.style.width = `${bottomHOrRightW - num < 24 ? 24 : bottomHOrRightW - num}px`
} else {
topOrLeftDom.style.height = `${topHOrLeftW + num}px`
bottomOrRightDom.style.height = `${bottomHOrRightW - num}px`
}
}
document.onmouseup = function () {
document.onmousemove = null
document.onmouseup = null
//点击 - 移动 - 松开 鼠标松开时,取消对事件的捕获
gDom.releaseCapture && gDom.releaseCapture()
states.isLeft = topOrLeftDom.style.width == '24px'
}
}
// 点击向左
const clickToLeft = () => {
topOrLeftRef.value.style.width = '24px'
states.isLeft = true
}
// 点击向右
const clickToRight = () => {
topOrLeftRef.value.style.width = '340px'
states.isLeft = false
}
</script>
<style scoped lang="scss">
@use './index.scss';
</style>
2.项目使用方法
import splitDragLayout from '@/usage/components/split-drag-layout/index'
<template>
<splitDragLayout>
<template #topOrleft>
左侧数据
</template>
<template #bottomOrRight>
右侧数据
</template>
</splitDragLayout>
</template>
3.getProps()方法
import { PropType } from 'vue'
export function getProps() {
return {
/** 高度 */
height: {
type: String as PropType<string>,
default: '100%',
},
/** 标题 */
title: {
type: String as PropType<string>,
default: '',
},
/** 是否显示 条件栏 */
isTerm: {
type: Boolean as PropType<boolean>,
default: false,
},
termPlaceholder: {
type: String as PropType<string>,
default: '请输入',
},
/** 宽度 */
width: {
type: String as PropType<string>,
default: 'auto',
},
/** 边距-上 */
top: {
type: String as PropType<string>,
default: 'var(--ever-gap-s6)',
},
/** 边距-右 */
right: {
type: String as PropType<string>,
default: 'var(--ever-gap-s6)',
},
/** 边距-下 */
bottom: {
type: String as PropType<string>,
default: 'var(--ever-gap-s6)',
},
/** 边距-左 */
left: {
type: String as PropType<string>,
default: 'var(--ever-gap-s6)',
},
}
}
4.index.scss
.split-pane {
display: flex;
height: 100%;
width: 100%;
}
.vertical-pane {
flex-direction: row;
}
.level-pane {
flex-direction: column;
}
.left-pane {
width: 340px;
overflow-x: hidden;
}
.right-pane {
flex: 1;
}
.top-pane {
height: calc(78% - 8px);
}
.bottom-pane {
height: calc(38% - 8px);
}
.vertical-line {
width: 1px;
height: 100%;
position: relative;
}
.vertical-line-inner {
position: absolute;
width: 9px;
background-color: transparent;
height: 100%;
cursor: ew-resize;
left: -4px;
}
.level-line {
cursor: ew-resize;
border-bottom: 1px solid #dce4f2;
height: 4px;
background-color: #0000;
}
.split-line {
background-color: #dce4f2;
}
.split-line:hover {
background-color: #c2d3f2;
}
.vertical-line:hover {
cursor: ew-resize;
}
// .level-line:hover {
// cursor: row-resize;
// }
.line-box {
height: 100%;
position: relative;
}
.icon-size {
width: 28px;
height: 28px;
max-width: inherit;
position: absolute;
top: 50%;
left: -14px;
cursor: pointer;
z-index: 2;
}
.icon-left {
background: url('@/assets/fold-left.svg') 60%;
}
.icon-left:hover {
background: url('@/assets/fold-left-hover.svg') 60%;
}
.icon-right {
background: url('@/assets/fold-right.svg') 60%;
}
.icon-right:hover {
background: url('@/assets/fold-right-hover.svg') 60%;
}
注:图标文件自己找资源替换哦
网友评论