s-custom-navbar.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <!-- 顶部导航栏 -->
  2. <template>
  3. <navbar :alway="isAlways" :back="false" bg="" :placeholder="isPlaceholder" :bgStyles="bgStyles" :opacity="isOpacity"
  4. :sticky="sticky">
  5. <template #item>
  6. <view class="nav-box">
  7. <view class="nav-icon" v-if="showLeftButton">
  8. <view class="icon-box ss-flex" :class="{ 'inner-icon-box': data.styleType === 'inner' }">
  9. <view class="icon-button icon-button-left ss-flex ss-row-center" @tap="onClickLeft">
  10. <text class="sicon-back" v-if="hasHistory" />
  11. <text class="sicon-home" v-else />
  12. </view>
  13. <view class="line"></view>
  14. <view class="icon-button icon-button-right ss-flex ss-row-center" @tap="onClickRight">
  15. <text class="sicon-more" />
  16. </view>
  17. </view>
  18. </view>
  19. <view class="nav-item" v-for="(item, index) in navList" :key="index" :style="[parseImgStyle(item)]"
  20. :class="[{ 'ss-flex ss-col-center ss-row-center': item.type !== 'search' }]">
  21. <navbar-item :data="item" :width="parseImgStyle(item).width" />
  22. </view>
  23. </view>
  24. </template>
  25. </navbar>
  26. </template>
  27. <script setup>
  28. /**
  29. * 装修组件 - 自定义标题栏
  30. *
  31. *
  32. * @property {Number | String} alwaysShow = [0,1] - 是否常驻
  33. * @property {Number | String} styleType = [inner] - 是否沉浸式
  34. * @property {String | Number} type - 标题背景模式
  35. * @property {String} color - 页面背景色
  36. * @property {String} src - 页面背景图片
  37. */
  38. import { computed, unref } from 'vue';
  39. import sheep from '@/sheep';
  40. import Navbar from './components/navbar.vue';
  41. import NavbarItem from './components/navbar-item.vue';
  42. import { showMenuTools } from '@/sheep/hooks/useModal';
  43. const props = defineProps({
  44. data: {
  45. type: Object,
  46. default: () => ({}),
  47. },
  48. showLeftButton: {
  49. type: Boolean,
  50. default: false,
  51. },
  52. });
  53. const hasHistory = sheep.$router.hasHistory();
  54. const sticky = computed(() => {
  55. if (props.data.styleType === 'inner') {
  56. if (props.data.alwaysShow) {
  57. return false;
  58. }
  59. }
  60. if (props.data.styleType === 'normal') {
  61. return false;
  62. }
  63. });
  64. const navList = computed(() => {
  65. // #ifdef MP
  66. return props.data.mpCells || [];
  67. // #endif
  68. return props.data.otherCells || [];
  69. });
  70. // 页面宽度
  71. const windowWidth = sheep.$platform.device.windowWidth;
  72. // 单元格宽度
  73. const cell = computed(() => {
  74. if (unref(navList).length) {
  75. // 默认宽度为8个格子,微信公众号右上角有胶囊按钮所以是6个格子
  76. let cell = (windowWidth - 90) / 8;
  77. // #ifdef MP
  78. cell = (windowWidth - 80 - unref(sheep.$platform.capsule).width) / 6;
  79. // #endif
  80. return cell;
  81. }
  82. });
  83. // 解析位置
  84. const parseImgStyle = (item) => {
  85. let obj = {
  86. width: item.width * cell.value + (item.width - 1) * 10 + 'px',
  87. left: item.left * cell.value + (item.left + 1) * 10 + 'px',
  88. 'border-radius': item.borderRadius + 'px',
  89. };
  90. return obj;
  91. };
  92. const isAlways = computed(() =>
  93. props.data.styleType === 'inner' ? Boolean(props.data.alwaysShow) : true,
  94. );
  95. const isOpacity = computed(() =>
  96. props.data.styleType === 'normal'
  97. ? false
  98. : props.showLeftButton
  99. ? false
  100. : props.data.styleType === 'inner',
  101. );
  102. const isPlaceholder = computed(() => props.data.styleType === 'normal');
  103. const bgStyles = computed(() => {
  104. return {
  105. background:
  106. props.data.bgType === 'img' && props.data.bgImg
  107. ? `url(${sheep.$url.cdn(props.data.bgImg)}) no-repeat top center / 100% 100%`
  108. : props.data.bgColor,
  109. };
  110. });
  111. // 左侧按钮:返回上一页或首页
  112. function onClickLeft() {
  113. if (hasHistory) {
  114. sheep.$router.back();
  115. } else {
  116. sheep.$router.go('/pages/index/index');
  117. }
  118. }
  119. // 右侧按钮:打开快捷菜单
  120. function onClickRight() {
  121. showMenuTools();
  122. }
  123. </script>
  124. <style lang="scss" scoped>
  125. .nav-box {
  126. width: 750rpx;
  127. position: relative;
  128. height: 100%;
  129. .nav-item {
  130. position: absolute;
  131. top: 50%;
  132. transform: translateY(-50%);
  133. }
  134. .nav-icon {
  135. position: absolute;
  136. top: 50%;
  137. transform: translateY(-50%);
  138. left: 20rpx;
  139. .inner-icon-box {
  140. border: 1px solid rgba(#fff, 0.4);
  141. background: none !important;
  142. }
  143. .icon-box {
  144. background: #ffffff;
  145. box-shadow: 0px 0px 4rpx rgba(51, 51, 51, 0.08), 0px 4rpx 6rpx 2rpx rgba(102, 102, 102, 0.12);
  146. border-radius: 30rpx;
  147. width: 134rpx;
  148. height: 56rpx;
  149. margin-left: 8rpx;
  150. .line {
  151. width: 2rpx;
  152. height: 24rpx;
  153. background: #e5e5e7;
  154. }
  155. .sicon-back {
  156. font-size: 32rpx;
  157. }
  158. .sicon-home {
  159. font-size: 32rpx;
  160. }
  161. .sicon-more {
  162. font-size: 32rpx;
  163. }
  164. .icon-button {
  165. width: 67rpx;
  166. height: 56rpx;
  167. &-left:hover {
  168. background: rgba(0, 0, 0, 0.16);
  169. border-radius: 30rpx 0px 0px 30rpx;
  170. }
  171. &-right:hover {
  172. background: rgba(0, 0, 0, 0.16);
  173. border-radius: 0px 30rpx 30rpx 0px;
  174. }
  175. }
  176. }
  177. }
  178. }
  179. </style>