uni-popup.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <template>
  2. <view v-if="showPopup" class="uni-popup">
  3. <view :class="[ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__mask" @click="close(true)" />
  4. <view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper safe-area" @click="close(true)" v-if="isIphoneX">
  5. <view class="uni-popup__wrapper-box" @click.stop="clear"><slot /></view>
  6. </view>
  7. <view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper" @click="close(true)" v-else>
  8. <view class="uni-popup__wrapper-box" @click.stop="clear"><slot /></view>
  9. </view>
  10. </view>
  11. </template>
  12. <script>
  13. export default {
  14. name: 'UniPopup',
  15. props: {
  16. // 开启动画
  17. animation: {
  18. type: Boolean,
  19. default: true
  20. },
  21. // 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
  22. type: {
  23. type: String,
  24. default: 'center'
  25. },
  26. // 是否开启自定义
  27. custom: {
  28. type: Boolean,
  29. default: false
  30. },
  31. // maskClick
  32. maskClick: {
  33. type: Boolean,
  34. default: true
  35. },
  36. show: {
  37. type: Boolean,
  38. default: true
  39. }
  40. },
  41. data() {
  42. return {
  43. ani: '',
  44. showPopup: false,
  45. callback: null,
  46. isIphoneX: false
  47. };
  48. },
  49. watch: {
  50. show(newValue) {
  51. if (newValue) {
  52. this.open();
  53. } else {
  54. this.close();
  55. }
  56. }
  57. },
  58. created() {
  59. this.isIphoneX = this.$util.uniappIsIPhoneX();
  60. },
  61. methods: {
  62. clear() {},
  63. open(callback) {
  64. if (callback) this.callback = callback;
  65. this.$emit('change', {
  66. show: true
  67. });
  68. this.showPopup = true;
  69. this.$nextTick(() => {
  70. setTimeout(() => {
  71. this.ani = 'uni-' + this.type;
  72. }, 30);
  73. });
  74. },
  75. close(type, callback) {
  76. if (!this.maskClick && type) return;
  77. this.$emit('change', {
  78. show: false
  79. });
  80. this.ani = '';
  81. this.$nextTick(() => {
  82. setTimeout(() => {
  83. this.showPopup = false;
  84. }, 300);
  85. });
  86. if (callback) callback();
  87. if (this.callback) this.callback.call(this);
  88. }
  89. }
  90. };
  91. </script>
  92. <style>
  93. @charset "UTF-8";
  94. .uni-popup {
  95. position: fixed;
  96. top: 0;
  97. top: 0;
  98. bottom: 0;
  99. left: 0;
  100. right: 0;
  101. z-index: 999;
  102. overflow: hidden;
  103. }
  104. .uni-popup__mask {
  105. position: absolute;
  106. top: 0;
  107. bottom: 0;
  108. left: 0;
  109. right: 0;
  110. z-index: 998;
  111. background: rgba(0, 0, 0, 0.4);
  112. opacity: 0;
  113. }
  114. .uni-popup__mask.ani {
  115. transition: all 0.3s;
  116. }
  117. .uni-popup__mask.uni-bottom,
  118. .uni-popup__mask.uni-center,
  119. .uni-popup__mask.uni-right,
  120. .uni-popup__mask.uni-left,
  121. .uni-popup__mask.uni-top {
  122. opacity: 1;
  123. }
  124. .uni-popup__wrapper {
  125. position: absolute;
  126. z-index: 999;
  127. box-sizing: border-box;
  128. }
  129. .uni-popup__wrapper.ani {
  130. transition: all 0.3s;
  131. }
  132. .uni-popup__wrapper.top {
  133. top: 0;
  134. left: 0;
  135. width: 100%;
  136. transform: translateY(-100%);
  137. }
  138. .uni-popup__wrapper.bottom {
  139. bottom: 0;
  140. left: 0;
  141. width: 100%;
  142. transform: translateY(100%);
  143. background: #ffffff;
  144. }
  145. .uni-popup__wrapper.right {
  146. bottom: 0;
  147. left: 0;
  148. width: 100%;
  149. transform: translateX(100%);
  150. }
  151. .uni-popup__wrapper.left {
  152. bottom: 0;
  153. left: 0;
  154. width: 100%;
  155. transform: translateX(-100%);
  156. }
  157. .uni-popup__wrapper.center {
  158. width: 100%;
  159. height: 100%;
  160. display: flex;
  161. justify-content: center;
  162. align-items: center;
  163. transform: scale(1.2);
  164. opacity: 0;
  165. }
  166. .uni-popup__wrapper-box {
  167. position: relative;
  168. box-sizing: border-box;
  169. border-radius: 10rpx;
  170. }
  171. .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
  172. background: #fff;
  173. }
  174. .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
  175. position: relative;
  176. max-width: 80%;
  177. max-height: 80%;
  178. overflow-y: scroll;
  179. }
  180. .uni-popup__wrapper.uni-custom.bottom .uni-popup__wrapper-box,
  181. .uni-popup__wrapper.uni-custom.top .uni-popup__wrapper-box {
  182. width: 100%;
  183. max-height: 500px;
  184. overflow-y: scroll;
  185. }
  186. .uni-popup__wrapper.uni-bottom,
  187. .uni-popup__wrapper.uni-top {
  188. transform: translateY(0);
  189. }
  190. .uni-popup__wrapper.uni-left,
  191. .uni-popup__wrapper.uni-right {
  192. transform: translateX(0);
  193. }
  194. .uni-popup__wrapper.uni-center {
  195. transform: scale(1);
  196. opacity: 1;
  197. }
  198. /* isIphoneX系列手机底部安全距离 */
  199. .bottom.safe-area {
  200. padding-bottom: constant(safe-area-inset-bottom);
  201. padding-bottom: env(safe-area-inset-bottom);
  202. }
  203. .left.safe-area {
  204. padding-bottom: 68rpx;
  205. }
  206. .right.safe-area {
  207. padding-bottom: 68rpx;
  208. }
  209. </style>