增加可拖动抽屉组件drag-drawer
This commit is contained in:
parent
e78f77fc76
commit
11209b0ada
|
|
@ -0,0 +1,18 @@
|
||||||
|
<template>
|
||||||
|
<div :class="`${prefix}-move-trigger`">
|
||||||
|
<div :class="`${prefix}-move-trigger-point`">
|
||||||
|
<i></i><i></i><i></i><i></i><i></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Mixin from './mixin'
|
||||||
|
export default {
|
||||||
|
name: 'DragDrawerTrigger',
|
||||||
|
mixins: [Mixin]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
<template>
|
||||||
|
<Drawer ref="drawerWrapper"
|
||||||
|
:value="value"
|
||||||
|
@input="handleInput"
|
||||||
|
:width="width"
|
||||||
|
:class-name="outerClasses"
|
||||||
|
v-bind="$attrs"
|
||||||
|
v-on="$listeners">
|
||||||
|
<!-- 所有插槽内容显示在这里 ↓ -->
|
||||||
|
|
||||||
|
<template v-for="(slots, slotsName) in $slots">
|
||||||
|
<template v-if="slotsName !== 'default'">
|
||||||
|
<render-dom v-for="(render, index) in slots"
|
||||||
|
:key="`b_drawer_${slotsName}_${index}`"
|
||||||
|
:render="() => render"
|
||||||
|
:slot="slotsName">
|
||||||
|
</render-dom>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div :class="`${prefix}-body-wrapper`"
|
||||||
|
:key="`b_drawer_${slotsName}`">
|
||||||
|
<render-dom v-for="(render, index) in slots"
|
||||||
|
:key="`b_drawer_${slotsName}_${index}`"
|
||||||
|
:render="() => render"
|
||||||
|
:slot="slotsName">
|
||||||
|
</render-dom>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<!-- 所有插槽内容显示在这里 ↑ -->
|
||||||
|
<div v-if="draggable"
|
||||||
|
:style="triggerStyle"
|
||||||
|
:class="`${prefix}-trigger-wrapper`"
|
||||||
|
@mousedown="handleTriggerMousedown">
|
||||||
|
<slot name="trigger">
|
||||||
|
<drag-drawer-trigger></drag-drawer-trigger>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
<div v-if="$slots.footer"
|
||||||
|
:class="`${prefix}-footer`">
|
||||||
|
<slot name="footer"></slot>
|
||||||
|
</div>
|
||||||
|
</Drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import RenderDom from '@/libs/render-dom'
|
||||||
|
import DragDrawerTrigger from './drag-drawer-trigger.vue'
|
||||||
|
import Mixin from './mixin'
|
||||||
|
import { on, off } from '@/libs/tools'
|
||||||
|
import './index.less'
|
||||||
|
export default {
|
||||||
|
name: 'BDrawer',
|
||||||
|
components: {
|
||||||
|
RenderDom,
|
||||||
|
DragDrawerTrigger
|
||||||
|
},
|
||||||
|
mixins: [Mixin],
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 256
|
||||||
|
},
|
||||||
|
// 是否可拖动修改宽度
|
||||||
|
draggable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 最小拖动宽度
|
||||||
|
minWidth: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 256
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
canMove: false,
|
||||||
|
wrapperWidth: 0,
|
||||||
|
wrapperLeft: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
outerClasses () {
|
||||||
|
const classesArray = [
|
||||||
|
`${this.prefix}-wrapper`,
|
||||||
|
this.canMove ? 'no-select pointer-events-none' : ''
|
||||||
|
]
|
||||||
|
return classesArray.join(' ')
|
||||||
|
},
|
||||||
|
placement () {
|
||||||
|
return this.$attrs.placement
|
||||||
|
},
|
||||||
|
innerWidth () {
|
||||||
|
const width = this.width
|
||||||
|
return width <= 100 ? (this.wrapperWidth * width) / 100 : width
|
||||||
|
},
|
||||||
|
triggerStyle () {
|
||||||
|
return {
|
||||||
|
[this.placement]: `${this.innerWidth}px`,
|
||||||
|
position: this.$attrs.inner ? 'absolute' : 'fixed'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleInput (status) {
|
||||||
|
this.$emit('input', status)
|
||||||
|
},
|
||||||
|
handleTriggerMousedown (event) {
|
||||||
|
this.canMove = true
|
||||||
|
this.$emit('on-resize-start')
|
||||||
|
// 防止鼠标选中抽屉中文字,造成拖动trigger触发浏览器原生拖动行为
|
||||||
|
window.getSelection().removeAllRanges()
|
||||||
|
},
|
||||||
|
handleMousemove (event) {
|
||||||
|
if (!this.canMove) return
|
||||||
|
// 更新容器宽度和距离左侧页面距离,如果是window则距左侧距离为0
|
||||||
|
this.setWrapperWidth()
|
||||||
|
const left = event.pageX - this.wrapperLeft
|
||||||
|
// 如果抽屉方向为右边,宽度计算需用容器宽度减去left
|
||||||
|
let width = this.placement === 'right' ? this.wrapperWidth - left : left
|
||||||
|
// 限定做小宽度
|
||||||
|
width = Math.max(width, parseFloat(this.minWidth))
|
||||||
|
event.atMin = width === parseFloat(this.minWidth)
|
||||||
|
// 如果当前width不大于100,视为百分比
|
||||||
|
if (width <= 100) width = (width / this.wrapperWidth) * 100
|
||||||
|
this.$emit('update:width', parseInt(width))
|
||||||
|
this.$emit('on-resize', event)
|
||||||
|
},
|
||||||
|
handleMouseup (event) {
|
||||||
|
this.canMove = false
|
||||||
|
this.$emit('on-resize-end')
|
||||||
|
},
|
||||||
|
setWrapperWidth () {
|
||||||
|
const {
|
||||||
|
width,
|
||||||
|
left
|
||||||
|
} = this.$refs.drawerWrapper.$el.getBoundingClientRect()
|
||||||
|
this.wrapperWidth = width
|
||||||
|
this.wrapperLeft = left
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
on(document, 'mousemove', this.handleMousemove)
|
||||||
|
on(document, 'mouseup', this.handleMouseup)
|
||||||
|
this.setWrapperWidth()
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
off(document, 'mousemove', this.handleMousemove)
|
||||||
|
off(document, 'mouseup', this.handleMouseup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
import DragDrawer from './drag-drawer.vue'
|
||||||
|
export default DragDrawer
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
@prefix: ~"drag-drawer";
|
||||||
|
@drag-drawer-trigger-height: 100px;
|
||||||
|
@drag-drawer-trigger-width: 8px;
|
||||||
|
|
||||||
|
.@{prefix}-wrapper{
|
||||||
|
&.no-select{
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
&.pointer-events-none{
|
||||||
|
pointer-events: none;
|
||||||
|
& .@{prefix}-trigger-wrapper{
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ivu-drawer{
|
||||||
|
&-header{
|
||||||
|
overflow: hidden !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
&-body{
|
||||||
|
padding: 0;
|
||||||
|
overflow: visible;
|
||||||
|
position: static;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.@{prefix}-body-wrapper{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.@{prefix}-trigger-wrapper{
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 0;
|
||||||
|
.@{prefix}-move-trigger{
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
height: @drag-drawer-trigger-height;
|
||||||
|
width: @drag-drawer-trigger-width;
|
||||||
|
background: rgb(243, 243, 243);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
border-radius: ~"4px / 6px";
|
||||||
|
box-shadow: 0 0 1px 1px rgba(0, 0, 0, .2);
|
||||||
|
line-height: @drag-drawer-trigger-height;
|
||||||
|
cursor: col-resize;
|
||||||
|
&-point{
|
||||||
|
display: inline-block;
|
||||||
|
width: 50%;
|
||||||
|
transform: translateX(50%);
|
||||||
|
i{
|
||||||
|
display: block;
|
||||||
|
border-bottom: 1px solid rgb(192, 192, 192);
|
||||||
|
padding-bottom: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.@{prefix}-footer{
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
border-top: 1px solid #e8e8e8;
|
||||||
|
padding: 10px 16px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
prefix: 'drag-drawer'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
export default {
|
||||||
|
name: 'RenderDom',
|
||||||
|
functional: true,
|
||||||
|
props: {
|
||||||
|
render: Function
|
||||||
|
},
|
||||||
|
render: (h, ctx) => {
|
||||||
|
return ctx.props.render(h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -39,5 +39,6 @@ export default {
|
||||||
cropper_page: 'Cropper',
|
cropper_page: 'Cropper',
|
||||||
message_page: 'Message Center',
|
message_page: 'Message Center',
|
||||||
tree_table_page: 'Tree Table',
|
tree_table_page: 'Tree Table',
|
||||||
org_tree_page: 'Org Tree'
|
org_tree_page: 'Org Tree',
|
||||||
|
drag_drawer_page: 'Draggable Drawer'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,5 +39,6 @@ export default {
|
||||||
cropper_page: '图片裁剪',
|
cropper_page: '图片裁剪',
|
||||||
message_page: '消息中心',
|
message_page: '消息中心',
|
||||||
tree_table_page: '树状表格',
|
tree_table_page: '树状表格',
|
||||||
org_tree_page: '组织结构树'
|
org_tree_page: '组织结构树',
|
||||||
|
drag_drawer_page: '可拖动抽屉'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,5 +39,6 @@ export default {
|
||||||
cropper_page: '圖片裁剪',
|
cropper_page: '圖片裁剪',
|
||||||
message_page: '消息中心',
|
message_page: '消息中心',
|
||||||
tree_table_page: '樹狀表格',
|
tree_table_page: '樹狀表格',
|
||||||
org_tree_page: '組織結構樹'
|
org_tree_page: '組織結構樹',
|
||||||
|
drag_drawer_page: '可拖動抽屜'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,15 @@ export default [
|
||||||
},
|
},
|
||||||
component: () => import('@/view/components/drag-list/drag-list.vue')
|
component: () => import('@/view/components/drag-list/drag-list.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'drag_drawer_page',
|
||||||
|
name: 'drag_drawer_page',
|
||||||
|
meta: {
|
||||||
|
icon: 'md-list',
|
||||||
|
title: '可拖拽抽屉'
|
||||||
|
},
|
||||||
|
component: () => import('@/view/components/drag-drawer')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'org_tree_page',
|
path: 'org_tree_page',
|
||||||
name: 'org_tree_page',
|
name: 'org_tree_page',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
<template>
|
||||||
|
<Card>
|
||||||
|
<h3 style="padding: 10px 0;">drag-drawer组件是对iview的drawer组件的封装,在支持drawer所有api的基础上,支持可拖动和footer底部插槽</h3>
|
||||||
|
<div style="padding: 10px 0">
|
||||||
|
<b>
|
||||||
|
方向
|
||||||
|
<i-switch v-model="placement">
|
||||||
|
<span slot="open">左</span>
|
||||||
|
<span slot="close">右</span>
|
||||||
|
</i-switch>
|
||||||
|
</b>
|
||||||
|
<b>
|
||||||
|
是否可拖动
|
||||||
|
<i-switch v-model="draggable"></i-switch>
|
||||||
|
</b>
|
||||||
|
<Button @click="showContainerBDrawer = !showContainerBDrawer" type="primary" style="margin-left: 10px">{{ showContainerBDrawer ? '关闭' : '打开' }}容器内抽屉</Button>
|
||||||
|
<Button @click="showWindowBDrawer = true" type="primary" style="margin-left: 10px">打开全屏抽屉</Button>
|
||||||
|
</div>
|
||||||
|
<div class="drag-drawer-inner-box">
|
||||||
|
<drag-drawer v-model="showContainerBDrawer"
|
||||||
|
:width.sync="width2"
|
||||||
|
min-width="30px"
|
||||||
|
:inner="true"
|
||||||
|
:transfer="false"
|
||||||
|
:placement="placementComputed"
|
||||||
|
:draggable="draggable"
|
||||||
|
@on-resize="handleResize"
|
||||||
|
:scrollable="true">
|
||||||
|
<div slot="header">
|
||||||
|
<Icon type="md-aperture" :size="18"></Icon>
|
||||||
|
<b>这是标题</b>
|
||||||
|
</div>
|
||||||
|
<p v-for="n in 200" :key="n">{{ n }}</p>
|
||||||
|
<div slot="footer">
|
||||||
|
<p>123123</p>
|
||||||
|
<p>21312</p>
|
||||||
|
</div>
|
||||||
|
</drag-drawer>
|
||||||
|
</div>
|
||||||
|
<drag-drawer v-model="showWindowBDrawer"
|
||||||
|
:width.sync="width1"
|
||||||
|
:min-width="300"
|
||||||
|
:placement="placementComputed"
|
||||||
|
:draggable="draggable"
|
||||||
|
:scrollable="true">
|
||||||
|
<div slot="header">
|
||||||
|
<Icon type="md-aperture" :size="18"></Icon>
|
||||||
|
<b>这是标题</b>
|
||||||
|
</div>
|
||||||
|
<Button @click="showBDrawer3 = true">显示多层</Button>
|
||||||
|
<p v-for="n in 200" :key="n">{{ n }}</p>
|
||||||
|
</drag-drawer>
|
||||||
|
</Card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import DragDrawer from '_c/drag-drawer'
|
||||||
|
export default {
|
||||||
|
name: 'drag_drawer_page',
|
||||||
|
components: {
|
||||||
|
DragDrawer
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
showWindowBDrawer: false,
|
||||||
|
showContainerBDrawer: false,
|
||||||
|
showBDrawer3: false,
|
||||||
|
width1: 300,
|
||||||
|
width2: 200,
|
||||||
|
placement: false,
|
||||||
|
draggable: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
placementComputed () {
|
||||||
|
return this.placement ? 'left' : 'right'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleResize (event) {
|
||||||
|
const { atMin } = event
|
||||||
|
/* eslint-disable */
|
||||||
|
console.log(atMin);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.drag-drawer-inner-box{
|
||||||
|
position: relative;
|
||||||
|
width: 500px;
|
||||||
|
height: 400px;
|
||||||
|
background: pink;
|
||||||
|
border: 1px solid pink;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue