Parcourir la source

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
cinwell.li il y a 8 ans
Parent
commit
de696c78bc

+ 2 - 0
examples/docs/zh-cn/date-picker.md

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

+ 7 - 7
examples/docs/zh-cn/slider.md

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

+ 1 - 1
package.json

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

+ 9 - 1
packages/date-picker/src/css/date-picker.css

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

+ 1 - 0
packages/date-picker/src/css/picker-panel.css

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

+ 9 - 3
packages/date-picker/src/panel/date-range.vue

@@ -1,8 +1,13 @@
 <template>
-  <transition name="md-fade-bottom">
+  <transition name="md-fade-bottom" @after-leave="$emit('dodestroy')">
     <div
       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">
         <slot name="sidebar" class="el-picker-panel__sidebar"></slot>
         <div class="el-picker-panel__sidebar" v-if="shortcuts">
@@ -269,7 +274,8 @@
         visible: '',
         disabledDate: '',
         leftTimePickerVisible: false,
-        rightTimePickerVisible: false
+        rightTimePickerVisible: false,
+        width: 0
       };
     },
 

+ 9 - 3
packages/date-picker/src/panel/date.vue

@@ -1,8 +1,13 @@
 <template>
-  <transition name="md-fade-bottom">
+  <transition name="md-fade-bottom" @after-leave="$emit('dodestroy')">
     <div
       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">
         <slot name="sidebar" class="el-picker-panel__sidebar"></slot>
         <div class="el-picker-panel__sidebar" v-if="shortcuts">
@@ -339,7 +344,8 @@
         year: null,
         month: null,
         week: null,
-        timePickerVisible: false
+        timePickerVisible: false,
+        width: 0
       };
     },
 

+ 4 - 2
packages/date-picker/src/panel/time-range.vue

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

+ 4 - 2
packages/date-picker/src/panel/time-select.vue

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

+ 4 - 2
packages/date-picker/src/panel/time.vue

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

+ 26 - 37
packages/date-picker/src/picker.vue

@@ -33,9 +33,20 @@
 import Vue from 'vue';
 import Clickoutside from 'main/utils/clickoutside';
 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';
 
+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 RANGE_SEPARATOR = ' - ';
 const DEFAULT_FORMATS = {
@@ -184,7 +195,7 @@ const PLACEMENT_MAP = {
 };
 
 export default {
-  mixins: [emitter],
+  mixins: [emitter, newPopper],
 
   props: {
     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: {
     handleClose() {
       this.pickerVisible = false;
@@ -382,16 +402,6 @@ export default {
       !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() {
       if (this.picker) {
         this.picker.resetView && this.picker.resetView();
@@ -406,6 +416,8 @@ export default {
         this.picker = new Vue(merge({
           el: document.createElement('div')
         }, 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.selectionMode = this.selectionMode;
         if (this.format) {
@@ -441,6 +453,7 @@ export default {
         this.pickerVisible = this.picker.visible = true;
         this.picker.resetView && this.picker.resetView();
 
+        this.picker.$on('dodestroy', this.doDestroy);
         this.picker.$on('pick', (date, visible = false) => {
           this.$emit('input', date);
 
@@ -460,20 +473,7 @@ export default {
         this.pickerVisible = this.picker.visible = true;
       }
 
-      this.$nextTick(() => {
-        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);
-        });
-      });
+      this.updatePopper();
 
       if (this.value instanceof Date) {
         this.picker.date = new Date(this.value.getTime());
@@ -488,18 +488,7 @@ export default {
         }
         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>

+ 43 - 42
packages/popover/src/main.vue

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

+ 34 - 47
packages/select-dropdown/src/select-dropdown.vue

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

+ 11 - 7
packages/select/src/select.vue

@@ -1,5 +1,8 @@
 <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' }">
       <transition-group @after-leave="resetInputHeight">
         <el-tag
@@ -45,10 +48,9 @@
       @keydown.native.tab="visible = false"
       @mouseenter.native="inputHovering = true"
       @mouseleave.native="inputHovering = false"
-      :icon="iconClass"
-      v-element-clickoutside="handleClose">
+      :icon="iconClass">
     </el-input>
-    <transition name="md-fade-bottom">
+    <transition name="md-fade-bottom" @after-leave="doDestroy">
       <el-select-menu
         ref="popper"
         v-show="visible && nodataText !== false">
@@ -128,9 +130,7 @@
       ElTag
     },
 
-    directives: {
-      ElementClickoutside: Clickoutside
-    },
+    directives: { Clickoutside },
 
     props: {
       name: String,
@@ -317,6 +317,10 @@
     },
 
     methods: {
+      doDestroy() {
+        this.$refs.popper.doDestroy();
+      },
+
       handleClose() {
         this.visible = false;
       },

+ 1 - 1
packages/slider/src/main.vue

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

+ 0 - 5
packages/table/src/table-body.js

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

+ 0 - 1
packages/table/src/table-column.js

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

+ 39 - 1
packages/theme-default/src/select-dropdown.css

@@ -4,7 +4,6 @@
 @component-namespace el {
 
   @b select-dropdown {
-    width: 100%;
     position: absolute;
     z-index: 1001;
     border: solid 1px #d3dce6;
@@ -12,5 +11,44 @@
     background-color: #fff;
     box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
     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;
   }
 }

+ 0 - 42
packages/theme-default/src/select.css

@@ -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__icon {
         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 {
       border: none;
       outline: none;

+ 1 - 2
packages/theme-default/src/time-select.css

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

+ 8 - 3
src/utils/clickoutside.js

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

+ 18 - 26
src/utils/vue-popper.js

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