tm-poup.vue 10 KB

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