vue-popper.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import PopperJS from './popper';
  2. /**
  3. * @param {HTMLElement} [reference=$refs.reference] - The reference element used to position the popper.
  4. * @param {HTMLElement} [popper=$refs.popper] - The HTML element used as popper, or a configuration used to generate the popper.
  5. * @param {String} [placement=button] - Placement of the popper accepted values: top(-start, -end), right(-start, -end), bottom(-start, -right), left(-start, -end)
  6. * @param {Number} [offset=0] - Amount of pixels the popper will be shifted (can be negative).
  7. * @param {Boolean} [visible=false] Visibility of the popup element.
  8. * @param {Boolean} [visible-arrow=false] Visibility of the arrow, no style.
  9. */
  10. export default {
  11. props: {
  12. placement: {
  13. type: String,
  14. default: 'bottom'
  15. },
  16. boundariesPadding: {
  17. type: Number,
  18. default: 5
  19. },
  20. reference: Object,
  21. popper: Object,
  22. offset: {
  23. default: 0
  24. },
  25. visible: Boolean,
  26. visibleArrow: Boolean,
  27. transition: String,
  28. options: {
  29. type: Object,
  30. default() {
  31. return {};
  32. }
  33. }
  34. },
  35. data() {
  36. return {
  37. showPopper: false
  38. };
  39. },
  40. watch: {
  41. visible: {
  42. immediate: true,
  43. handler(val) {
  44. this.showPopper = val;
  45. }
  46. },
  47. showPopper(val) {
  48. val ? this.updatePopper() : this.destroyPopper();
  49. }
  50. },
  51. methods: {
  52. createPopper() {
  53. if (!/^(top|bottom|left|right)(-start|-end)?$/g.test(this.placement)) {
  54. return;
  55. }
  56. const options = this.options;
  57. const popper = this.popper || this.$refs.popper;
  58. const reference = this.reference || this.$refs.reference;
  59. if (!popper || !reference) return;
  60. if (this.visibleArrow) {
  61. this.appendArrow(popper);
  62. }
  63. if (this.popperJS && this.popperJS.hasOwnProperty('destroy')) {
  64. this.popperJS.destroy();
  65. }
  66. options.placement = this.placement;
  67. options.offset = this.offset;
  68. this.$nextTick(() => {
  69. this.popperJS = new PopperJS(
  70. reference,
  71. popper,
  72. options
  73. );
  74. this.popperJS.onCreate(popper => {
  75. this.resetTransformOrigin(popper);
  76. this.$emit('created', this);
  77. });
  78. });
  79. },
  80. updatePopper() {
  81. if (this.popperJS) {
  82. this.popperJS.update();
  83. } else {
  84. this.createPopper();
  85. }
  86. },
  87. doDestroy() {
  88. if (this.showPopper) return;
  89. this.popperJS._popper.removeEventListener('transitionend', this.doDestroy);
  90. this.popperJS.destroy();
  91. this.popperJS = null;
  92. },
  93. destroyPopper() {
  94. if (this.popperJS) {
  95. this.resetTransformOrigin(this.popperJS);
  96. if (this.transition) {
  97. this.popperJS._popper.addEventListener('transitionend', this.doDestroy);
  98. } else {
  99. this.doDestroy();
  100. }
  101. }
  102. },
  103. resetTransformOrigin(popper) {
  104. let placementMap = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' };
  105. let placement = popper._popper.getAttribute('x-placement').split('-')[0];
  106. let origin = placementMap[placement];
  107. popper._popper.style.transformOrigin = ['top', 'bottom'].indexOf(placement) > -1 ? `center ${ origin }` : `${ origin } center`;
  108. },
  109. appendArrow(element) {
  110. let hash;
  111. if (this.appended) {
  112. return;
  113. }
  114. this.appended = true;
  115. for (let item in element.attributes) {
  116. if (/^_v-/.test(element.attributes[item].name)) {
  117. hash = element.attributes[item].name;
  118. break;
  119. }
  120. }
  121. const arrow = document.createElement('div');
  122. if (hash) {
  123. arrow.setAttribute(hash, '');
  124. }
  125. arrow.setAttribute('x-arrow', '');
  126. arrow.className = 'popper__arrow';
  127. element.appendChild(arrow);
  128. }
  129. },
  130. beforeDestroy() {
  131. if (this.popperJS) {
  132. this.popperJS.destroy();
  133. }
  134. }
  135. };