detail-navbar.vue 6.3 KB

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