xuan-popup.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. <!--
  2. *属性 isdistance 每个弹窗之间是否有间距
  3. *数组形式传值
  4. *type,类型 success warn info err loading(string)
  5. *content,内容(string)
  6. *timeout,消失时间(Number)
  7. *isClick,是否点击消失(Boolean)
  8. -->
  9. <template>
  10. <view class="popup_list">
  11. <view v-for="(items,index) of popup_list" :id="items.uuid" :key="items.uuid" >
  12. <view class="mpopup" :style="{ background: items.color ,top:index*distance+45+'px'}" :class="[items.animator,items.typeClass]" @click="close(items.uuid,index)">
  13. <view class="pic"><image class="icon" mode="aspectFit" :src="items.icon"></image></view>
  14. <text class="text" :style="{ color: items.colortext }">{{ items.content }}</text>
  15. </view>
  16. </view>
  17. </view>
  18. </template>
  19. <script>
  20. export default{
  21. data(){
  22. return{
  23. popup_list:[],//弹窗数组
  24. distance:65//每个弹窗之间间距
  25. }
  26. },
  27. props:{
  28. //是否有间距
  29. isdistance:{
  30. type:Boolean,
  31. default:true
  32. },
  33. },
  34. methods:{
  35. init:function(list){
  36. if (list.type == 'success') {
  37. list.icon = '../../static/xuan-popup/success.png';
  38. list.typeClass='mpopup-success';
  39. return list;
  40. }
  41. if (list.type == 'warn') {
  42. list.icon = '../../static/xuan-popup/warn.png';
  43. list.typeClass='mpopup-warn';
  44. return list;
  45. }
  46. if (list.type == 'info') {
  47. list.icon = '../../static/xuan-popup/info.png';
  48. list.typeClass='mpopup-info';
  49. return list;
  50. }
  51. if (list.type == 'err') {
  52. list.icon = '../../static/xuan-popup/err.png';
  53. list.typeClass='mpopup-err';
  54. return list;
  55. }
  56. if (list.type == 'loading') {
  57. list.icon = '../../static/xuan-popup/loading.png';
  58. list.typeClass='mpopup-loading';
  59. return list;
  60. }
  61. },
  62. open:function(list){
  63. if(!this.isdistance){this.distance=0}
  64. //生成uuid
  65. let uuid=this.guid();
  66. list.uuid=uuid;
  67. //添加动画
  68. list.animator='fade_Down';
  69. //判断是否可点击消失/可控制消失
  70. if(typeof(list.isClick)!='boolean'){list.isClick=false;}
  71. //if(typeof(list.isControl)!='boolean'){list.isControl=false;}
  72. //初始化
  73. let new_list=this.init(list);
  74. //添加进数组
  75. this.popup_list.push(new_list);
  76. if(!new_list.isClick){
  77. this.disappear(new_list.uuid,new_list.timeout);
  78. }//可点击消失
  79. else{
  80. this.$emit('uuidCallback',new_list.uuid);
  81. }
  82. // else if(new_list.isControl){
  83. // this.$emit('Callback',new_list.uuid);
  84. // }
  85. },
  86. //自动消失
  87. disappear:function(uuid,timeout){
  88. //退出动画之后,短暂延迟后移除本元素
  89. this.fade_out_animator(uuid,timeout).then(res=>{
  90. setTimeout(()=>{
  91. for(let i=0;i<this.popup_list.length;i++){
  92. if(this.popup_list[i].uuid==res){
  93. //移除本元素
  94. this.popup_list.splice(i,1);
  95. this.$forceUpdate()
  96. }
  97. }
  98. },250)
  99. });
  100. },
  101. fade_out_animator:function(uuid,timeout){
  102. //timeout秒后退出
  103. if(!timeout||typeof(timeout)!='number'){timeout=3000;}
  104. return new Promise(res=>{
  105. setTimeout(()=>{
  106. for(let i=0;i<this.popup_list.length;i++){
  107. if(this.popup_list[i].uuid==uuid){
  108. //添加退出动画
  109. this.popup_list[i].animator='fade_Top';
  110. res(uuid);
  111. }
  112. }
  113. },timeout)
  114. })
  115. },
  116. //可控制关闭的弹出框
  117. close:function(uuid,ind){
  118. if(ind){
  119. if(!this.popup_list[ind].isClick){return}
  120. }
  121. this.remove_element(uuid).then((res)=>{
  122. setTimeout(()=>{
  123. for(let i=0;i<this.popup_list.length;i++){
  124. if(this.popup_list[i].uuid==res){
  125. //移除本元素
  126. this.popup_list.splice(i,1);
  127. this.$emit('closeCallback',uuid);
  128. this.$forceUpdate()
  129. }
  130. }
  131. },250)
  132. })
  133. },
  134. //控制移除元素
  135. remove_element:function(uuid){
  136. return new Promise(res=>{
  137. for (var i = 0; i < this.popup_list.length; i++) {
  138. if(this.popup_list[i].uuid==uuid){
  139. this.popup_list[i].animator='fade_Top';
  140. res(uuid)
  141. break;
  142. }
  143. }
  144. })
  145. },
  146. //更新
  147. update:function(update_list){
  148. for (var i = 0; i < this.popup_list.length; i++) {
  149. if(this.popup_list[i].uuid==update_list.uuid){
  150. this.popup_list[i].type=update_list.type;
  151. this.init(this.popup_list[i]);
  152. this.popup_list[i].content=update_list.content;
  153. break;
  154. }
  155. }
  156. },
  157. //生成uuid
  158. guid:function() {
  159. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
  160. var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
  161. return v.toString(16);
  162. });
  163. }
  164. }
  165. }
  166. </script>
  167. <style lang="scss">
  168. .mpopup{
  169. display: flex;
  170. flex-direction: row;
  171. text-align: center;
  172. justify-content: center;
  173. align-items: center;
  174. min-height: 45px;
  175. width: 550rpx;
  176. transition :all .5s;
  177. position: fixed;
  178. left: 0;
  179. right: 0;
  180. margin: 0 auto;
  181. border-radius: 5px;
  182. z-index:998;
  183. .pic{
  184. display: flex;
  185. text-align: center;
  186. justify-content: center;
  187. width: 15px;
  188. height: 15px;
  189. margin: auto 20px auto 0;
  190. .icon{
  191. width: 100%;
  192. height: auto;
  193. }
  194. }
  195. .text{
  196. margin: auto 20px auto 0;
  197. width: 65%;
  198. font-size: 16px;
  199. }
  200. }
  201. .mpopup-success{
  202. background: #f0f9eb;
  203. border: 1px solid #e1f3d8;
  204. color: #67c23a;
  205. }
  206. .mpopup-err{
  207. background: #fef0f0;
  208. border: 1px solid #fde2e2;
  209. color: #f56c6c;
  210. }
  211. .mpopup-warn{
  212. background: #fdf6ec;
  213. border: 1px solid #faecd8;
  214. color: #e6a23c;
  215. }
  216. .mpopup-info{
  217. background: #edf2fc;
  218. border: 1px solid #ebeef5;
  219. color: #909399;
  220. }
  221. .mpopup-loading{
  222. background: #e2f5ff;
  223. border: 1px solid #ceeeff;
  224. color: #5cbaff;
  225. image{
  226. animation: rotate360 1.5s ease infinite;
  227. }
  228. }
  229. .fade_Down{
  230. animation: fadeInDown 0.6s both;
  231. }
  232. .fade_Top{
  233. animation: fadeInTop 0.5s forwards;
  234. }
  235. /*从上到下*/
  236. @keyframes fadeInDown
  237. {
  238. from {
  239. opacity: 0;
  240. -webkit-transform: translate(0,-100px);
  241. transform: stranslate(0,-100px);
  242. }
  243. to {
  244. opacity:1;
  245. -webkit-transform: translate(0,10px);
  246. transform: stranslate(0,10px);
  247. }
  248. }
  249. /*从下到上*/
  250. @keyframes fadeInTop
  251. {
  252. from {
  253. opacity:1;
  254. -webkit-transform: translate(0,10px);
  255. transform: stranslate(0,10px);
  256. }
  257. to {
  258. opacity: 0;
  259. -webkit-transform: translate(0,-100px);
  260. transform: stranslate(0,-100px);
  261. }
  262. }
  263. @keyframes rotate360
  264. {
  265. from {
  266. transform: rotate(0);
  267. }
  268. to{
  269. transform: rotate(360deg);
  270. }
  271. }
  272. </style>