lee-popup.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <template>
  2. <view class="lee-popup-mask" :class="maskClass" @click="maskClickHandler" data-role="mask">
  3. <view class="lee-popup" :style="popupStyle" @transitionend="onAnimationEnd">
  4. <slot></slot>
  5. </view>
  6. </view>
  7. </template>
  8. <script>
  9. // 弹出层状态
  10. const Status = {
  11. OPEN: 'open',
  12. CLOSE: 'close',
  13. OPENED: 'opened',
  14. CLOSED: 'closed'
  15. }
  16. /**
  17. * LeePopup弹出层
  18. * @property {String} type = [top|left|right|bottom] 弹出方向
  19. * @value top 从顶部弹出
  20. * @value left 从左侧弹出
  21. * @value right 从右侧弹出
  22. * @value bottom 从底部弹出
  23. * @property {String} width 横向弹出时,指定弹框宽度
  24. * @property {String} height 纵向弹出时,指定弹出高度
  25. * @property {Object} customStyle 自定义弹出层样式
  26. * @property {Boolean} animation 是否开启动画
  27. * @property {Boolean} round 是否使用圆角
  28. * @property {String} padding 定义边距
  29. * @event {Function(status: String)} change 状态更新事件
  30. * @event {Function} open 弹层打开事件,动画未结束
  31. * @event {Function} opened 弹层打开事件,动画结束时
  32. * @event {Function} close 弹层关闭事件,动画未结束
  33. * @event {Function} closed 弹层关闭事件,动画结束时
  34. */
  35. export default {
  36. props: {
  37. // 弹窗方向
  38. type: {
  39. type: String,
  40. default: 'top'
  41. },
  42. // 横向弹出时,指定弹框宽度
  43. width: {
  44. type: String,
  45. default: '440rpx'
  46. },
  47. // 纵向弹出时,指定弹出高度
  48. height: {
  49. type: String,
  50. default: 'auto'
  51. },
  52. // 自定义弹出层样式
  53. customStyle: {
  54. type: Object,
  55. default: () => {}
  56. },
  57. // 是否开启动画
  58. animation: {
  59. type: Boolean,
  60. default: true
  61. },
  62. // 圆角模式
  63. round: {
  64. type: Boolean,
  65. default: false
  66. },
  67. // 边距
  68. padding: {
  69. type: String,
  70. default: '30rpx'
  71. }
  72. },
  73. data() {
  74. return {
  75. status: Status.CLOSED
  76. }
  77. },
  78. computed: {
  79. // 是否为纵向弹出层
  80. isVertical() {
  81. return ['top', 'bottom'].includes(this.type)
  82. },
  83. // 弹出层样式计算
  84. popupStyle() {
  85. const style = Object.assign({
  86. width: this.isVertical ? '100%' : this.width,
  87. height: this.isVertical ? this.height : '100%',
  88. padding: this.padding
  89. }, this.customStyle)
  90. if (this.animation) {
  91. style.transition = 'all .5s'
  92. }
  93. return Object.entries(style).map(item => `${item[0]}: ${item[1]}`).join(';')
  94. },
  95. // 遮罩层类计算
  96. maskClass() {
  97. const list = [
  98. `lee-popup-type_${this.type}`,
  99. `lee-popup-status_${this.status}`,
  100. ]
  101. if (this.round) {
  102. list.push('lee-popup-round')
  103. }
  104. return list
  105. }
  106. },
  107. watch: {
  108. // 派发状态更新事件
  109. status(status) {
  110. this.$emit(status)
  111. this.$emit('change', status)
  112. }
  113. },
  114. methods: {
  115. // 打开弹出层
  116. open() {
  117. this.status = this.animation ? Status.OPEN : Status.OPENED
  118. },
  119. // 关闭弹出层
  120. close() {
  121. this.status = this.animation ? Status.CLOSE : Status.CLOSED
  122. },
  123. // 点击遮罩层
  124. maskClickHandler(e) {
  125. if (e.target.dataset.role === 'mask') {
  126. this.close()
  127. }
  128. },
  129. // 动画结束
  130. onAnimationEnd() {
  131. if (this.status === Status.OPEN) {
  132. this.status = Status.OPENED
  133. } else if (this.status === Status.CLOSE) {
  134. this.status = Status.CLOSED
  135. }
  136. }
  137. }
  138. }
  139. </script>
  140. <style lang="scss">
  141. $z-index: 3000;
  142. .lee-popup-mask {
  143. top: 0;
  144. left: 0;
  145. width: 100%;
  146. height: 100%;
  147. position: fixed;
  148. z-index: $z-index;
  149. background-color: $uni-bg-color-mask;
  150. &.lee-popup-status_closed {
  151. visibility: hidden;
  152. }
  153. }
  154. .lee-popup {
  155. box-sizing: border-box;
  156. background-color: $uni-bg-color;
  157. position: absolute;
  158. &-round > & {
  159. border-radius: $uni-border-radius-lg;
  160. }
  161. &-type_top > & {
  162. top: 0;
  163. left: 0;
  164. transform: translate(0, -100%);
  165. border-top-left-radius: 0;
  166. border-top-right-radius: 0;
  167. }
  168. &-type_left > & {
  169. top: 0;
  170. left: 0;
  171. transform: translate(-100%, 0);
  172. border-top-left-radius: 0;
  173. border-bottom-left-radius: 0;
  174. }
  175. &-type_right > & {
  176. top: 0;
  177. right: 0;
  178. transform: translate(100%, 0);
  179. border-top-right-radius: 0;
  180. border-bottom-right-radius: 0;
  181. }
  182. &-type_bottom > & {
  183. left: 0;
  184. bottom: 0;
  185. transform: translate(0, 100%);
  186. border-bottom-left-radius: 0;
  187. border-bottom-right-radius: 0;
  188. }
  189. &-status_open > &,
  190. &-status_opened > & {
  191. transform: translate(0, 0);
  192. }
  193. }
  194. </style>