uni-popup.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <template>
  2. <view v-if="showPopup" class="uni-popup" @touchmove.stop.prevent="clear">
  3. <uni-transition :mode-class="['fade']" :styles="maskClass" :duration="duration" :show="showTrans" @click="onTap" />
  4. <uni-transition :mode-class="ani" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
  5. <view class="uni-popup__wrapper-box" @click.stop="clear">
  6. <slot />
  7. </view>
  8. </uni-transition>
  9. </view>
  10. </template>
  11. <script>
  12. import uniTransition from '../uni-transition/uni-transition.vue'
  13. /**
  14. * PopUp 弹出层
  15. * @description 弹出层组件,为了解决遮罩弹层的问题
  16. * @tutorial https://ext.dcloud.net.cn/plugin?id=329
  17. * @property {String} type = [top|center|bottom] 弹出方式
  18. * @value top 顶部弹出
  19. * @value center 中间弹出
  20. * @value bottom 底部弹出
  21. * @property {Boolean} animation = [ture|false] 是否开启动画
  22. * @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
  23. * @event {Function} change 打开关闭弹窗触发,e={show: false}
  24. */
  25. export default {
  26. name: 'UniPopup',
  27. components: {
  28. uniTransition
  29. },
  30. props: {
  31. // 开启动画
  32. animation: {
  33. type: Boolean,
  34. default: true
  35. },
  36. // 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
  37. type: {
  38. type: String,
  39. default: 'center'
  40. },
  41. // maskClick
  42. maskClick: {
  43. type: Boolean,
  44. default: true
  45. }
  46. },
  47. data() {
  48. return {
  49. duration: 300,
  50. ani: [],
  51. showPopup: false,
  52. showTrans: false,
  53. maskClass: {
  54. 'position': 'fixed',
  55. 'bottom': 0,
  56. 'top': 0,
  57. 'left': 0,
  58. 'right': 0,
  59. 'backgroundColor': 'rgba(0, 0, 0, 0.4)'
  60. },
  61. transClass: {
  62. 'position': 'fixed',
  63. 'left': 0,
  64. 'right': 0,
  65. }
  66. }
  67. },
  68. watch: {
  69. type: {
  70. handler: function(newVal) {
  71. switch (this.type) {
  72. case 'top':
  73. this.ani = ['slide-top']
  74. this.transClass = {
  75. 'position': 'fixed',
  76. 'left': 0,
  77. 'right': 0,
  78. }
  79. break
  80. case 'bottom':
  81. this.ani = ['slide-bottom']
  82. this.transClass = {
  83. 'position': 'fixed',
  84. 'left': 0,
  85. 'right': 0,
  86. 'bottom': 0
  87. }
  88. break
  89. case 'center':
  90. this.ani = ['zoom-out', 'fade']
  91. this.transClass = {
  92. 'position': 'fixed',
  93. /* #ifndef APP-NVUE */
  94. 'display': 'flex',
  95. 'flexDirection': 'column',
  96. /* #endif */
  97. 'bottom': 0,
  98. 'left': 0,
  99. 'right': 0,
  100. 'top': 0,
  101. 'justifyContent': 'center',
  102. 'alignItems': 'center'
  103. }
  104. break
  105. }
  106. },
  107. immediate: true
  108. }
  109. },
  110. created() {
  111. if (this.animation) {
  112. this.duration = 300
  113. } else {
  114. this.duration = 0
  115. }
  116. },
  117. methods: {
  118. clear(e) {
  119. // TODO nvue 取消冒泡
  120. e.stopPropagation()
  121. },
  122. open() {
  123. this.showPopup = true
  124. this.$nextTick(() => {
  125. clearTimeout(this.timer)
  126. this.timer = setTimeout(() => {
  127. this.showTrans = true
  128. }, 50);
  129. })
  130. this.$emit('change', {
  131. show: true
  132. })
  133. },
  134. close(type) {
  135. this.showTrans = false
  136. this.$nextTick(() => {
  137. clearTimeout(this.timer)
  138. this.timer = setTimeout(() => {
  139. this.$emit('change', {
  140. show: false
  141. })
  142. this.showPopup = false
  143. }, 300)
  144. })
  145. },
  146. onTap() {
  147. if (!this.maskClick) return
  148. this.close()
  149. }
  150. }
  151. }
  152. </script>
  153. <style lang="scss" scoped>
  154. .uni-popup {
  155. position: fixed;
  156. /* #ifdef H5 */
  157. top: var(--window-top);
  158. /* #endif */
  159. /* #ifndef H5 */
  160. top: 0;
  161. /* #endif */
  162. bottom: 0;
  163. left: 0;
  164. right: 0;
  165. /* #ifndef APP-NVUE */
  166. z-index: 99;
  167. /* #endif */
  168. }
  169. .uni-popup__mask {
  170. position: absolute;
  171. top: 0;
  172. bottom: 0;
  173. left: 0;
  174. right: 0;
  175. // background-color: $uni-bg-color-mask;
  176. background-color: #7f7f7f;
  177. opacity: 0;
  178. }
  179. .mask-ani {
  180. transition-property: opacity;
  181. transition-duration: 0.2s;
  182. }
  183. .uni-top-mask {
  184. opacity: 1;
  185. }
  186. .uni-bottom-mask {
  187. opacity: 1;
  188. }
  189. .uni-center-mask {
  190. opacity: 1;
  191. }
  192. .uni-popup__wrapper {
  193. /* #ifndef APP-NVUE */
  194. display: block;
  195. /* #endif */
  196. position: absolute;
  197. }
  198. .top {
  199. top: 0;
  200. left: 0;
  201. right: 0;
  202. transform: translateY(-500px);
  203. }
  204. .bottom {
  205. bottom: 0;
  206. left: 0;
  207. right: 0;
  208. transform: translateY(500px);
  209. }
  210. .center {
  211. /* #ifndef APP-NVUE */
  212. display: flex;
  213. flex-direction: column;
  214. /* #endif */
  215. bottom: 0;
  216. left: 0;
  217. right: 0;
  218. top: 0;
  219. justify-content: center;
  220. align-items: center;
  221. transform: scale(1.2);
  222. opacity: 0;
  223. }
  224. .uni-popup__wrapper-box {
  225. /* #ifndef APP-NVUE */
  226. display: block;
  227. /* #endif */
  228. position: relative;
  229. }
  230. .content-ani {
  231. // transition: transform 0.3s;
  232. transition-property: transform, opacity;
  233. transition-duration: 0.2s;
  234. }
  235. .uni-top-content {
  236. transform: translateY(0);
  237. }
  238. .uni-bottom-content {
  239. transform: translateY(0);
  240. }
  241. .uni-center-content {
  242. transform: scale(1);
  243. opacity: 1;
  244. }
  245. </style>