main.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <template>
  2. <transition name="el-notification-fade">
  3. <div
  4. :class="['el-notification', customClass, horizontalClass]"
  5. v-show="visible"
  6. :style="positionStyle"
  7. @mouseenter="clearTimer()"
  8. @mouseleave="startTimer()"
  9. @click="click"
  10. role="alert"
  11. >
  12. <i
  13. class="el-notification__icon"
  14. :class="[ typeClass, iconClass ]"
  15. v-if="type || iconClass">
  16. </i>
  17. <div class="el-notification__group" :class="{ 'is-with-icon': typeClass || iconClass }">
  18. <h2 class="el-notification__title" v-text="title"></h2>
  19. <div class="el-notification__content" v-show="message">
  20. <slot>
  21. <p v-if="!dangerouslyUseHTMLString">{{ message }}</p>
  22. <p v-else v-html="message"></p>
  23. </slot>
  24. </div>
  25. <div
  26. class="el-notification__closeBtn el-icon-close"
  27. v-if="showClose"
  28. @click.stop="close"></div>
  29. </div>
  30. </div>
  31. </transition>
  32. </template>
  33. <script type="text/babel">
  34. let typeMap = {
  35. success: 'success',
  36. info: 'info',
  37. warning: 'warning',
  38. error: 'error'
  39. };
  40. export default {
  41. data() {
  42. return {
  43. visible: false,
  44. title: '',
  45. message: '',
  46. duration: 4500,
  47. type: '',
  48. showClose: true,
  49. customClass: '',
  50. iconClass: '',
  51. onClose: null,
  52. onClick: null,
  53. closed: false,
  54. verticalOffset: 0,
  55. timer: null,
  56. dangerouslyUseHTMLString: false,
  57. position: 'top-right'
  58. };
  59. },
  60. computed: {
  61. typeClass() {
  62. return this.type && typeMap[this.type] ? `el-icon-${ typeMap[this.type] }` : '';
  63. },
  64. horizontalClass() {
  65. return this.position.indexOf('right') > -1 ? 'right' : 'left';
  66. },
  67. verticalProperty() {
  68. return /^top-/.test(this.position) ? 'top' : 'bottom';
  69. },
  70. positionStyle() {
  71. return {
  72. [this.verticalProperty]: `${ this.verticalOffset }px`
  73. };
  74. }
  75. },
  76. watch: {
  77. closed(newVal) {
  78. if (newVal) {
  79. this.visible = false;
  80. this.$el.addEventListener('transitionend', this.destroyElement);
  81. }
  82. }
  83. },
  84. methods: {
  85. destroyElement() {
  86. this.$el.removeEventListener('transitionend', this.destroyElement);
  87. this.$destroy(true);
  88. this.$el.parentNode.removeChild(this.$el);
  89. },
  90. click() {
  91. if (typeof this.onClick === 'function') {
  92. this.onClick();
  93. }
  94. },
  95. close() {
  96. this.closed = true;
  97. if (typeof this.onClose === 'function') {
  98. this.onClose();
  99. }
  100. },
  101. clearTimer() {
  102. clearTimeout(this.timer);
  103. },
  104. startTimer() {
  105. if (this.duration > 0) {
  106. this.timer = setTimeout(() => {
  107. if (!this.closed) {
  108. this.close();
  109. }
  110. }, this.duration);
  111. }
  112. },
  113. keydown(e) {
  114. if (e.keyCode === 46 || e.keyCode === 8) {
  115. this.clearTimer(); // detele 取消倒计时
  116. } else if (e.keyCode === 27) { // esc关闭消息
  117. if (!this.closed) {
  118. this.close();
  119. }
  120. } else {
  121. this.startTimer(); // 恢复倒计时
  122. }
  123. }
  124. },
  125. mounted() {
  126. if (this.duration > 0) {
  127. this.timer = setTimeout(() => {
  128. if (!this.closed) {
  129. this.close();
  130. }
  131. }, this.duration);
  132. }
  133. document.addEventListener('keydown', this.keydown);
  134. },
  135. beforeDestroy() {
  136. document.removeEventListener('keydown', this.keydown);
  137. }
  138. };
  139. </script>