vue-popper.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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. watch: {
  36. 'visible'(val) {
  37. if (this.popperDestroying) return;
  38. val ? this.updatePopper() : this.destroyPopper();
  39. }
  40. },
  41. methods: {
  42. createPopper() {
  43. if (!/^(top|bottom|left|right)(-start|-end)?$/g.test(this.placement)) {
  44. return;
  45. }
  46. this.popper = this.popper || this.$refs.popper;
  47. this.reference = this.reference || this.$refs.reference;
  48. if (!this.popper || !this.reference) {
  49. return;
  50. }
  51. if (this.visibleArrow) {
  52. this.appendArrow(this.popper);
  53. }
  54. if (this.popperJS && this.popperJS.hasOwnProperty('destroy')) {
  55. this.popperJS.destroy();
  56. }
  57. this.$set('options.placement', this.placement);
  58. this.$set('options.offset', this.offset);
  59. this.popperJS = new PopperJS(
  60. this.reference,
  61. this.popper,
  62. this.options
  63. );
  64. this.popperJS.onCreate(popper => {
  65. this.resetTransformOrigin(popper);
  66. this.$emit('created', this);
  67. });
  68. },
  69. updatePopper() {
  70. if (this.popperJS) {
  71. this.popperJS.update();
  72. } else {
  73. this.createPopper();
  74. }
  75. },
  76. doDestroy() {
  77. if (this.visible) return;
  78. this.popperJS._popper.removeEventListener('transitionend', this.doDestroy);
  79. this.popperJS.destroy();
  80. this.popperJS = null;
  81. },
  82. destroyPopper() {
  83. if (this.popperJS) {
  84. this.resetTransformOrigin(this.popperJS);
  85. if (this.transition) {
  86. this.popperJS._popper.addEventListener('transitionend', this.doDestroy);
  87. } else {
  88. this.doDestroy();
  89. }
  90. }
  91. },
  92. resetTransformOrigin(popper) {
  93. let placementMap = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' };
  94. let placement = popper._popper.getAttribute('x-placement').split('-')[0];
  95. let origin = placementMap[placement];
  96. popper._popper.style.transformOrigin = ['top', 'bottom'].indexOf(placement) > -1 ? `center ${ origin }` : `${ origin } center`;
  97. },
  98. appendArrow(element) {
  99. let hash;
  100. if (this.appended) {
  101. return;
  102. }
  103. this.appended = true;
  104. for (let item in element.attributes) {
  105. if (/^_v-/.test(element.attributes[item].name)) {
  106. hash = element.attributes[item].name;
  107. break;
  108. }
  109. }
  110. const arrow = document.createElement('div');
  111. if (hash) {
  112. arrow.setAttribute(hash, '');
  113. }
  114. arrow.setAttribute('x-arrow', '');
  115. arrow.className = 'popper__arrow';
  116. element.appendChild(arrow);
  117. }
  118. },
  119. beforeDestroy() {
  120. if (this.popperJS) {
  121. this.popperJS.destroy();
  122. }
  123. }
  124. };