s-custom-navbar.vue 5.4 KB

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