iview/src/components/drawer/drawer.vue
2019-08-27 09:42:40 +08:00

312 lines
No EOL
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div v-transfer-dom :data-transfer="transfer">
<transition name="fade">
<div :class="maskClasses" :style="maskStyle" v-show="visible" v-if="mask" @click="handleMask"></div>
</transition>
<div :class="wrapClasses" @click="handleWrapClick">
<transition :name="'move-' + placement">
<div :class="classes" :style="mainStyles" v-show="visible">
<div :class="contentClasses" ref="content">
<a class="ivu-drawer-close" v-if="closable" @click="close">
<slot name="close">
<Icon type="ios-close"></Icon>
</slot>
</a>
<div :class="[prefixCls + '-header']" v-if="showHead"><slot name="header"><div :class="[prefixCls + '-header-inner']">{{ title }}</div></slot></div>
<div :class="[prefixCls + '-body']" :style="styles"><slot></slot></div>
</div>
<div class="ivu-drawer-drag" :class="{ 'ivu-drawer-drag-left': placement === 'left' }" v-if="draggable" @mousedown="handleTriggerMousedown">
<slot name="trigger">
<div class="ivu-drawer-drag-move-trigger">
<div class="ivu-drawer-drag-move-trigger-point">
<i></i><i></i><i></i><i></i><i></i>
</div>
</div>
</slot>
</div>
</div>
</transition>
</div>
</div>
</template>
<script>
import Icon from '../icon';
import { oneOf, findBrothersComponents, findComponentsUpward } from '../../utils/assist';
import TransferDom from '../../directives/transfer-dom';
import Emitter from '../../mixins/emitter';
import ScrollbarMixins from '../modal/mixins-scrollbar';
import { on, off } from '../../utils/dom';
const prefixCls = 'ivu-drawer';
export default {
name: 'Drawer',
mixins: [ Emitter, ScrollbarMixins ],
components: { Icon },
directives: { TransferDom },
props: {
value: {
type: Boolean,
default: false
},
title: {
type: String
},
width: {
type: [Number, String],
default: 256
},
closable: {
type: Boolean,
default: true
},
maskClosable: {
type: Boolean,
default: true
},
mask: {
type: Boolean,
default: true
},
maskStyle: {
type: Object
},
styles: {
type: Object
},
scrollable: {
type: Boolean,
default: false
},
placement: {
validator (value) {
return oneOf(value, ['left', 'right']);
},
default: 'right'
},
zIndex: {
type: Number,
default: 1000
},
transfer: {
type: Boolean,
default () {
return !this.$IVIEW || this.$IVIEW.transfer === '' ? true : this.$IVIEW.transfer;
}
},
className: {
type: String
},
inner: {
type: Boolean,
default: false
},
// Whether drag and drop is allowed to adjust width
draggable: {
type: Boolean,
default: false
},
beforeClose: Function,
},
data () {
return {
prefixCls: prefixCls,
visible: this.value,
wrapShow: false,
showHead: true,
canMove: false,
dragWidth: this.width,
wrapperWidth: this.width,
wrapperLeft: 0,
minWidth: 256
};
},
computed: {
wrapClasses () {
return [
`${prefixCls}-wrap`,
{
[`${prefixCls}-hidden`]: !this.wrapShow,
[`${this.className}`]: !!this.className,
[`${prefixCls}-no-mask`]: !this.mask,
[`${prefixCls}-wrap-inner`]: this.inner,
[`${prefixCls}-wrap-dragging`]: this.canMove
}
];
},
mainStyles () {
let style = {};
const width = parseInt(this.dragWidth);
const styleWidth = {
width: width <= 100 ? `${width}%` : `${width}px`
};
Object.assign(style, styleWidth);
return style;
},
contentClasses () {
return [
`${prefixCls}-content`,
{
[`${prefixCls}-content-no-mask`]: !this.mask
}
];
},
classes () {
return [
`${prefixCls}`,
`${prefixCls}-${this.placement}`,
{
[`${prefixCls}-no-header`]: !this.showHead,
[`${prefixCls}-inner`]: this.inner
}
];
},
maskClasses () {
return [
`${prefixCls}-mask`,
{
[`${prefixCls}-mask-inner`]: this.inner
}
];
}
},
methods: {
close () {
if (!this.beforeClose) {
return this.handleClose();
}
const before = this.beforeClose();
if (before && before.then) {
before.then(() => {
this.handleClose();
});
} else {
this.handleClose();
}
},
handleClose () {
this.visible = false;
this.$emit('input', false);
this.$emit('on-close');
},
handleMask () {
if (this.maskClosable && this.mask) {
this.close();
}
},
handleWrapClick (event) {
// use indexOf,do not use === ,because ivu-modal-wrap can have other custom className
const className = event.target.getAttribute('class');
if (className && className.indexOf(`${prefixCls}-wrap`) > -1) this.handleMask();
},
handleMousemove (event) {
if (!this.canMove || !this.draggable) return;
// 更新容器宽度和距离左侧页面距离如果是window则距左侧距离为0
this.handleSetWrapperWidth();
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.dragWidth = width;
this.$emit('on-resize-width', parseInt(this.dragWidth));
},
handleSetWrapperWidth () {
const {
width,
left
} = this.$el.getBoundingClientRect();
this.wrapperWidth = width;
this.wrapperLeft = left;
},
handleMouseup () {
if (!this.draggable) return;
this.canMove = false;
},
handleTriggerMousedown () {
this.canMove = true;
// 防止鼠标选中抽屉中文字造成拖动trigger触发浏览器原生拖动行为
window.getSelection().removeAllRanges();
},
},
mounted () {
if (this.visible) {
this.wrapShow = true;
}
let showHead = true;
if (this.$slots.header === undefined && !this.title) {
showHead = false;
}
this.showHead = showHead;
on(document, 'mousemove', this.handleMousemove);
on(document, 'mouseup', this.handleMouseup);
this.handleSetWrapperWidth();
},
beforeDestroy () {
off(document, 'mousemove', this.handleMousemove);
off(document, 'mouseup', this.handleMouseup);
this.removeScrollEffect();
},
watch: {
value (val) {
this.visible = val;
},
visible (val) {
if (val === false) {
this.timer = setTimeout(() => {
this.wrapShow = false;
// #4831 Check if there are any drawers left at the parent level
const brotherDrawers = findBrothersComponents(this, 'Drawer') || [];
const parentDrawers = findComponentsUpward(this, 'Drawer') || [];
const otherDrawers = [].concat(brotherDrawers).concat(parentDrawers);
const isScrollDrawer = otherDrawers.some(item => item.visible && !item.scrollable);
if (!isScrollDrawer) {
this.removeScrollEffect();
}
}, 300);
} else {
if (this.timer) clearTimeout(this.timer);
this.wrapShow = true;
if (!this.scrollable) {
this.addScrollEffect();
}
}
this.broadcast('Table', 'on-visible-change', val);
this.broadcast('Slider', 'on-visible-change', val); // #2852
this.$emit('on-visible-change', val);
},
scrollable (val) {
if (!val) {
this.addScrollEffect();
} else {
this.removeScrollEffect();
}
},
title (val) {
if (this.$slots.header === undefined) {
this.showHead = !!val;
}
},
width (val) {
this.dragWidth = val;
}
}
};
</script>