index.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <template>
  2. <view class="wrap" :class="{'wrap-shadow': shadow}">
  3. <StatusBar />
  4. <view class="nav-bar-wrap" :style="[getNavWrapStyle]">
  5. <!-- 状态栏高度 -->
  6. <view class="nav-bar flex">
  7. <view class="nav-bar_left" v-if="!hideLeft">
  8. <slot name='left'>
  9. <view class="left-btns" :class="{ 'left-btns_home': onlyHome || (!getIsHome && !onlyBack), 'left-btns_only-back': onlyBack && !onlyHome }">
  10. <view class="back" hover-class="hover-active" @click="go('back')">
  11. <image src="https://cdn.aliyinba.com/UploadFiles/shop2/number/nav_bar/nav-back.png" mode="aspectFill"></image>
  12. </view>
  13. <view class="home" hover-class="hover-active" @click="go('home')">
  14. <image src="https://cdn.aliyinba.com/UploadFiles/shop2/number/nav_bar/nav-home.png" mode="aspectFill"></image>
  15. </view>
  16. </view>
  17. </slot>
  18. </view>
  19. <view class="nav-bar_content flex flex-center flex-1 w-0" :class="{'right-slot': ifShowRight}" :style="[getNavBarContent]">
  20. <view class="nav-bar_content_title flex-1 w-0 ellipsis">
  21. <slot name="title">{{ title }}</slot>
  22. </view>
  23. <view class="nav-bar_content_right" v-if="ifShowRight">
  24. <slot name="right">
  25. <text>右侧插槽</text>
  26. <!-- <image class="warn-icon" :src="getFileUrl('/fault.png')" mode="aspectFill"></image> -->
  27. </slot>
  28. </view>
  29. </view>
  30. </view>
  31. </view>
  32. </view>
  33. </template>
  34. <script setup>
  35. import { computed, unref, useSlots } from 'vue'
  36. import StatusBar from "./StatusBar.vue"
  37. import { getFileUrl } from "@/utils/file.js";
  38. const systemInfo = uni.getWindowInfo();
  39. let menuButtonInfo = {}
  40. // #ifdef MP-WEIXIN
  41. menuButtonInfo = uni.getMenuButtonBoundingClientRect() // 右上角胶囊信息
  42. // #endif
  43. const emit = defineEmits(['back'])
  44. const props = defineProps({
  45. title: { type: String },
  46. hideLeft: { type: Boolean, default: false },
  47. onlyBack: { type: Boolean, default: false }, // 仅显示返回键,不显示首页
  48. onlyHome: { type: Boolean, default: false }, // 仅显示返回主页(首页)按钮,左上角永远回首页
  49. customBack: { type: Boolean, default: false }, // 为 true 时点击返回触发 @back,由父组件处理
  50. warn: { type: Boolean, default: false }, // 警告
  51. shadow: { type: Boolean, default: false }, // 警告
  52. })
  53. const slots = useSlots()
  54. // 是否显示返回首页
  55. const getIsHome = computed(() => {
  56. const pages = getCurrentPages(); // 获取路由栈
  57. return pages.length >= 2
  58. })
  59. // 是否显示右侧按钮
  60. const ifShowRight = computed(() => slots.right || props.warn)
  61. //
  62. const statusBarHeight = computed(() => systemInfo.statusBarHeight ?? 0)
  63. const statusH = unref(statusBarHeight)
  64. const menuTop = menuButtonInfo.top ?? statusH
  65. const menuRight = menuButtonInfo.right ?? ((systemInfo.windowWidth ?? 375) - 87)
  66. const menuHeight = menuButtonInfo.height ?? 32
  67. const menuWidth = menuButtonInfo.width ?? 87
  68. const gap = menuButtonInfo.top != null ? Math.max(0, menuTop - statusH) : 4
  69. const getNavWrapStyle = computed(() => {
  70. const w = systemInfo.windowWidth ?? 375
  71. const padRight = Math.max(0, w - menuRight)
  72. return {
  73. padding: `${gap}px ${padRight}px`,
  74. height: `${menuHeight + gap * 2}px`
  75. }
  76. })
  77. const getNavBarContent = computed(() => {
  78. const style = {}
  79. if(unref(ifShowRight)){
  80. style.paddingRight = menuWidth + 'px'
  81. }else{
  82. style.position = 'absolute'
  83. style.width = '100%'
  84. style.top = '0'
  85. style.bottom = '0'
  86. style.left = '0'
  87. style.zIndex = '0'
  88. style.padding = `0 ${menuWidth + 10}px`
  89. }
  90. return style
  91. })
  92. function go(type){
  93. switch (type){
  94. case 'back':
  95. if (props.customBack) {
  96. emit('back')
  97. } else {
  98. uni.navigateBack()
  99. }
  100. break;
  101. case 'home':
  102. // 首页为 tabBar 页面,用 switchTab
  103. uni.switchTab({ url: '/pages/index/index' });
  104. break;
  105. default:
  106. uni.navigateTo({ url: type })
  107. break;
  108. }
  109. }
  110. </script>
  111. <style scoped lang="scss">
  112. .wrap{
  113. position: sticky;
  114. z-index: 101;
  115. background: #ffffff;
  116. &-shadow{
  117. box-shadow: 0 1rpx 0 2rpx #F4F6FA;
  118. }
  119. .nav-bar-wrap{
  120. .nav-bar{
  121. height: 100%;
  122. position: relative;
  123. &_left{
  124. position: relative;
  125. z-index: 10;
  126. margin-right: 30rpx;
  127. flex: none;
  128. .left-btns{
  129. border-radius: 99rpx;
  130. background: #DDDDDD80;
  131. width: 182rpx;
  132. height: 100%;
  133. display: flex;
  134. align-items: center;
  135. &_home{
  136. width: 90rpx;
  137. .back{
  138. display: none !important;
  139. }
  140. }
  141. &_only-back{
  142. width: 90rpx;
  143. .home{
  144. display: none !important;
  145. }
  146. .back::after{
  147. display: none;
  148. }
  149. }
  150. .back, .home{
  151. flex: 1;
  152. width: 0;
  153. height: 100%;
  154. display: flex;
  155. justify-content: center;
  156. align-items: center;
  157. }
  158. .back{
  159. position: relative;
  160. &::after{
  161. position: absolute;
  162. right: 0;
  163. top: 50%;
  164. transform: translateY(-50%);
  165. content: ' ';
  166. display: block;
  167. clear: both;
  168. background: #CECECE80;
  169. width: 2rpx;
  170. height: 34rpx;
  171. }
  172. image{
  173. width: 18rpx;
  174. height: 32rpx;
  175. }
  176. }
  177. .home{
  178. image{
  179. width: 36rpx;
  180. height: 32rpx;
  181. }
  182. }
  183. }
  184. }
  185. &_content{
  186. &.right-slot{
  187. .nav-bar_content_title{
  188. text-align: left !important;
  189. }
  190. }
  191. &_title{
  192. text-align: center;
  193. font-size: 36rpx;
  194. color: #333333;
  195. }
  196. &_right{
  197. flex: none;
  198. display: flex;
  199. align-items: center;
  200. margin: 0 26rpx;
  201. }
  202. }
  203. }
  204. }
  205. }
  206. </style>