detail-navbar.vue 5.8 KB

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