index.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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) // 状态栏高度
  63. const getNavWrapStyle = computed(() => {
  64. const { windowWidth } = systemInfo
  65. const { top, right, height } = menuButtonInfo
  66. return {
  67. padding: `${top - unref(statusBarHeight)}px ${windowWidth - right}px`,
  68. height: `${height + (top - unref(statusBarHeight)) * 2}px`
  69. }
  70. })
  71. const getNavBarContent = computed(() => {
  72. const { width } = menuButtonInfo
  73. const style = {}
  74. if(unref(ifShowRight)){
  75. style.paddingRight = width + 'px'
  76. }else{
  77. style.position = 'absolute'
  78. style.width = '100%'
  79. style.top = '0'
  80. style.bottom = '0'
  81. style.zIndex = '-1'
  82. style.padding = `0 ${width + 10}px`
  83. }
  84. return style
  85. })
  86. function go(type){
  87. switch (type){
  88. case 'back':
  89. if (props.customBack) {
  90. emit('back')
  91. } else {
  92. uni.navigateBack()
  93. }
  94. break;
  95. case 'home':
  96. // 首页为 tabBar 页面,用 switchTab
  97. uni.switchTab({ url: '/pages/index/index' });
  98. break;
  99. default:
  100. uni.navigateTo({ url: type })
  101. break;
  102. }
  103. }
  104. </script>
  105. <style scoped lang="scss">
  106. .wrap{
  107. position: sticky;
  108. z-index: 101;
  109. &-shadow{
  110. box-shadow: 0 1rpx 0 2rpx #F4F6FA;
  111. }
  112. .nav-bar-wrap{
  113. padding:4px 8px;
  114. height:40px;
  115. .nav-bar{
  116. height: 100%;
  117. position: relative;
  118. &_left{
  119. margin-right: 30rpx;
  120. flex: none;
  121. .left-btns{
  122. border-radius: 99rpx;
  123. background: #DDDDDD80;
  124. width: 182rpx;
  125. height: 100%;
  126. display: flex;
  127. align-items: center;
  128. &_home{
  129. width: 90rpx;
  130. .back{
  131. display: none !important;
  132. }
  133. }
  134. &_only-back{
  135. width: 90rpx;
  136. .home{
  137. display: none !important;
  138. }
  139. .back::after{
  140. display: none;
  141. }
  142. }
  143. .back, .home{
  144. flex: 1;
  145. width: 0;
  146. height: 100%;
  147. display: flex;
  148. justify-content: center;
  149. align-items: center;
  150. }
  151. .back{
  152. position: relative;
  153. &::after{
  154. position: absolute;
  155. right: 0;
  156. top: 50%;
  157. transform: translateY(-50%);
  158. content: ' ';
  159. display: block;
  160. clear: both;
  161. background: #CECECE80;
  162. width: 2rpx;
  163. height: 34rpx;
  164. }
  165. image{
  166. width: 18rpx;
  167. height: 32rpx;
  168. }
  169. }
  170. .home{
  171. image{
  172. width: 36rpx;
  173. height: 32rpx;
  174. }
  175. }
  176. }
  177. }
  178. &_content{
  179. &.right-slot{
  180. .nav-bar_content_title{
  181. text-align: left !important;
  182. }
  183. }
  184. &_title{
  185. text-align: center;
  186. font-size: 36rpx;
  187. color: #fff;
  188. // background: red;
  189. }
  190. &_right{
  191. flex: none;
  192. display: flex;
  193. align-items: center;
  194. margin: 0 26rpx;
  195. }
  196. }
  197. }
  198. }
  199. }
  200. </style>