directive.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import Vue from 'vue';
  2. import Loading from './loading.vue';
  3. import { addClass, removeClass, getStyle } from 'element-ui/src/utils/dom';
  4. import { PopupManager } from 'element-ui/src/utils/popup';
  5. import afterLeave from 'element-ui/src/utils/after-leave';
  6. const Mask = Vue.extend(Loading);
  7. const loadingDirective = {};
  8. loadingDirective.install = Vue => {
  9. if (Vue.prototype.$isServer) return;
  10. const toggleLoading = (el, binding) => {
  11. if (binding.value) {
  12. Vue.nextTick(() => {
  13. if (binding.modifiers.fullscreen) {
  14. el.originalPosition = getStyle(document.body, 'position');
  15. el.originalOverflow = getStyle(document.body, 'overflow');
  16. el.maskStyle.zIndex = PopupManager.nextZIndex();
  17. addClass(el.mask, 'is-fullscreen');
  18. insertDom(document.body, el, binding);
  19. } else {
  20. removeClass(el.mask, 'is-fullscreen');
  21. if (binding.modifiers.body) {
  22. el.originalPosition = getStyle(document.body, 'position');
  23. ['top', 'left'].forEach(property => {
  24. const scroll = property === 'top' ? 'scrollTop' : 'scrollLeft';
  25. el.maskStyle[property] = el.getBoundingClientRect()[property] +
  26. document.body[scroll] +
  27. document.documentElement[scroll] -
  28. parseInt(getStyle(document.body, `margin-${ property }`), 10) +
  29. 'px';
  30. });
  31. ['height', 'width'].forEach(property => {
  32. el.maskStyle[property] = el.getBoundingClientRect()[property] + 'px';
  33. });
  34. insertDom(document.body, el, binding);
  35. } else {
  36. el.originalPosition = getStyle(el, 'position');
  37. insertDom(el, el, binding);
  38. }
  39. }
  40. });
  41. } else {
  42. afterLeave(el.instance, _ => {
  43. if (!el.instance.hiding) return;
  44. el.domVisible = false;
  45. const target = binding.modifiers.fullscreen || binding.modifiers.body
  46. ? document.body
  47. : el;
  48. removeClass(target, 'el-loading-parent--relative');
  49. removeClass(target, 'el-loading-parent--hidden');
  50. el.instance.hiding = false;
  51. }, 300, true);
  52. el.instance.visible = false;
  53. el.instance.hiding = true;
  54. }
  55. };
  56. const insertDom = (parent, el, binding) => {
  57. if (!el.domVisible && getStyle(el, 'display') !== 'none' && getStyle(el, 'visibility') !== 'hidden') {
  58. Object.keys(el.maskStyle).forEach(property => {
  59. el.mask.style[property] = el.maskStyle[property];
  60. });
  61. if (el.originalPosition !== 'absolute' && el.originalPosition !== 'fixed') {
  62. addClass(parent, 'el-loading-parent--relative');
  63. }
  64. if (binding.modifiers.fullscreen && binding.modifiers.lock) {
  65. addClass(parent, 'el-loading-parent--hidden');
  66. }
  67. el.domVisible = true;
  68. parent.appendChild(el.mask);
  69. Vue.nextTick(() => {
  70. if (el.instance.hiding) {
  71. el.instance.$emit('after-leave');
  72. } else {
  73. el.instance.visible = true;
  74. }
  75. });
  76. el.domInserted = true;
  77. } else if (el.domVisible && el.instance.hiding === true) {
  78. el.instance.visible = true;
  79. el.instance.hiding = false;
  80. }
  81. };
  82. Vue.directive('loading', {
  83. bind: function(el, binding, vnode) {
  84. const textExr = el.getAttribute('element-loading-text');
  85. const spinnerExr = el.getAttribute('element-loading-spinner');
  86. const backgroundExr = el.getAttribute('element-loading-background');
  87. const customClassExr = el.getAttribute('element-loading-custom-class');
  88. const vm = vnode.context;
  89. const mask = new Mask({
  90. el: document.createElement('div'),
  91. data: {
  92. text: vm && vm[textExr] || textExr,
  93. spinner: vm && vm[spinnerExr] || spinnerExr,
  94. background: vm && vm[backgroundExr] || backgroundExr,
  95. customClass: vm && vm[customClassExr] || customClassExr,
  96. fullscreen: !!binding.modifiers.fullscreen
  97. }
  98. });
  99. el.instance = mask;
  100. el.mask = mask.$el;
  101. el.maskStyle = {};
  102. binding.value && toggleLoading(el, binding);
  103. },
  104. update: function(el, binding) {
  105. el.instance.setText(el.getAttribute('element-loading-text'));
  106. if (binding.oldValue !== binding.value) {
  107. toggleLoading(el, binding);
  108. }
  109. },
  110. unbind: function(el, binding) {
  111. if (el.domInserted) {
  112. el.mask &&
  113. el.mask.parentNode &&
  114. el.mask.parentNode.removeChild(el.mask);
  115. toggleLoading(el, { value: false, modifiers: binding.modifiers });
  116. }
  117. el.instance && el.instance.$destroy();
  118. }
  119. });
  120. };
  121. export default loadingDirective;