s-custom-navbar.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <!-- 顶部导航栏 -->
  2. <template>
  3. <navbar
  4. :alway="isAlway"
  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.mode == '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} mode = [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.mode == 'inner') {
  68. if (props.data.alway) {
  69. return false;
  70. }
  71. }
  72. if (props.data.mode == 'normal') {
  73. return false;
  74. }
  75. });
  76. const navList = computed(() => {
  77. if (!props.data.list) return [];
  78. // #ifdef MP
  79. return props.data.list.mp;
  80. // #endif
  81. return props.data.list.app;
  82. });
  83. // 单元格大小
  84. const windowWidth = sheep.$platform.device.windowWidth;
  85. const cell = computed(() => {
  86. if (unref(navList).length) {
  87. let cell = (windowWidth - 90) / 8;
  88. // #ifdef MP
  89. cell = (windowWidth - 80 - unref(sheep.$platform.capsule).width) / 6;
  90. // #endif
  91. return cell;
  92. }
  93. });
  94. // 解析位置
  95. const parseImgStyle = (item) => {
  96. let obj = {
  97. width: item.width * cell.value + (item.width - 1) * 10 + 'px',
  98. left: item.left * cell.value + (item.left + 1) * 10 + 'px',
  99. 'border-radius': item.borderRadius + 'px',
  100. };
  101. return obj;
  102. };
  103. const isAlway = computed(() =>
  104. props.data.mode === 'inner' ? Boolean(props.data.alwaysShow) : true,
  105. );
  106. const isOpacity = computed(() =>
  107. props.data.mode === 'normal'
  108. ? false
  109. : props.showLeftButton
  110. ? false
  111. : props.data.mode === 'inner',
  112. );
  113. const isPlaceholder = computed(() => props.data.mode === 'normal');
  114. const bgStyles = computed(() => {
  115. if (props.data.type) {
  116. return {
  117. background:
  118. props.data.type == 'color'
  119. ? props.data.color
  120. : `url(${sheep.$url.cdn(props.data.src)}) no-repeat top center / 100% 100%`,
  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. function onClickRight() {
  132. showMenuTools();
  133. }
  134. </script>
  135. <style lang="scss" scoped>
  136. .nav-box {
  137. width: 750rpx;
  138. position: relative;
  139. height: 100%;
  140. .nav-item {
  141. position: absolute;
  142. top: 50%;
  143. transform: translateY(-50%);
  144. }
  145. .nav-icon {
  146. position: absolute;
  147. top: 50%;
  148. transform: translateY(-50%);
  149. left: 20rpx;
  150. .inner-icon-box {
  151. border: 1px solid rgba(#fff, 0.4);
  152. background: none !important;
  153. }
  154. .icon-box {
  155. background: #ffffff;
  156. box-shadow: 0px 0px 4rpx rgba(51, 51, 51, 0.08),
  157. 0px 4rpx 6rpx 2rpx rgba(102, 102, 102, 0.12);
  158. border-radius: 30rpx;
  159. width: 134rpx;
  160. height: 56rpx;
  161. margin-left: 8rpx;
  162. .line {
  163. width: 2rpx;
  164. height: 24rpx;
  165. background: #e5e5e7;
  166. }
  167. .sicon-back {
  168. font-size: 32rpx;
  169. }
  170. .sicon-home {
  171. font-size: 32rpx;
  172. }
  173. .sicon-more {
  174. font-size: 32rpx;
  175. }
  176. .icon-button {
  177. width: 67rpx;
  178. height: 56rpx;
  179. &-left:hover {
  180. background: rgba(0, 0, 0, 0.16);
  181. border-radius: 30rpx 0px 0px 30rpx;
  182. }
  183. &-right:hover {
  184. background: rgba(0, 0, 0, 0.16);
  185. border-radius: 0px 30rpx 30rpx 0px;
  186. }
  187. }
  188. }
  189. }
  190. }
  191. </style>