detail-navbar.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. <!-- 商品详情:商品/评价/详情的 nav -->
  2. <template>
  3. <su-fixed alway :bgStyles="{ background: '#fff' }" :val="0" noNav opacity :placeholder="false">
  4. <su-status-bar />
  5. <view
  6. class="ui-bar ss-flex ss-col-center ss-row-between ss-p-x-20"
  7. :style="[{ height: sys_navBar - sys_statusBar + 'px' }]"
  8. >
  9. <!-- 左 -->
  10. <view class="icon-box ss-flex">
  11. <view class="icon-button icon-button-left ss-flex ss-row-center" @tap="onClickLeft">
  12. <text class="sicon-back" v-if="hasHistory" />
  13. <text class="sicon-home" v-else />
  14. </view>
  15. <view class="line"></view>
  16. <view class="icon-button icon-button-right ss-flex ss-row-center" @tap="onClickRight">
  17. <text class="sicon-more" />
  18. </view>
  19. </view>
  20. <!-- 中 -->
  21. <view class="detail-tab-card ss-flex-1" :style="[{ opacity: state.tabOpacityVal }]">
  22. <view class="tab-box ss-flex ss-col-center ss-row-around">
  23. <view
  24. class="tab-item ss-flex-1 ss-flex ss-row-center ss-col-center"
  25. v-for="item in state.tabList"
  26. :key="item.value"
  27. @tap="onTab(item)"
  28. >
  29. <view class="tab-title" :class="state.curTab === item.value ? 'cur-tab-title' : ''">
  30. {{ item.label }}
  31. </view>
  32. <view v-show="state.curTab === item.value" class="tab-line"></view>
  33. </view>
  34. </view>
  35. </view>
  36. <!-- #ifdef MP -->
  37. <view :style="[capsuleStyle]"></view>
  38. <!-- #endif -->
  39. </view>
  40. </su-fixed>
  41. </template>
  42. <script setup>
  43. import { reactive } from 'vue';
  44. import { onPageScroll } from '@dcloudio/uni-app';
  45. import sheep from '@/sheep';
  46. import throttle from '@/sheep/helper/throttle.js';
  47. import { showMenuTools, closeMenuTools } from '@/sheep/hooks/useModal';
  48. const sys_statusBar = sheep.$platform.device.statusBarHeight;
  49. const sys_navBar = sheep.$platform.navbar;
  50. const capsuleStyle = {
  51. width: sheep.$platform.capsule.width + 'px',
  52. height: sheep.$platform.capsule.height + 'px',
  53. };
  54. const state = reactive({
  55. tabOpacityVal: 0,
  56. curTab: 'goods',
  57. tabList: [
  58. {
  59. label: '商品',
  60. value: 'goods',
  61. to: 'detail-swiper-selector',
  62. },
  63. {
  64. label: '评价',
  65. value: 'comment',
  66. to: 'detail-comment-selector',
  67. },
  68. {
  69. label: '详情',
  70. value: 'detail',
  71. to: 'detail-content-selector',
  72. },
  73. ],
  74. });
  75. const emits = defineEmits(['clickLeft']);
  76. const hasHistory = sheep.$router.hasHistory();
  77. function onClickLeft() {
  78. if (hasHistory) {
  79. sheep.$router.back();
  80. } else {
  81. sheep.$router.go('/pages/index/index');
  82. }
  83. emits('clickLeft');
  84. }
  85. function onClickRight() {
  86. showMenuTools();
  87. }
  88. let commentCard = {
  89. top: 0,
  90. bottom: 0,
  91. };
  92. function getCommentCardNode() {
  93. return new Promise((res, rej) => {
  94. uni.createSelectorQuery()
  95. .select('.detail-comment-selector')
  96. .boundingClientRect((data) => {
  97. if (data) {
  98. commentCard.top = data.top;
  99. commentCard.bottom = data.top + data.height;
  100. res(data);
  101. } else {
  102. res(null);
  103. }
  104. })
  105. .exec();
  106. });
  107. }
  108. function onTab(tab) {
  109. let scrollTop = 0;
  110. if (tab.value === 'comment') {
  111. scrollTop = commentCard.top - sys_navBar + 1;
  112. } else if (tab.value === 'detail') {
  113. scrollTop = commentCard.bottom - sys_navBar + 1;
  114. }
  115. uni.pageScrollTo({
  116. scrollTop,
  117. duration: 200,
  118. });
  119. }
  120. onPageScroll((e) => {
  121. state.tabOpacityVal = e.scrollTop > sheep.$platform.navbar ? 1 : e.scrollTop * 0.01;
  122. if (commentCard.top === 0) {
  123. throttle(() => {
  124. getCommentCardNode();
  125. }, 50);
  126. }
  127. if (e.scrollTop < commentCard.top - sys_navBar) {
  128. state.curTab = 'goods';
  129. } else if (
  130. e.scrollTop >= commentCard.top - sys_navBar &&
  131. e.scrollTop <= commentCard.bottom - sys_navBar
  132. ) {
  133. state.curTab = 'comment';
  134. } else {
  135. state.curTab = 'detail';
  136. }
  137. });
  138. </script>
  139. <style lang="scss" scoped>
  140. .icon-box {
  141. box-shadow: 0px 0px 4rpx rgba(51, 51, 51, 0.08), 0px 4rpx 6rpx 2rpx rgba(102, 102, 102, 0.12);
  142. border-radius: 30rpx;
  143. width: 134rpx;
  144. height: 56rpx;
  145. margin-left: 8rpx;
  146. border: 1px solid rgba(#fff, 0.4);
  147. .line {
  148. width: 2rpx;
  149. height: 24rpx;
  150. background: #e5e5e7;
  151. }
  152. .sicon-back {
  153. font-size: 32rpx;
  154. color: #000;
  155. }
  156. .sicon-home {
  157. font-size: 32rpx;
  158. color: #000;
  159. }
  160. .sicon-more {
  161. font-size: 32rpx;
  162. color: #000;
  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. .left-box {
  178. position: relative;
  179. width: 60rpx;
  180. height: 60rpx;
  181. display: flex;
  182. justify-content: center;
  183. align-items: center;
  184. .circle {
  185. position: absolute;
  186. left: 0;
  187. top: 0;
  188. width: 60rpx;
  189. height: 60rpx;
  190. background: rgba(#fff, 0.6);
  191. border: 1rpx solid #ebebeb;
  192. border-radius: 50%;
  193. box-sizing: border-box;
  194. z-index: -1;
  195. }
  196. }
  197. .right {
  198. position: relative;
  199. width: 60rpx;
  200. height: 60rpx;
  201. display: flex;
  202. justify-content: center;
  203. align-items: center;
  204. .circle {
  205. position: absolute;
  206. left: 0;
  207. top: 0;
  208. width: 60rpx;
  209. height: 60rpx;
  210. background: rgba(#ffffff, 0.6);
  211. border: 1rpx solid #ebebeb;
  212. box-sizing: border-box;
  213. border-radius: 50%;
  214. z-index: -1;
  215. }
  216. }
  217. .detail-tab-card {
  218. width: 50%;
  219. .tab-item {
  220. height: 80rpx;
  221. position: relative;
  222. z-index: 11;
  223. .tab-title {
  224. font-size: 30rpx;
  225. }
  226. .cur-tab-title {
  227. font-weight: $font-weight-bold;
  228. }
  229. .tab-line {
  230. width: 60rpx;
  231. height: 6rpx;
  232. border-radius: 6rpx;
  233. position: absolute;
  234. left: 50%;
  235. transform: translateX(-50%);
  236. bottom: 10rpx;
  237. background-color: var(--ui-BG-Main);
  238. z-index: 12;
  239. }
  240. }
  241. }
  242. </style>