z-popup.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. <template>
  2. <view class="popup_view" :style="{top:popupTop, bottom: popupBottom, zIndex: zIndex}"
  3. :class="{'popup_view_bottom': type == 'bottom' ,'popup_view_center':type == 'center', 'popup_view_top': type == 'top'}"
  4. @touchmove="onTouchMove" v-if="currentValue">
  5. <!-- 遮罩层动画 -->
  6. <view class="popup_mask" @click="hideOnBlur && setAnimationHide()"></view>
  7. <!-- 显示信息层 -->
  8. <view class="popup_container" ref="popupContainer" :class="{'popup_container_bottom': type == 'bottom' ,'popup_container_center':type == 'center', 'popup_container_top': type == 'top'}" :style="containerStyle">
  9. <slot></slot>
  10. </view>
  11. </view>
  12. </template>
  13. <script>
  14. // #ifdef APP-NVUE
  15. const animation = weex.requireModule('animation');
  16. const dom = weex.requireModule('dom');
  17. // #endif
  18. export default {
  19. props: {
  20. //是否显示
  21. value: {
  22. type: Boolean,
  23. default: function() {
  24. return false;
  25. }
  26. },
  27. //点击遮罩层关闭弹窗
  28. hideOnBlur: {
  29. type: Boolean,
  30. default: function() {
  31. return true;
  32. }
  33. },
  34. //禁止页面滚动(H5生效)
  35. scroll: {
  36. type: Boolean,
  37. default: true
  38. },
  39. // 类型
  40. // bottom 靠下
  41. // center 居中
  42. // top 靠上
  43. type: {
  44. type: String,
  45. default: function() {
  46. return "bottom";
  47. }
  48. },
  49. // 偏移
  50. offset: {
  51. type: Number,
  52. default: function() {
  53. return 0;
  54. }
  55. },
  56. // index
  57. zIndex: {
  58. type: Number,
  59. default: function() {
  60. return 500;
  61. }
  62. },
  63. width: {
  64. type: String,
  65. default: function() {
  66. return '600upx';
  67. }
  68. },
  69. radius: {
  70. type: String,
  71. default: function() {
  72. return '0upx';
  73. }
  74. },
  75. },
  76. computed: {
  77. containerStyle(){
  78. let style = {
  79. 'opacity': this.opacity,
  80. 'width':this.width,
  81. 'border-radius': this.radius
  82. };
  83. if(this.transform){
  84. style.transform = this.transform;
  85. }
  86. return style;
  87. }
  88. },
  89. created() {
  90. this.systemInfo = uni.getSystemInfoSync();
  91. if (typeof this.value !== "undefined") {
  92. if(this.value){
  93. this.setAnimationShow();
  94. }
  95. }
  96. },
  97. watch: {
  98. value(val) {
  99. if(val){
  100. this.setAnimationShow();
  101. } else {
  102. this.setAnimationHide();
  103. }
  104. }
  105. },
  106. data() {
  107. return {
  108. // 传进来的值
  109. currentValue: false,
  110. opacity: 0,
  111. popupTop: "inherit",
  112. popupBottom: "inherit",
  113. transform: "",
  114. systemInfo: {},
  115. timer: null
  116. };
  117. },
  118. methods: {
  119. onTouchMove: function(event) {
  120. !this.scroll && event.preventDefault();
  121. },
  122. getPxRpx(px){
  123. let ratio = 750 / this.systemInfo.screenWidth;
  124. return ratio * px;
  125. },
  126. setAnimationShow() {
  127. this.currentValue = true;
  128. this.$nextTick(() => {
  129. setTimeout(() => {
  130. this.timer && clearTimeout(this.timer);
  131. this.$emit("input", true);
  132. this.$emit("change", true);
  133. if (this.type == "bottom") {
  134. this.animationParsing({
  135. translateY: 0,
  136. defaulTranslateY: 1,
  137. opacity: 1
  138. });
  139. this.popupTop = "0rpx";
  140. if(this.offset > 0){
  141. this.popupBottom = this.offset + "rpx";
  142. } else {
  143. this.popupBottom = this.getPxRpx(this.systemInfo.windowBottom) + "rpx";
  144. }
  145. } else if (this.type == "center") {
  146. this.popupTop = "0rpx";
  147. this.popupBottom = "0rpx";
  148. this.animationParsing({
  149. scale: 1,
  150. defaulScale: 0,
  151. opacity: 1
  152. });
  153. } else if (this.type == "top") {
  154. this.animationParsing({
  155. defaulTranslateY: -1,
  156. translateY: 0,
  157. opacity: 1
  158. });
  159. this.popupBottom = "0rpx";
  160. if(this.offset > 0){
  161. this.popupTop = (this.offset + this.getPxRpx(this.systemInfo.statusBarHeight)) + "rpx";
  162. this.maskTop = this.popupTop;
  163. } else {
  164. this.popupTop = "0rpx";
  165. this.maskTop = "0rpx";
  166. }
  167. }
  168. });
  169. });
  170. },
  171. setAnimationHide() {
  172. this.timer && clearTimeout(this.timer);
  173. this.timer = setTimeout(() => {
  174. this.currentValue = false;
  175. this.$emit("input", false);
  176. this.$emit("change", false);
  177. }, 300);
  178. if (this.type == "bottom") {
  179. this.animationParsing({
  180. defaulTranslateY: 0,
  181. translateY: 1,
  182. opacity: 0
  183. });
  184. this.timer = setTimeout(() => {
  185. this.popupTop = "inherit";
  186. this.popupBottom = "0rpx";
  187. this.maskTop = "0rpx";
  188. this.maskBottom = "0rpx";
  189. },300);
  190. } else if (this.type == "center") {
  191. this.popupTop = "0rpx";
  192. this.popupBottom = "0rpx";
  193. this.animationParsing({
  194. scale: 0,
  195. defaulScale: 1,
  196. opacity: 0
  197. });
  198. } else if (this.type == "top") {
  199. this.animationParsing({
  200. defaulTranslateY: 0,
  201. translateY: -1,
  202. opacity: 0
  203. });
  204. this.timer = setTimeout(() => {
  205. this.popupTop = "0rpx";
  206. this.popupBottom = "inherit";
  207. this.maskTop = "0rpx";
  208. this.maskBottom = "0rpx";
  209. }, 300);
  210. }
  211. },
  212. animationParsing(data){
  213. // #ifndef APP-NVUE
  214. let transform = "";
  215. if(data.hasOwnProperty("translateX")){
  216. transform += " translateX("+ (data.translateX * 100) +"%)"
  217. }
  218. if(data.hasOwnProperty("translateY")){
  219. transform += " translateY("+ (data.translateY * 100) +"%)"
  220. }
  221. if(data.hasOwnProperty("scale")){
  222. transform += " scale("+ data.scale +")"
  223. }
  224. this.opacity = data.opacity;
  225. this.transform = transform;
  226. // #endif
  227. // #ifdef APP-NVUE
  228. let popupContainer = this.$refs.popupContainer;
  229. if(popupContainer){
  230. // if(data.hasOwnProperty("defaulTranslateY") || data.hasOwnProperty("defaulScale")){
  231. // let defaulTransform = "";
  232. // if(data.hasOwnProperty("defaulTranslateY")){
  233. // defaulTransform = "translateY(" + (data.defaulTranslateY * 100) + "%)";
  234. // }
  235. // if(data.hasOwnProperty("defaulScale")){
  236. // defaulTransform = "scale(" + data.defaulScale + ")";
  237. // }
  238. // this.transform = defaulTransform;
  239. // }
  240. if(Array.isArray(popupContainer)){
  241. popupContainer = popupContainer[0];
  242. }
  243. let transform = "";
  244. if(data.hasOwnProperty("translateX") || data.hasOwnProperty("translateY")){
  245. transform += " translate("+ (data.translateX ? data.translateX * 100 : 0) +"%, " + (data.translateY ? data.translateY * 100 : 0) + "%)";
  246. }
  247. if(data.hasOwnProperty("scale")){
  248. transform += " scale("+ data.scale +")"
  249. }
  250. animation.transition(popupContainer, {
  251. styles: {
  252. transform: transform,
  253. transformOrigin: 'center center',
  254. opacity: data.opacity,
  255. },
  256. duration: 300, //ms
  257. timingFunction: 'ease',
  258. delay: 0 //ms
  259. }, function () { });
  260. }
  261. // #endif
  262. },
  263. }
  264. };
  265. </script>
  266. <style lang="scss" scoped>
  267. .popup_view {
  268. position: fixed;
  269. z-index: 500;
  270. top: 0;
  271. right: 0;
  272. left: 0;
  273. bottom: 0;
  274. /* #ifndef APP-NVUE */
  275. display: flex;
  276. /* #endif */
  277. flex-direction: row;
  278. }
  279. .popup_view_bottom {
  280. align-items: flex-end;
  281. justify-content: center;
  282. }
  283. .popup_view_top {
  284. align-items: flex-start;
  285. justify-content: center;
  286. }
  287. .popup_view_center {
  288. align-items: center;
  289. justify-content: center;
  290. }
  291. /*遮罩层*/
  292. .popup_mask {
  293. position: absolute;
  294. top: 0;
  295. right: 0;
  296. left: 0;
  297. bottom: 0;
  298. background: rgba(0, 0, 0, 0.5);
  299. }
  300. .popup_container {
  301. /* #ifndef APP-NVUE */
  302. max-width: 100vw;
  303. max-height: 100vh;
  304. min-height: 50rpx;
  305. transition: all 0.4s;
  306. z-index: 2;
  307. /* #endif */
  308. z-index: 501;
  309. opacity: 0;
  310. font-size: 28rpx;
  311. position: relative;
  312. overflow: hidden;
  313. }
  314. .popup_container_bottom {
  315. transform: translateY(100%);
  316. width: 750rpx;
  317. }
  318. .popup_container_center {
  319. }
  320. .popup_container_top {
  321. transform: translateY(-100%);
  322. width: 750rpx;
  323. }
  324. </style>