add split-pane
This commit is contained in:
parent
525e9a2205
commit
cdc55dc39b
|
|
@ -152,14 +152,14 @@ export const appRouter = [
|
|||
name: 'count-to',
|
||||
title: '数字渐变',
|
||||
component: resolve => { require(['@/views/my-components/count-to/count-to.vue'], resolve); }
|
||||
},
|
||||
{
|
||||
path: 'split-pane-page',
|
||||
icon: 'ios-pause',
|
||||
name: 'split-pane-page',
|
||||
title: 'split-pane',
|
||||
component: resolve => { require(['@/views/my-components/split-pane/split-pane-page.vue'], resolve); }
|
||||
}
|
||||
// {
|
||||
// path: 'clipboard-page',
|
||||
// icon: 'clipboard',
|
||||
// name: 'clipboard-page',
|
||||
// title: '一键复制',
|
||||
// component: resolve => { require(['@/views/my-components/clipboard/clipboard.vue'], resolve); }
|
||||
// }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
<template>
|
||||
<div>
|
||||
<Card :padding="0">
|
||||
<div class="split-pane-con">
|
||||
<split-pane :style="{height: '100%'}" :min="30" :max="80" @on-trigger-moving="handleMoving" direction="horizontal" v-model="triggerOffset">
|
||||
<div slot="left" style="height: 100%;">
|
||||
<split-pane :style="{height: '100%'}" direction="vertical" v-model="triggerOffsetV">
|
||||
<div class="introduce-left-con" slot="top" style="background: #EDE3A0;height: 100%;padding: 30px;">
|
||||
<h4>- 该组件可以拖动修改左右尺寸,还可以绑定v-model来设置,如设置v-model="40"即左侧40%,右侧60%</h4>
|
||||
<h4>- 可设置最小和最大距离,如:min="80"即向右拖动到80%处就不能再拖动</h4>
|
||||
<h4>- 可绑定事件@on-trigger-moving,回调函数的返回值是鼠标事件对象,同时该对象还包括两个我们自定义的变量,即atMax和atMin,即此时是否是在最大或最小距离处,类型是Boolean。来拖动右边的trigger看看吧。</h4>
|
||||
<h4 style="margin-bottom: 10px;">- 可使用slot="trigger"自定义拖动触发器,但有三个注意点:</h4>
|
||||
<h5>-- 样式需要设置position: absolute;</h5>
|
||||
<h5>-- 需要给trigger绑定mousedown事件,绑定的方法调用this.$refs.pane.handleMousedow(e),e为mousedown事件的事件对象</h5>
|
||||
<h5>-- 给trigger添加:style="{width: offset + '%'}",这里的offset是通过v-model给split-pane组件绑定的值</h5>
|
||||
<h4>- 其他api请看源码</h4>
|
||||
</div>
|
||||
<div slot="bottom" style="background: #A2EDB6;height: 100%;">
|
||||
<split-pane ref="pane" :style="{height: '100%'}" direction="horizontal" v-model="triggerOffsetMin">
|
||||
<div slot="left" style="background: #EDACE2;height: 100%;"></div>
|
||||
<div slot="trigger"
|
||||
:style="{left: triggerOffsetMin + '%'}"
|
||||
@mousedown="handleMousedown"
|
||||
class="custom-trigger"></div>
|
||||
<div slot="right" style="background: #A2EDB6;height: 100%;"></div>
|
||||
</split-pane>
|
||||
</div>
|
||||
</split-pane>
|
||||
</div>
|
||||
<div class="split-pane-right-con" slot="right" style="background: #8FB5ED;height: 100%;">
|
||||
<p>是否是在最小距离处: {{ atMin }}</p>
|
||||
<p>是否是在最大距离处: {{ atMax }}</p>
|
||||
</div>
|
||||
</split-pane>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import splitPane from './split-pane';
|
||||
export default {
|
||||
name: 'split-pane-page',
|
||||
components: {
|
||||
splitPane
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
triggerOffset: 50,
|
||||
triggerOffsetV: 70,
|
||||
triggerOffsetMin: 40,
|
||||
atMax: false,
|
||||
atMin: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleMousedown (e) {
|
||||
this.$refs.pane.handleMousedown(e);
|
||||
},
|
||||
handleMoving (e) {
|
||||
this.atMax = e.atMax;
|
||||
this.atMin = e.atMin;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.split-pane-con{
|
||||
width: 100%;
|
||||
height: 89vh;
|
||||
}
|
||||
.custom-trigger{
|
||||
position: absolute;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
box-shadow: 2px 2px 5px 2px rgba(0, 0, 0, .1) , 2px 2px 10px 2px rgba(0, 0, 0, .2) inset;
|
||||
border: 1px solid #c3c3c3;
|
||||
cursor: pointer;
|
||||
}
|
||||
.introduce-left-con h4{
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.introduce-left-con h5{
|
||||
margin-bottom: 10px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
.split-pane-right-con{
|
||||
padding: 30px;
|
||||
}
|
||||
.split-pane-right-con p{
|
||||
font-size: 26px;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import splitPane from './split-pane.vue';
|
||||
|
||||
export default splitPane;
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
@prefix: ~"split-pane";
|
||||
@container: ~"@{prefix}-container";
|
||||
@trigger: ~"@{prefix}-trigger";
|
||||
|
||||
.@{prefix}{
|
||||
position: relative;
|
||||
&-container{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-horizontal{
|
||||
& > div > .@{trigger}{
|
||||
transform: translateX(-50%);
|
||||
cursor: col-resize;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
margin: 0 1px;
|
||||
}
|
||||
}
|
||||
|
||||
&-vertical{
|
||||
& > div > .@{trigger}{
|
||||
transform: translateY(-50%);
|
||||
cursor: row-resize;
|
||||
height: 2px;
|
||||
width: 100%;
|
||||
margin: 1px 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-trigger{
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
background: #BDBDBD;
|
||||
}
|
||||
|
||||
&-left-area{
|
||||
height: 100%;
|
||||
float: left;
|
||||
z-index: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&-right-area{
|
||||
height: 100%;
|
||||
float: left;
|
||||
z-index: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&-top-area{
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&-bottom-area{
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
<style lang="less">
|
||||
@import './split-pane.less';
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="wraperClasses"
|
||||
ref="wraper"
|
||||
@mouseup="handleMouseup"
|
||||
@mousemove="handleMousemove"
|
||||
@mouseleave="handleMouseout">
|
||||
<div v-if="direction === 'horizontal'" :class="`${prefix}-container`">
|
||||
<div :class="`${prefix}-left-area`" :style="{width: leftSize}">
|
||||
<slot name="left"></slot>
|
||||
</div>
|
||||
<slot name="trigger">
|
||||
<div
|
||||
:class="`${prefix}-trigger`"
|
||||
ref="trigger"
|
||||
:style="{left: `${triggerOffset}%`}"
|
||||
@mousedown="handleMousedown"
|
||||
unselectable="on">
|
||||
</div>
|
||||
</slot>
|
||||
<div :class="`${prefix}-right-area`" :style="{width: rightSize}">
|
||||
<slot name="right"></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else :class="`${prefix}-container`">
|
||||
<div :class="`${prefix}-top-area`" :style="{height: leftSize}">
|
||||
<slot name="top"></slot>
|
||||
</div>
|
||||
<slot name="trigger">
|
||||
<div
|
||||
:class="`${prefix}-trigger`"
|
||||
ref="trigger"
|
||||
:style="{top: `${triggerOffset}%`}"
|
||||
@mousedown="handleMousedown"
|
||||
unselectable="on">
|
||||
</div>
|
||||
</slot>
|
||||
<div :class="`${prefix}-bottom-area`" :style="{height: rightSize}">
|
||||
<slot name="bottom"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const oneOf = function (ele, targetArr) {
|
||||
if (targetArr.indexOf(ele) >= 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
export default {
|
||||
name: 'splitPane',
|
||||
props: {
|
||||
value: {
|
||||
type: Number,
|
||||
default: 50
|
||||
},
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'horizontal',
|
||||
validator (val) {
|
||||
return oneOf(val, ['vertical', 'horizontal']);
|
||||
}
|
||||
},
|
||||
min: {
|
||||
type: [Number, String],
|
||||
default: 3
|
||||
},
|
||||
max: {
|
||||
type: [Number, String],
|
||||
default: 97
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
prefix: 'split-pane',
|
||||
canMove: false,
|
||||
triggerOffset: 50,
|
||||
triggerOldOffset: 50,
|
||||
offset: {},
|
||||
atMin: false,
|
||||
atMax: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
wraperClasses () {
|
||||
return [
|
||||
this.prefix,
|
||||
this.direction === 'vertical' ? `${this.prefix}-vertical` : `${this.prefix}-horizontal`
|
||||
];
|
||||
},
|
||||
leftSize () {
|
||||
return `${this.triggerOffset}%`;
|
||||
},
|
||||
rightSize () {
|
||||
return `${100 - this.triggerOffset}%`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleMouseup () {
|
||||
this.canMove = false;
|
||||
},
|
||||
handleMousedown (e) {
|
||||
this.canMove = true;
|
||||
this.triggerOldOffset = this.triggerOffset;
|
||||
this.offset = {
|
||||
x: e.pageX,
|
||||
y: e.pageY
|
||||
};
|
||||
e.preventDefault();
|
||||
},
|
||||
handleMouseout () {
|
||||
this.canMove = false;
|
||||
},
|
||||
handleMousemove (e) {
|
||||
if (this.canMove) {
|
||||
let offset;
|
||||
if (this.direction === 'horizontal') {
|
||||
offset = this.triggerOldOffset + Math.floor(((e.clientX - this.offset.x) / this.$refs.wraper.offsetWidth) * 10000) / 100;
|
||||
} else {
|
||||
offset = this.triggerOldOffset + Math.floor(((e.clientY - this.offset.y) / this.$refs.wraper.offsetHeight) * 10000) / 100;
|
||||
}
|
||||
if (offset <= this.min) {
|
||||
this.triggerOffset = Math.max(offset, this.min);
|
||||
} else {
|
||||
this.triggerOffset = Math.min(offset, this.max);
|
||||
}
|
||||
this.atMin = this.triggerOffset === this.min;
|
||||
this.atMax = this.triggerOffset === this.max;
|
||||
e.atMin = this.atMin;
|
||||
e.atMax = this.atMax;
|
||||
this.$emit('input', offset);
|
||||
this.$emit('on-trigger-moving', e);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (this.value !== undefined) {
|
||||
this.triggerOffset = this.value;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
Loading…
Reference in New Issue