uni-popup-ori.vue 4.8 KB

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