Tooltip/Popover: adjust the element to body, fixed #296 (#300)

* Tooltip/Popover: adjust the element to body, fixed #296

* Popover: fix destroy popover

* Refactor vue-popper, #296

* Fix datepicker style

* Poppover: remove settimeout

* Select: fix click outside

* Fix popper zIndex
pull/362/head
cinwell.li 2016-10-12 17:41:49 +08:00 committed by GitHub
parent 457cfe4af0
commit de696c78bc
22 changed files with 232 additions and 236 deletions

View File

@ -119,6 +119,7 @@
<span class="demonstration">带快捷选项</span> <span class="demonstration">带快捷选项</span>
<el-date-picker <el-date-picker
v-model="value2" v-model="value2"
align="right"
type="date" type="date"
placeholder="选择日期" placeholder="选择日期"
:picker-options="pickerOptions1"> :picker-options="pickerOptions1">
@ -193,6 +194,7 @@
<span class="demonstration"></span> <span class="demonstration"></span>
<el-date-picker <el-date-picker
v-model="value5" v-model="value5"
align="right"
type="year" type="year"
placeholder="选择年"> placeholder="选择年">
</el-date-picker> </el-date-picker>

View File

@ -16,22 +16,22 @@
.demo-box.demo-slider .source { .demo-box.demo-slider .source {
padding: 0; padding: 0;
} }
.demo-box.demo-slider .block { .demo-box.demo-slider .block {
padding: 30px 24px; padding: 30px 24px;
overflow: hidden; overflow: hidden;
border-bottom: solid 1px #EFF2F6; border-bottom: solid 1px #EFF2F6;
&:last-child { &:last-child {
border-bottom: none; border-bottom: none;
} }
} }
.demo-box.demo-slider .demonstration { .demo-box.demo-slider .demonstration {
font-size: 14px; font-size: 14px;
color: #8492a6; color: #8492a6;
line-height: 44px; line-height: 44px;
} }
.demo-box.demo-slider .demonstration + .el-slider { .demo-box.demo-slider .demonstration + .el-slider {
float: right; float: right;
width: 70%; width: 70%;
@ -52,7 +52,7 @@
<template> <template>
<div class="block"> <div class="block">
<span class="demonstration">默认</span> <span class="demonstration">默认</span>
<el-slider v-model="value1"></el-slider> <el-slider v-model="value1"></el-slider>
</div> </div>
<div class="block"> <div class="block">
<span class="demonstration">自定义初始值</span> <span class="demonstration">自定义初始值</span>
@ -85,7 +85,7 @@
<el-slider <el-slider
v-model="value3" v-model="value3"
:step="10"> :step="10">
</el-slider> </el-slider>
</div> </div>
<div class="block"> <div class="block">
<span class="demonstration">显示间断点</span> <span class="demonstration">显示间断点</span>
@ -121,7 +121,7 @@
<el-slider <el-slider
v-model="value5" v-model="value5"
show-input> show-input>
</el-slider> </el-slider>
</div> </div>
</template> </template>

View File

@ -74,7 +74,7 @@
"vue": "^2.0.2", "vue": "^2.0.2",
"vue-loader": "^9.5.1", "vue-loader": "^9.5.1",
"vue-markdown-loader": "^0.5.1", "vue-markdown-loader": "^0.5.1",
"vue-popup": "^0.2.7", "vue-popup": "^0.2.8",
"vue-router": "^2.0.0", "vue-router": "^2.0.0",
"webpack": "^1.13.2", "webpack": "^1.13.2",
"webpack-dev-server": "^1.15.1", "webpack-dev-server": "^1.15.1",

View File

@ -3,7 +3,15 @@
@component-namespace el { @component-namespace el {
@b date-picker { @b date-picker {
min-width: 300px; min-width: 254px;
&.has-sidebar {
min-width: 368px;
}
&.has-time {
min-width: 324px;
}
.el-picker-panel__content { .el-picker-panel__content {
min-width: 224px; min-width: 224px;

View File

@ -9,6 +9,7 @@
border-radius: 2px; border-radius: 2px;
line-height: 20px; line-height: 20px;
margin: 5px 0; margin: 5px 0;
min-width: 513px;
@e body, body-wrapper { @e body, body-wrapper {
&::after { &::after {

View File

@ -1,8 +1,13 @@
<template> <template>
<transition name="md-fade-bottom"> <transition name="md-fade-bottom" @after-leave="$emit('dodestroy')">
<div <div
v-show="visible" v-show="visible"
class="el-picker-panel el-date-range-picker"> :style="{ width: width + 'px' }"
class="el-picker-panel el-date-range-picker"
:class="{
'has-sidebar': $slots.sidebar || shortcuts,
'has-time': showTime
}">
<div class="el-picker-panel__body-wrapper"> <div class="el-picker-panel__body-wrapper">
<slot name="sidebar" class="el-picker-panel__sidebar"></slot> <slot name="sidebar" class="el-picker-panel__sidebar"></slot>
<div class="el-picker-panel__sidebar" v-if="shortcuts"> <div class="el-picker-panel__sidebar" v-if="shortcuts">
@ -269,7 +274,8 @@
visible: '', visible: '',
disabledDate: '', disabledDate: '',
leftTimePickerVisible: false, leftTimePickerVisible: false,
rightTimePickerVisible: false rightTimePickerVisible: false,
width: 0
}; };
}, },

View File

@ -1,8 +1,13 @@
<template> <template>
<transition name="md-fade-bottom"> <transition name="md-fade-bottom" @after-leave="$emit('dodestroy')">
<div <div
v-show="visible" v-show="visible"
class="el-picker-panel el-date-picker"> :style="{ width: width + 'px' }"
class="el-picker-panel el-date-picker"
:class="{
'has-sidebar': $slots.sidebar || shortcuts,
'has-time': showTime
}">
<div class="el-picker-panel__body-wrapper"> <div class="el-picker-panel__body-wrapper">
<slot name="sidebar" class="el-picker-panel__sidebar"></slot> <slot name="sidebar" class="el-picker-panel__sidebar"></slot>
<div class="el-picker-panel__sidebar" v-if="shortcuts"> <div class="el-picker-panel__sidebar" v-if="shortcuts">
@ -339,7 +344,8 @@
year: null, year: null,
month: null, month: null,
week: null, week: null,
timePickerVisible: false timePickerVisible: false,
width: 0
}; };
}, },

View File

@ -1,7 +1,8 @@
<template> <template>
<transition name="md-fade-bottom"> <transition name="md-fade-bottom" @after-leave="$emit('dodestroy')">
<div <div
v-show="visible" v-show="visible"
:style="{ width: width + 'px' }"
class="el-time-range-picker el-picker-panel"> class="el-time-range-picker el-picker-panel">
<div class="el-time-range-picker__content"> <div class="el-time-range-picker__content">
<div class="el-time-range-picker__cell"> <div class="el-time-range-picker__cell">
@ -91,7 +92,8 @@
minMinutes: minTime.getMinutes(), minMinutes: minTime.getMinutes(),
minSeconds: minTime.getSeconds(), minSeconds: minTime.getSeconds(),
format: 'HH:mm:ss', format: 'HH:mm:ss',
visible: false visible: false,
width: 0
}; };
}, },

View File

@ -1,7 +1,8 @@
<template> <template>
<transition name="md-fade-bottom"> <transition name="md-fade-bottom" @after-leave="$emit('dodestroy')">
<div <div
v-show="visible" v-show="visible"
:style="{ width: width + 'px' }"
class="el-picker-panel time-select"> class="el-picker-panel time-select">
<div class="el-picker-panel__content"> <div class="el-picker-panel__content">
<div class="time-select-item" <div class="time-select-item"
@ -91,7 +92,8 @@
step: '00:30', step: '00:30',
value: '', value: '',
visible: false, visible: false,
minTime: '' minTime: '',
width: 0
}; };
}, },

View File

@ -1,7 +1,8 @@
<template> <template>
<transition name="md-fade-bottom"> <transition name="md-fade-bottom" @after-leave="$emit('dodestroy')">
<div <div
v-show="currentVisible" v-show="currentVisible"
:style="{width: width + 'px'}"
class="el-time-panel"> class="el-time-panel">
<div class="el-time-panel__content"> <div class="el-time-panel__content">
<time-spinner <time-spinner
@ -81,7 +82,8 @@
seconds: 0, seconds: 0,
selectableRange: [], selectableRange: [],
currentDate: this.$options.defaultValue || this.date, currentDate: this.$options.defaultValue || this.date,
currentVisible: this.visible currentVisible: this.visible,
width: 0
}; };
}, },

View File

@ -33,9 +33,20 @@
import Vue from 'vue'; import Vue from 'vue';
import Clickoutside from 'main/utils/clickoutside'; import Clickoutside from 'main/utils/clickoutside';
import { merge, formatDate, parseDate, getWeekNumber } from './util'; import { merge, formatDate, parseDate, getWeekNumber } from './util';
import Popper from 'main/utils/popper'; import Popper from 'main/utils/vue-popper';
import emitter from 'main/mixins/emitter'; import emitter from 'main/mixins/emitter';
const newPopper = {
props: {
appendToBody: Popper.props.appendToBody,
offset: Popper.props.offset,
boundariesPadding: Popper.props.boundariesPadding
},
methods: Popper.methods,
data: Popper.data,
beforeDestroy: Popper.beforeDestroy
};
const FUNCTION_KEYS = [13, 16, 17, 18, 19, 20, 27, 33, 34, 35, 36, 37, 38, 39, 40]; const FUNCTION_KEYS = [13, 16, 17, 18, 19, 20, 27, 33, 34, 35, 36, 37, 38, 39, 40];
const RANGE_SEPARATOR = ' - '; const RANGE_SEPARATOR = ' - ';
const DEFAULT_FORMATS = { const DEFAULT_FORMATS = {
@ -184,7 +195,7 @@ const PLACEMENT_MAP = {
}; };
export default { export default {
mixins: [emitter], mixins: [emitter, newPopper],
props: { props: {
format: String, format: String,
@ -277,6 +288,15 @@ export default {
} }
}, },
created() {
// vue-popper
this.options = {
boundariesPadding: 0,
gpuAcceleration: false
};
this.placement = PLACEMENT_MAP[this.align] || PLACEMENT_MAP.left;
},
methods: { methods: {
handleClose() { handleClose() {
this.pickerVisible = false; this.pickerVisible = false;
@ -382,16 +402,6 @@ export default {
!this.pickerVisible ? this.showPicker() : this.hidePicker(); !this.pickerVisible ? this.showPicker() : this.hidePicker();
}, },
destroyPopper() {
if (this.popper) {
this.resetTransformOrigin(this.popper);
setTimeout(() => {
this.popper && this.popper.destroy();
this.popper = null;
}, 300);
}
},
hidePicker() { hidePicker() {
if (this.picker) { if (this.picker) {
this.picker.resetView && this.picker.resetView(); this.picker.resetView && this.picker.resetView();
@ -406,6 +416,8 @@ export default {
this.picker = new Vue(merge({ this.picker = new Vue(merge({
el: document.createElement('div') el: document.createElement('div')
}, this.panel)); }, this.panel));
this.popperElm = this.picker.$el;
this.picker.width = this.$refs.reference.getBoundingClientRect().width;
this.picker.showTime = this.type === 'datetime' || this.type === 'datetimerange'; this.picker.showTime = this.type === 'datetime' || this.type === 'datetimerange';
this.picker.selectionMode = this.selectionMode; this.picker.selectionMode = this.selectionMode;
if (this.format) { if (this.format) {
@ -441,6 +453,7 @@ export default {
this.pickerVisible = this.picker.visible = true; this.pickerVisible = this.picker.visible = true;
this.picker.resetView && this.picker.resetView(); this.picker.resetView && this.picker.resetView();
this.picker.$on('dodestroy', this.doDestroy);
this.picker.$on('pick', (date, visible = false) => { this.picker.$on('pick', (date, visible = false) => {
this.$emit('input', date); this.$emit('input', date);
@ -460,20 +473,7 @@ export default {
this.pickerVisible = this.picker.visible = true; this.pickerVisible = this.picker.visible = true;
} }
this.$nextTick(() => { this.updatePopper();
if (this.popper) return;
this.popper = new Popper(this.$refs.reference, this.picker.$el, {
gpuAcceleration: false,
placement: PLACEMENT_MAP[this.align] || PLACEMENT_MAP.left,
boundariesPadding: 0,
forceAbsolute: true
});
this.popper.onCreate(popper => {
this.resetTransformOrigin(popper);
});
});
if (this.value instanceof Date) { if (this.value instanceof Date) {
this.picker.date = new Date(this.value.getTime()); this.picker.date = new Date(this.value.getTime());
@ -488,18 +488,7 @@ export default {
} }
this.picker.ajustScrollTop && this.picker.ajustScrollTop(); this.picker.ajustScrollTop && this.picker.ajustScrollTop();
}); });
},
resetTransformOrigin(popper) {
let placementMap = { top: 'bottom', bottom: 'top' };
let placement = popper._popper.getAttribute('x-placement').split('-')[0];
let origin = placementMap[placement];
popper._popper.style.transformOrigin = `center ${ origin }`;
} }
},
beforeDestroy() {
this.popper && this.popper.destroy();
} }
}; };
</script> </script>

View File

@ -57,54 +57,55 @@ export default {
}, },
mounted() { mounted() {
setTimeout(() => { let _timer;
let _timer; const reference = this.reference || this.$refs.reference || this.$slots.reference[0].elm;
const reference = this.reference || this.$refs.reference || this.$slots.reference[0].elm; const popper = this.popper || this.$refs.popper;
this.$nextTick(() => { this.$nextTick(() => {
if (this.trigger === 'click') { if (this.trigger === 'click') {
on(reference, 'click', () => { this.showPopper = !this.showPopper; }); on(reference, 'click', () => { this.showPopper = !this.showPopper; });
on(document, 'click', (e) => { on(document, 'click', (e) => {
if (!this.$el || if (!this.$el ||
!reference || !reference ||
this.$el.contains(e.target) || this.$el.contains(e.target) ||
reference.contains(e.target)) return; reference.contains(e.target) ||
!popper ||
popper.contains(e.target)) return;
this.showPopper = false;
});
} else if (this.trigger === 'hover') {
on(reference, 'mouseenter', () => {
this.showPopper = true;
clearTimeout(_timer);
});
on(reference, 'mouseleave', () => {
_timer = setTimeout(() => {
this.showPopper = false; this.showPopper = false;
}); }, 200);
} else if (this.trigger === 'hover') { });
on(reference, 'mouseenter', () => { } else {
this.showPopper = true; if ([].slice.call(reference.children).length) {
clearTimeout(_timer); const children = reference.childNodes;
});
on(reference, 'mouseleave', () => {
_timer = setTimeout(() => {
this.showPopper = false;
}, 200);
});
} else {
if ([].slice.call(reference.children).length) {
const children = reference.childNodes;
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
if (children[i].nodeName === 'INPUT') { if (children[i].nodeName === 'INPUT') {
on(children[i], 'focus', () => { this.showPopper = true; }); on(children[i], 'focus', () => { this.showPopper = true; });
on(children[i], 'blur', () => { this.showPopper = false; }); on(children[i], 'blur', () => { this.showPopper = false; });
break; break;
}
} }
} else if (
reference.nodeName === 'INPUT' ||
reference.nodeName === 'TEXTAREA'
) {
on(reference, 'focus', () => { this.showPopper = true; });
on(reference, 'blur', () => { this.showPopper = false; });
} else {
on(reference, 'mousedown', () => { this.showPopper = true; });
on(reference, 'mouseup', () => { this.showPopper = false; });
} }
} else if (
reference.nodeName === 'INPUT' ||
reference.nodeName === 'TEXTAREA'
) {
on(reference, 'focus', () => { this.showPopper = true; });
on(reference, 'blur', () => { this.showPopper = false; });
} else {
on(reference, 'mousedown', () => { this.showPopper = true; });
on(reference, 'mouseup', () => { this.showPopper = false; });
} }
}); }
}, 100); });
}, },
destroyed() { destroyed() {

View File

@ -1,71 +1,58 @@
<template> <template>
<div class="el-select-dropdown"> <div
class="el-select-dropdown"
:class="{ 'is-multiple': $parent.multiple }"
:style="{ minWidth: minWidth }">
<slot></slot> <slot></slot>
</div> </div>
</template> </template>
<script type="text/babel"> <script type="text/babel">
import Popper from 'main/utils/popper'; import Popper from 'main/utils/vue-popper';
export default { export default {
name: 'el-select-dropdown', name: 'el-select-dropdown',
componentName: 'select-dropdown', componentName: 'select-dropdown',
mixins: [Popper],
props: {
placement: {
default: 'bottom-start'
},
boundariesPadding: {
default: 0
},
options: {
default() {
return {
forceAbsolute: true,
gpuAcceleration: false
};
}
}
},
data() { data() {
return { return {
popper: null minWidth: ''
}; };
}, },
created() { watch: {
this.$on('updatePopper', this.updatePopper); '$parent.inputWidth'() {
this.$on('destroyPopper', this.destroyPopper); this.minWidth = this.$parent.$el.getBoundingClientRect().width + 'px';
},
methods: {
updatePopper() {
if (this.popper) {
this.$nextTick(() => {
this.popper.update();
});
} else {
this.$nextTick(() => {
this.popper = new Popper(this.$parent.$refs.reference.$el, this.$el, {
gpuAcceleration: false,
placement: 'bottom-start',
boundariesPadding: 0,
forceAbsolute: true
});
this.popper.onCreate(popper => {
this.resetTransformOrigin(popper);
});
});
}
},
destroyPopper() {
if (this.popper) {
this.resetTransformOrigin(this.popper);
setTimeout(() => {
this.popper.destroy();
this.popper = null;
}, 300);
}
},
resetTransformOrigin(popper) {
let placementMap = { top: 'bottom', bottom: 'top' };
let placement = popper._popper.getAttribute('x-placement').split('-')[0];
let origin = placementMap[placement];
popper._popper.style.transformOrigin = `center ${ origin }`;
} }
}, },
beforeDestroy() { mounted() {
if (this.popper) { this.referenceElm = this.$parent.$refs.reference.$el;
this.popper.destroy(); this.$parent.popperElm = this.popperElm = this.$el;
} this.$on('updatePopper', _ => { this.showPopper = true; });
this.$on('destroyPopper', _ => { this.showPopper = false; });
} }
}; };
</script> </script>

View File

@ -1,5 +1,8 @@
<template> <template>
<div class="el-select" :class="{ 'is-multiple': multiple, 'is-small': size === 'small' }"> <div
class="el-select"
v-clickoutside="handleClose"
:class="{ 'is-multiple': multiple, 'is-small': size === 'small' }">
<div class="el-select__tags" v-if="multiple" @click.stop="toggleMenu" ref="tags" :style="{ 'max-width': inputWidth - 32 + 'px' }"> <div class="el-select__tags" v-if="multiple" @click.stop="toggleMenu" ref="tags" :style="{ 'max-width': inputWidth - 32 + 'px' }">
<transition-group @after-leave="resetInputHeight"> <transition-group @after-leave="resetInputHeight">
<el-tag <el-tag
@ -45,10 +48,9 @@
@keydown.native.tab="visible = false" @keydown.native.tab="visible = false"
@mouseenter.native="inputHovering = true" @mouseenter.native="inputHovering = true"
@mouseleave.native="inputHovering = false" @mouseleave.native="inputHovering = false"
:icon="iconClass" :icon="iconClass">
v-element-clickoutside="handleClose">
</el-input> </el-input>
<transition name="md-fade-bottom"> <transition name="md-fade-bottom" @after-leave="doDestroy">
<el-select-menu <el-select-menu
ref="popper" ref="popper"
v-show="visible && nodataText !== false"> v-show="visible && nodataText !== false">
@ -128,9 +130,7 @@
ElTag ElTag
}, },
directives: { directives: { Clickoutside },
ElementClickoutside: Clickoutside
},
props: { props: {
name: String, name: String,
@ -317,6 +317,10 @@
}, },
methods: { methods: {
doDestroy() {
this.$refs.popper.doDestroy();
},
handleClose() { handleClose() {
this.visible = false; this.visible = false;
}, },

View File

@ -26,7 +26,7 @@
</div> </div>
</template> </template>
<script type="text/ecmascript-6"> <script type="text/babel">
import Popper from 'main/utils/popper'; import Popper from 'main/utils/popper';
import ElInputNumber from 'packages/input-number/index.js'; import ElInputNumber from 'packages/input-number/index.js';
import { getStyle } from 'wind-dom/src/style'; import { getStyle } from 'wind-dom/src/style';

View File

@ -155,11 +155,6 @@ export default {
grid.$emit('rowclick', row, event); grid.$emit('rowclick', row, event);
}, },
handleCreate(vm) {
document.body.appendChild(vm.$refs.popper);
vm.updatePopper();
},
$getPropertyText(row, property, columnId) { $getPropertyText(row, property, columnId) {
let grid = this.$parent; let grid = this.$parent;
const column = getColumnById(grid, columnId); const column = getColumnById(grid, columnId);

View File

@ -190,7 +190,6 @@ export default {
return _self.showTooltipWhenOverflow return _self.showTooltipWhenOverflow
? <el-tooltip ? <el-tooltip
on-created={ this.handleCreate }
effect={ this.effect } effect={ this.effect }
placement="top" placement="top"
disabled={ this.tooltipDisabled }> disabled={ this.tooltipDisabled }>

View File

@ -4,7 +4,6 @@
@component-namespace el { @component-namespace el {
@b select-dropdown { @b select-dropdown {
width: 100%;
position: absolute; position: absolute;
z-index: 1001; z-index: 1001;
border: solid 1px #d3dce6; border: solid 1px #d3dce6;
@ -12,5 +11,44 @@
background-color: #fff; background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04); box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
box-sizing: border-box; box-sizing: border-box;
margin: 5px 0;
@when multiple {
& .el-select-dropdown__item.selected {
color: #20A0FF;
background-color: #fff;
&.hover {
background-color: #E5E9F2;
}
&::after {
position: absolute;
right: 10px;
font-family: 'element-icons';
content: "\E608";
font-size: 11px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
}
}
}
@b select-dropdown__nodata {
padding: 10px 0;
margin: 0;
text-align: center;
color: #999;
}
@b select-dropdown__list {
list-style: none;
padding: 6px 0;
margin: 0;
width: 100%;
max-height: 274px;
box-sizing: border-box;
overflow-y: auto;
} }
} }

View File

@ -25,27 +25,6 @@
} }
} }
& .el-select-dropdown {
margin: 5px 0;
& p.el-select-dropdown__nodata {
padding: 10px 0;
margin: 0;
text-align: center;
color: #999;
}
}
& .el-select-dropdown__list {
list-style: none;
padding: 6px 0;
margin: 0;
width: 100%;
max-height: 274px;
box-sizing: border-box;
overflow-y: auto;
}
& .el-input { & .el-input {
& .el-input__icon { & .el-input__icon {
color: #c0ccda; color: #c0ccda;
@ -95,27 +74,6 @@
} }
} }
@when multiple {
& .el-select-dropdown__item.selected {
color: #20A0FF;
background-color: #fff;
&.hover {
background-color: #E5E9F2;
}
&::after {
position: absolute;
right: 10px;
font-family: 'element-icons';
content: "\E608";
font-size: 11px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
}
}
@e input { @e input {
border: none; border: none;
outline: none; outline: none;

View File

@ -3,9 +3,8 @@
@import "../../date-picker/src/css/vars.css"; @import "../../date-picker/src/css/vars.css";
.time-select { .time-select {
min-width: 200px;
margin: 5px 0; margin: 5px 0;
width: 100%; min-width: 0;
} }
.time-select .el-picker-panel__content { .time-select .el-picker-panel__content {

View File

@ -1,3 +1,5 @@
import { on, off } from 'wind-dom/src/event';
/** /**
* v-clickoutside * v-clickoutside
* @desc 点击元素外面才会触发的事件 * @desc 点击元素外面才会触发的事件
@ -11,7 +13,10 @@ const clickoutsideContext = '@@clickoutsideContext';
export default { export default {
bind(el, binding, vnode) { bind(el, binding, vnode) {
const documentHandler = function(e) { const documentHandler = function(e) {
if (!vnode.context || el.contains(e.target)) return; if (!vnode.context ||
el.contains(e.target) ||
!vnode.context.popperElm ||
vnode.context.popperElm.contains(e.target)) return;
if (binding.expression) { if (binding.expression) {
vnode.context[el[clickoutsideContext].methodName](); vnode.context[el[clickoutsideContext].methodName]();
} else { } else {
@ -23,7 +28,7 @@ export default {
methodName: binding.expression, methodName: binding.expression,
bindingFn: binding.value bindingFn: binding.value
}; };
document.addEventListener('click', documentHandler); on(document, 'click', documentHandler);
}, },
update(el, binding) { update(el, binding) {
@ -32,7 +37,7 @@ export default {
}, },
unbind(el) { unbind(el) {
document.removeEventListener('click', el[clickoutsideContext].documentHandler); off(document, 'click', el[clickoutsideContext].documentHandler);
}, },
install(Vue) { install(Vue) {

View File

@ -1,4 +1,5 @@
import PopperJS from './popper'; import PopperJS from './popper';
import { PopupManager } from 'vue-popup';
/** /**
* @param {HTMLElement} [reference=$refs.reference] - The reference element used to position the popper. * @param {HTMLElement} [reference=$refs.reference] - The reference element used to position the popper.
@ -26,6 +27,10 @@ export default {
value: Boolean, value: Boolean,
visibleArrow: Boolean, visibleArrow: Boolean,
transition: String, transition: String,
appendToBody: {
type: Boolean,
default: true
},
options: { options: {
type: Object, type: Object,
default() { default() {
@ -62,44 +67,30 @@ export default {
} }
const options = this.options; const options = this.options;
const popper = this.popper || this.$refs.popper; const popper = this.popperElm = this.popperElm || this.popper || this.$refs.popper;
const reference = this.reference || this.$refs.reference || this.$slots.reference[0].elm; const reference = this.referenceElm = this.referenceElm || this.reference || this.$refs.reference || this.$slots.reference[0].elm;
if (!popper || !reference) return; if (!popper || !reference) return;
if (this.visibleArrow) {
this.appendArrow(popper);
}
if (this.visibleArrow) this.appendArrow(popper);
if (this.appendToBody) document.body.appendChild(this.popperElm);
if (this.popperJS && this.popperJS.hasOwnProperty('destroy')) { if (this.popperJS && this.popperJS.hasOwnProperty('destroy')) {
this.popperJS.destroy(); this.popperJS.destroy();
} }
options.placement = this.placement; options.placement = this.placement;
options.offset = this.offset; options.offset = this.offset;
this.popperJS = new PopperJS(reference, popper, options);
this.$nextTick(() => { this.popperJS.onCreate(_ => this.$emit('created', this));
this.popperJS = new PopperJS( this.popperJS._popper.style.zIndex = PopupManager.nextZIndex();
reference,
popper,
options
);
this.popperJS.onCreate(popper => {
this.resetTransformOrigin(popper);
this.$emit('created', this);
});
});
}, },
updatePopper() { updatePopper() {
if (this.popperJS) { this.popperJS ? this.popperJS.update() : this.createPopper();
this.popperJS.update();
} else {
this.createPopper();
}
}, },
doDestroy() { doDestroy() {
if (this.showPopper) return; if (this.showPopper || !this.popperJS) return;
this.popperJS.destroy(); this.popperJS.destroy();
this.popperJS = null; this.popperJS = null;
}, },
@ -144,8 +135,9 @@ export default {
}, },
beforeDestroy() { beforeDestroy() {
if (this.popperJS) { this.doDestroy();
this.popperJS.destroy(); this.popperElm &&
} document.body.contains(this.popperElm) &&
document.body.removeChild(this.popperElm);
} }
}; };