tm-poup.vue 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. <template>
  2. <view class="tm-poups " @click.stop="">
  3. <block v-if="position_sv != 'center'">
  4. <view v-show="value==true&&position_sv != 'center'" class="tm-poup " :class="[
  5. isFilter?'blur':'',
  6. position_sv == 'center' ? 'tm-poup-center' : '',
  7. position_sv !='center'?position_sv:'',
  8. isClickbled?'isClickbled':''
  9. ]" @click.stop.prevent="overClick" @touchmove.stop.prevent="stopMove" :style="{
  10. backgroundColor: overColor,
  11. width:'100%',height:'100%'
  12. }">
  13. <!-- 内容 -->
  14. <!-- <view class="tm-poup-wk bottom">{{ show ? 'on' : 'off'}}</view> -->
  15. <scroll-view :animation="aniData" @click.stop.prevent="" class="tm-poup-wk dhshiKa" scroll-y="true" :class="[
  16. position_sv == 'top'?'round-b-' + round:'',
  17. position_sv == 'bottom'?'round-t-' + round:'',
  18. position_sv, aniOn ? 'on ' : 'off',
  19. black_tmeme ? 'grey-darken-5 bk' : bgColor
  20. ]" :style="{
  21. width: (position_sv == 'top' || position_sv == 'bottom') ? '100%' : width_w,
  22. height: position_sv == 'right' || position_sv == 'left' ?'100%' : height_h,
  23. }">
  24. <view :class="[clssStyle]" >
  25. <slot></slot>
  26. </view>
  27. </scroll-view>
  28. </view>
  29. </block>
  30. <view v-if="value===true&&position_sv == 'center'" class="tm-poup " :class="[
  31. isFilter?'blur':'',
  32. position_sv == 'center' ? 'tm-poup-center' : ''
  33. ]" @click="overClick" @touchmove.stop.prevent="stopMove" :style="{
  34. backgroundColor: overColor,
  35. width:sysInfo.screenWidth+'px',height:'100%'
  36. }">
  37. <!-- 内容 -->
  38. <scroll-view :animation="aniData" @click.stop.prevent="" class="tm-poup-wk " scroll-y="true" :class="[
  39. `round-${round}`,aniOn ? 'on' : 'off', position_sv,
  40. black_tmeme ? 'grey-darken-5 bk' : bgColor
  41. ]" :style="{
  42. width: width_w,
  43. height: height_h
  44. }">
  45. <view :class="[clssStyle]">
  46. <slot></slot>
  47. </view>
  48. </scroll-view>
  49. </view>
  50. </view>
  51. </template>
  52. <script>
  53. /**
  54. * poup弹出层
  55. * @description poup弹出层,上下,左右方向。
  56. * @property {Boolean} value = [true|false] 使用时value.sync可同步,也可不同步。等同于v-model
  57. * @property {Boolea} v-model 显示和关闭。
  58. * @property {String} position = [bottom|top|left|right|center] 方向可选bottom,left,right,top,center
  59. * @property {Function} change 改变时会调用此函数,参数e等同于v-model和value
  60. * @property {String|Number} width 宽,位置为left,right是起作用。可以是30%或者数字(单位upx)
  61. * @property {String|Number} height 宽,位置为top,bottom是起作用。可以是30%或者数字(单位upx)
  62. * @property {String|Number} round 圆角0-25
  63. * @property {String|Boolean} black = [true|false] 暗黑模式
  64. * @property {Boolean} over-close = [true|false] 是否点击遮罩关闭。
  65. * @property {Boolean} is-filter = [true|false] 是否背景模糊
  66. * @property {String} clss-style = [] 自定内容的类
  67. * @property {String} bg-color = [white|blue] 默认:white,白色背景;请填写背景的主题色名称。
  68. * @property {String} over-color = [] 默认:rgba(0,0,0,0.3), 遮罩层颜色值不是主题。
  69. * @example <tm-poup height="85%" v-model="show"></tm-poup>
  70. */
  71. export default {
  72. name: 'tm-poup',
  73. props: {
  74. bgColor: {
  75. type: String,
  76. default: 'white'
  77. },
  78. // 遮罩层颜色。
  79. overColor: {
  80. type: String,
  81. default: 'rgba(0,0,0,0.3)'
  82. },
  83. black: {
  84. type: Boolean | String,
  85. default: null
  86. },
  87. clssStyle: {
  88. type: String,
  89. default: ''
  90. },
  91. value: {
  92. type: Boolean,
  93. default: false
  94. },
  95. // bottom,left,right,top
  96. position: {
  97. type: String,
  98. default: 'bottom'
  99. },
  100. round: {
  101. type: String | Number,
  102. default: '10'
  103. },
  104. width: {
  105. type: String | Number,
  106. default: '30%'
  107. },
  108. height: {
  109. type: String | Number,
  110. default: 220
  111. },
  112. overClose: {
  113. type: Boolean,
  114. default: true
  115. },
  116. isFilter: {
  117. type: Boolean,
  118. default: true,
  119. },
  120. //允许穿透背景遮罩。
  121. isClickbled: {
  122. type: Boolean,
  123. default: false
  124. }
  125. },
  126. model: {
  127. prop: 'value',
  128. event: 'input',
  129. sysInfo: {},
  130. },
  131. watch: {
  132. value:function(val){
  133. this.$emit('change', val);
  134. if(val){
  135. this.open()
  136. }else{this.close()}
  137. },
  138. position: function() {
  139. this.position_sv = this.position
  140. }
  141. },
  142. created() {
  143. this.sysInfo = uni.getSystemInfoSync();
  144. },
  145. computed: {
  146. black_tmeme: function() {
  147. if (this.black !== null) return this.black;
  148. return this.$tm.vx.state().tmVuetify.black;
  149. },
  150. width_w: function() {
  151. let w = this.$TestUnit(this.width);
  152. let i = w.value;
  153. if (w.type == 'number') {
  154. i = w.value + 'px';
  155. }
  156. return i;
  157. },
  158. height_h: function() {
  159. let w = this.$TestUnit(this.height);
  160. let i = w.value;
  161. if (w.type == 'number') {
  162. i = w.value + 'px';
  163. }
  164. return i;
  165. },
  166. },
  167. data() {
  168. return {
  169. aniOn: false,
  170. closeTimid: null,
  171. position_sv: this.position,
  172. dhshiKa:true,//是否结束动画
  173. aniData:null,
  174. timdiiid:6369784254,
  175. };
  176. },
  177. deactivated() {
  178. clearTimeout(this.closeTimid)
  179. },
  180. destroyed() {
  181. clearTimeout(this.closeTimid)
  182. },
  183. mounted() {
  184. if(this.value){
  185. this.open()
  186. }
  187. },
  188. methods: {
  189. overClick() {
  190. if (!this.overClose) return;
  191. this.close();
  192. },
  193. close() {
  194. let t = this;
  195. clearTimeout(this.timdiiid)
  196. this.dhshiKa=false;
  197. t.aniOn=false;
  198. this.createBtT(this.position_sv,'off').then(()=>{
  199. t.$emit('input', false);
  200. t.closeTimid = null;
  201. t.dhshiKa = true;
  202. // t.$emit('change', false);
  203. // console.log('off');
  204. })
  205. },
  206. open() {
  207. let t = this;
  208. clearTimeout(this.timdiiid)
  209. this.dhshiKa=false
  210. this.aniOn=true;
  211. this.createBtT(this.position_sv,'on').then(()=>{
  212. t.dhshiKa=true
  213. t.isclick=false
  214. // console.log('on');
  215. })
  216. },
  217. //下至上。
  218. createBtT(pos,type){
  219. let t = this;
  220. this.aniData = '';
  221. let aniData = uni.createAnimation({
  222. duration:240,
  223. timingFunction: 'linear',
  224. })
  225. this.aniData = aniData;
  226. if(pos=='bottom'){
  227. if(type=='on'){
  228. aniData.translateY('0%').step();
  229. this.aniData = aniData.export()
  230. }
  231. if(type=='off'){
  232. aniData.translateY('100%').step();
  233. this.aniData = aniData.export()
  234. }
  235. }else if(pos=='top'){
  236. if(type=='on'){
  237. aniData.translateY('0%').step();
  238. this.aniData = aniData.export()
  239. }
  240. if(type=='off'){
  241. aniData.translateY('-100%').step();
  242. this.aniData = aniData.export()
  243. }
  244. }else if(pos=='left'){
  245. if(type=='on'){
  246. aniData.translateX('0%').step();
  247. this.aniData = aniData.export()
  248. }
  249. if(type=='off'){
  250. aniData.translateX('-100%').step();
  251. this.aniData = aniData.export()
  252. }
  253. }else if(pos=='right'){
  254. if(type=='on'){
  255. aniData.translateX('0%').step();
  256. this.aniData = aniData.export()
  257. }
  258. if(type=='off'){
  259. aniData.translateX('100%').step();
  260. this.aniData = aniData.export()
  261. }
  262. }else if(pos=='center'){
  263. if(type=='on'){
  264. aniData.opacity(1).scale(1).step();
  265. this.aniData = aniData.export()
  266. }
  267. if(type=='off'){
  268. aniData.opacity(0).scale(0.6).step();
  269. this.aniData = aniData.export()
  270. }
  271. }
  272. return new Promise(res=>{
  273. t.timdiiid = setTimeout(()=>{
  274. t.aniData = null;
  275. res();
  276. },240)
  277. })
  278. },
  279. stopMove(e) {}
  280. }
  281. };
  282. </script>
  283. <style lang="scss" scoped>
  284. .tm-poup {
  285. position: fixed;
  286. z-index: 452;
  287. width: 100%;
  288. height: 100%;
  289. min-height: 100%;
  290. min-width: 100%;
  291. overflow: hidden;
  292. top: 0;
  293. left: 0;
  294. &.isClickbled {
  295. pointer-events: none;
  296. }
  297. &.okkk{
  298. pointer-events: none;
  299. }
  300. &.blur {
  301. backdrop-filter: blur(10px);
  302. }
  303. &.on {
  304. animation: opta 1s linear;
  305. }
  306. &.off {
  307. animation: opta_off 0.35s linear;
  308. }
  309. .tm-poup-wk {
  310. position: absolute;
  311. overflow: hidden;
  312. pointer-events: auto;
  313. // transition: all 0.3s;
  314. &.bottom {
  315. transform: translateY(100%);
  316. width: 100%;
  317. bottom: 0;
  318. }
  319. &.top {
  320. top: 0;
  321. left: 0;
  322. width: 100%;
  323. transform: translateY(-100%);
  324. }
  325. &.left {
  326. top: 0;
  327. transform: translateX(-100%);
  328. border-radius: 0 !important;
  329. left: 0;
  330. }
  331. &.right {
  332. top: 0;
  333. right: 0;
  334. transform: translateX(100%);
  335. border-radius: 0 !important;
  336. }
  337. &.center {
  338. opacity:0;
  339. transform: scale(0.6);
  340. }
  341. }
  342. &.tm-poup-center {
  343. display: flex;
  344. justify-content: center;
  345. align-items: center;
  346. align-content: center;
  347. .tm-poup-wk {
  348. position: static;
  349. }
  350. }
  351. }
  352. @keyframes opta {
  353. from {
  354. opacity: 0.6;
  355. }
  356. to {
  357. opacity: 1;
  358. }
  359. }
  360. @keyframes opta_off {
  361. from {
  362. opacity: 1;
  363. }
  364. to {
  365. opacity: 0;
  366. }
  367. }
  368. @keyframes bottomTtop {
  369. from {
  370. transform: translateY(100%);
  371. }
  372. to {
  373. transform: translateY(0%);
  374. }
  375. }
  376. @keyframes bottomTtop_off {
  377. from {
  378. transform: translateY(0%);
  379. }
  380. to {
  381. transform: translateY(100%);
  382. }
  383. }
  384. @keyframes topTbottom {
  385. from {
  386. transform: translateY(-100%);
  387. }
  388. to {
  389. transform: translateY(0);
  390. }
  391. }
  392. @keyframes topTbottom_off {
  393. from {
  394. transform: translateY(0);
  395. }
  396. to {
  397. transform: translateY(-100%);
  398. }
  399. }
  400. @keyframes leftTright {
  401. from {
  402. transform: translateX(-100%);
  403. }
  404. to {
  405. transform: translateX(0);
  406. }
  407. }
  408. @keyframes leftTright_off {
  409. from {
  410. transform: translateX(0);
  411. }
  412. to {
  413. transform: translateX(-100%);
  414. }
  415. }
  416. @keyframes rightTleft {
  417. from {
  418. transform: translateX(100%);
  419. }
  420. to {
  421. transform: translateX(0%);
  422. }
  423. }
  424. @keyframes rightTleft_off {
  425. from {
  426. transform: translateX(0%);
  427. }
  428. to {
  429. transform: translateX(100%);
  430. }
  431. }
  432. @keyframes Centerleft {
  433. from {
  434. transform: scale(0.65);
  435. opacity: 0.65;
  436. }
  437. to {
  438. transform: scale(1);
  439. opacity: 1;
  440. }
  441. }
  442. @keyframes Centerleft_off {
  443. from {
  444. transform: scale(1);
  445. opacity: 1;
  446. }
  447. to {
  448. transform: scale(0.65);
  449. opacity: 0.65;
  450. }
  451. }
  452. </style>