custom-nav.vue 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. <template>
  2. <view class="custom-nav" v-show="title" :class="{ transparent: transparent, hide: !title }">
  3. <navigator open-type="navigateBack" v-if="!noback" class="back" :class="bangs ? 'bangs' : ''" @tap="tapLeft">
  4. <text class="cuIcon-back"></text>
  5. </navigator>
  6. <view class="center" :class="bangs ? 'bangs' : ''" @tap="tapCenter">
  7. <text>{{ title }}</text>
  8. </view>
  9. <view class="right" :class="{ bangs: bangs, color: color }" @tap="tapRight">
  10. <slot></slot>
  11. </view>
  12. <view v-if="LOADING" class="loading" @tap.stop="">
  13. <view class="loading-wrapper">
  14. <text class="cuIcon-loading1"></text>
  15. </view>
  16. </view>
  17. <view v-if="modalShow" class="custom-modal" :class="modalShow && modalAsync ? 'in' : 'out'">
  18. <view class="modal" :class="modalShow && modalAsync ? 'in' : 'out'">
  19. <view class="title">{{ modalTitle }}</view>
  20. <view class="message">
  21. <view v-for="(item, index) in modalMessages" :key="index">{{ item }}</view>
  22. </view>
  23. <view class="btn">
  24. <text v-if="!modalNoCancel" @tap="modalCancel" class="cancel">取消</text>
  25. <text @tap="modalConfire" class="confire">确定</text>
  26. </view>
  27. </view>
  28. </view>
  29. <view v-if="toastMessage" class="custom-toast" :class="{ 'toast-in': toastMessage }" :style="{ top: toastTop ? toastTop : '50%' }">{{ toastMessage }}</view>
  30. </view>
  31. </template>
  32. <script>
  33. import Vue from 'vue'
  34. const eventBUS = new Vue()
  35. export default {
  36. props: {
  37. color: String,
  38. title: String,
  39. noback: String,
  40. transparent: String
  41. },
  42. data() {
  43. return {
  44. LOADING: false,
  45. modalTitle: '', // 提示标题
  46. modalMessages: [], // 提示信息
  47. modalAsync: true, // 延迟消失
  48. modalShow: false, // 是否显示 modal
  49. modalNoCancel: false, // 是否显示取消按钮
  50. toastMessage: '', // toast 消息提示
  51. toastTop: '', // toast 位置
  52. }
  53. },
  54. computed: {
  55. bangs() { return this.$store.state.device.bangs }
  56. },
  57. created() {
  58. uni.$on('HIDELOADING', () => {
  59. this.hideLoading()
  60. })
  61. uni.$on('TOAST', (msg) => {
  62. this.toast(msg)
  63. })
  64. uni.$on('UPDATAAPP', path => {
  65. this.modal('提示', ['新版本已经下载成功,现在安装'], 'noCancel').then(() => {
  66. plus.runtime.install(path)
  67. })
  68. })
  69. },
  70. methods: {
  71. tapLeft() {
  72. this.$emit('lTap')
  73. },
  74. tapCenter() {
  75. this.$emit('cTap')
  76. },
  77. tapRight() {
  78. this.$emit('rTap')
  79. },
  80. loading() {
  81. this.LOADING = true
  82. },
  83. hideLoading() {
  84. this.LOADING = false
  85. },
  86. modalCancel() { // modal点击取消
  87. eventBUS.$emit('cancel')
  88. },
  89. modalConfire() { // modal点击确定
  90. eventBUS.$emit('confire')
  91. },
  92. modal(title, message, noCancel) { // 弹出 modal
  93. noCancel ? this.modalNoCancel = true : ''
  94. this.modalShow = true
  95. this.modalTitle = title
  96. this.modalMessages = message
  97. const that = this
  98. return new Promise((resolve, reject) => {
  99. eventBUS.$on('confire', () => {
  100. resolve()
  101. that.close()
  102. })
  103. eventBUS.$on('cancel', () => {
  104. reject()
  105. that.close()
  106. })
  107. })
  108. },
  109. close() { // 关闭 modal
  110. this.modalAsync = false
  111. setTimeout(e => {
  112. this.modalShow = false
  113. this.modalAsync = true
  114. }, 200)
  115. },
  116. toast(message, position) {
  117. if (position === 'bottom') {
  118. this.toastTop = '80%'
  119. }
  120. this.toastMessage = ''
  121. this.toastMessage = message
  122. setTimeout(() => this.toastTop = this.toastMessage = '', 2345);
  123. }
  124. }
  125. }
  126. </script>
  127. <style lang="scss" scoped>
  128. .custom-nav {
  129. top: 0;
  130. left: 0;
  131. z-index: 2;
  132. width: 100%;
  133. @include flex();
  134. position: fixed;
  135. font-size: 40rpx;
  136. background: #FFFFFF;
  137. box-sizing: border-box;
  138. height: $app-nav-height;
  139. box-shadow: 0px 1px 0px 0px rgba(178, 178 ,178 ,1);
  140. &.transparent {
  141. height: 0;
  142. overflow: hidden;
  143. box-shadow: none;
  144. background: transparent;
  145. border-top-color: transparent;
  146. }
  147. &.hide {
  148. height: 0!important;
  149. box-shadow: 0px 0px 0px 0px #FFFFFF;
  150. }
  151. .back {
  152. width: 88rpx;
  153. height: 100%;
  154. color: #333333;
  155. @include flex(column);
  156. justify-content: flex-end;
  157. text {
  158. margin-bottom: 24rpx;
  159. }
  160. &.bangs {
  161. text {
  162. margin-bottom: 12rpx;
  163. }
  164. }
  165. }
  166. .center {
  167. flex: 1;
  168. height: 100%;
  169. text {
  170. left: 50%;
  171. bottom: 24rpx;
  172. position: absolute;
  173. transform: translateX(-50%);
  174. }
  175. &.bangs {
  176. text {
  177. bottom: 12rpx;
  178. }
  179. }
  180. }
  181. .right {
  182. @include flex(column);
  183. height: 100%;
  184. width: 180rpx;
  185. font-size: 28rpx;
  186. padding-bottom: 28rpx;
  187. align-items: flex-end;
  188. box-sizing: border-box;
  189. justify-content: flex-end;
  190. color: $app-main-text-color;
  191. &.color {
  192. color: $app-base-color;
  193. }
  194. &.bangs {
  195. padding-bottom: 16rpx;
  196. }
  197. }
  198. .loading {
  199. @include flex();
  200. top: 0;
  201. left: 0;
  202. right: 0;
  203. bottom: 0;
  204. z-index: 666;
  205. position: fixed;
  206. .loading-wrapper {
  207. @include flex();
  208. top: 50%;
  209. left: 50%;
  210. width: 120rpx;
  211. height: 120rpx;
  212. color: #FFFFFF;
  213. font-size: 60rpx;
  214. position: absolute;
  215. border-radius: 8rpx;
  216. background: rgba(0, 0, 0, .6);
  217. transform: translate(-50%, -50%);
  218. text {
  219. animation: loading .6s infinite linear;
  220. }
  221. }
  222. }
  223. .custom-modal {
  224. @include flex();
  225. top: 0;
  226. left: 0;
  227. right: 0;
  228. bottom: 0;
  229. z-index: 999;
  230. position: fixed;
  231. background: rgba(1, 1, 1, .4);
  232. &.in {
  233. animation: bg-in .2s;
  234. animation-fill-mode: forwards;
  235. }
  236. &.out {
  237. animation: bg-out .2s;
  238. animation-fill-mode: forwards;
  239. }
  240. .modal {
  241. @include flex(column);
  242. width: 80%;
  243. min-height: 25%;
  244. border-radius: 8rpx;
  245. background: #FFFFFF;
  246. &.in {
  247. animation: modal-in .2s;
  248. animation-fill-mode: forwards;
  249. }
  250. &.out {
  251. animation: modal-out .2s;
  252. animation-fill-mode: forwards;
  253. }
  254. .title {
  255. @include flex();
  256. width: 100%;
  257. height: 100rpx;
  258. font-size: 42rpx;
  259. color: $app-base-color;
  260. }
  261. .message {
  262. @include flex(column);
  263. flex: 1;
  264. width: 100%;
  265. padding: 30rpx;
  266. font-size: 32rpx;
  267. box-sizing: border-box;
  268. border-top: 2rpx solid #EEEEEE;
  269. border-bottom: 2rpx solid #EEEEEE;
  270. view {
  271. @include flex();
  272. flex: 1;
  273. width: 100%;
  274. margin: 8rpx 0;
  275. text-align: center;
  276. }
  277. }
  278. .btn {
  279. @include flex();
  280. width: 100%;
  281. height: 100rpx;
  282. text {
  283. @include flex();
  284. flex: 1;
  285. height: 100%;
  286. font-size: 32rpx;
  287. color: $app-base-color;
  288. &.cancel {
  289. color: $app-sec-text-color;
  290. border-right: 2rpx solid #EEEEEE;
  291. }
  292. }
  293. }
  294. }
  295. }
  296. .custom-toast {
  297. top: 50%;
  298. left: 50%;
  299. z-index: 999;
  300. color: #FFFFFF;
  301. position: fixed;
  302. font-size: 28rpx;
  303. max-width: 700rpx;
  304. text-align: center;
  305. line-height: 42rpx;
  306. border-radius: 8rpx;
  307. padding: 10rpx 20rpx;
  308. background: rgba(0, 0, 0, .6);
  309. transform: translate(-50%, -50%);
  310. &.toast-in {
  311. animation: toast-in .2s;
  312. animation-fill-mode: forwards;
  313. }
  314. }
  315. }
  316. @keyframes loading {
  317. 0% { transform: rotateZ(0deg); }
  318. 100% { transform: rotateZ(360deg); }
  319. }
  320. @keyframes bg-in {
  321. 0% { background: rgba(0, 0, 0, 0) }
  322. 100% { background: rgba(0, 0, 0, .4) }
  323. }
  324. @keyframes bg-out {
  325. 0% { background: rgba(0, 0, 0, .4) }
  326. 100% { background: rgba(0, 0, 0, 0) }
  327. }
  328. @keyframes modal-in {
  329. 0% { transform: scale(0, 0); }
  330. 100% { transform: scale(1, 1); }
  331. }
  332. @keyframes modal-out {
  333. 0% { transform: scale(1, 1); }
  334. 100% { transform: scale(0, 0); }
  335. }
  336. @keyframes toast-in {
  337. 0% { opacity: 0; }
  338. 100% { opacity: 1; }
  339. }
  340. </style>