s-custom-navbar.vue 5.1 KB

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