goods-detail.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. <template>
  2. <view class="product-detail">
  3. <tui-skeleton v-if="isRequest" :loadingType="3" :isLoading="true"></tui-skeleton>
  4. <!-- 顶部导航 -->
  5. <goods-top-tabs @change="onTabChange" :current="currentTab" v-show="scorllTop > 100"></goods-top-tabs>
  6. <!-- 锚点0 -->
  7. <view id="anchor-0" class="anchor"></view>
  8. <!-- 轮播 -->
  9. <goods-image-swiper :list="imageList" @click="onSwiperClick" @change="onSwiperChange"></goods-image-swiper>
  10. <!-- 价格 -->
  11. <goods-price></goods-price>
  12. <!-- 活动优惠券 -->
  13. <goods-coupon-list></goods-coupon-list>
  14. <!-- 商品基本信息:商品名称 && 分享 && 标签 && 备注 && 服务-->
  15. <goods-info @share="onShare"></goods-info>
  16. <!-- 参数 -->
  17. <view class="section"><goods-params-section></goods-params-section></view>
  18. <!-- 优惠券 -->
  19. <view class="section"><goods-coupon-section></goods-coupon-section></view>
  20. <!-- 锚点1 -->
  21. <view id="anchor-1" class="anchor"></view>
  22. <!-- 商品详情 -->
  23. <view class="section detail">
  24. <view class="title">商品详情</view>
  25. <!-- 空 -->
  26. <view class="section-empty">暂无商品详情</view>
  27. </view>
  28. <!-- 锚点2 -->
  29. <view id="anchor-2" class="anchor"></view>
  30. <!-- 服务项目 -->
  31. <view class="section service-items">
  32. <view class="title">服务项目</view>
  33. <!-- 空 -->
  34. <view class="section-empty">暂无服务项目</view>
  35. </view>
  36. <!-- 商品操作导航 -->
  37. <goods-navbar class="navbar" :class="navbarType" @rightClick="navbarRightClick" @leftClick="navbarLeftClick">
  38. <template v-slot:left>
  39. <view class="left-btn text1" v-text="leftButton[0]"></view>
  40. <view class="left-btn" v-if="leftButton[1]">
  41. <text class="prefix">券后</text>
  42. <text class="text2" v-text="leftButton[1]"></text>
  43. </view>
  44. </template>
  45. <template v-slot:right>
  46. <view class="right-btn text1" v-text="rightButton[0]"></view>
  47. <view class="right-btn" v-if="rightButton[1]">
  48. <text class="prefix">券后</text>
  49. <text class="text2" v-text="rightButton[1]"></text>
  50. </view>
  51. </template>
  52. </goods-navbar>
  53. <!-- 安全区域 -->
  54. <cm-safe-area-bottom></cm-safe-area-bottom>
  55. <!-- 活动价 -->
  56. <goods-activity-popup
  57. ref="activitypPopup"
  58. :ladderList="ladderList"
  59. @open="$refs.receiveBuyPopup.close()"
  60. @close="$refs.receiveBuyPopup.open()"
  61. ></goods-activity-popup>
  62. <!-- 领券购买 -->
  63. <goods-receive-buy-pupup ref="receiveBuyPopup" @detail="$refs.activitypPopup.open()"></goods-receive-buy-pupup>
  64. <!-- 分享弹窗 -->
  65. <cm-share-popup ref="sharePopup" :data="posterData" type="product"></cm-share-popup>
  66. </view>
  67. </template>
  68. <script>
  69. // 配置
  70. import { navbarButtonGroup } from './config/config.js'
  71. import { debounce } from '@/common/utils.js'
  72. import { shareDataResult } from '@/common/share.helper.js'
  73. import { mapGetters } from 'vuex'
  74. export default {
  75. data() {
  76. return {
  77. jumpState: 0,
  78. isRequest: true,
  79. // 轮播图
  80. currentTab: 0,
  81. imageList: ['https://picsum.photos/1000/1000?random=1', 'https://picsum.photos/1000/1000?random=2'],
  82. navbarType: 'groupByCoupon',
  83. leftButton: {},
  84. rightButton: {},
  85. ladderList: [
  86. {
  87. buyPrice: '2000',
  88. buyNum: 1
  89. },
  90. {
  91. buyPrice: '2000',
  92. buyNum: 2
  93. },
  94. {
  95. buyPrice: '2000',
  96. buyNum: 3
  97. }
  98. ],
  99. // 锚点列表
  100. anchorList: [],
  101. scorllTop: 0,
  102. productInfo: {},
  103. posterData: {}
  104. }
  105. },
  106. computed: {
  107. ...mapGetters(['userId'])
  108. },
  109. onPageScroll(e) {
  110. this.scorllTop = e.scrollTop
  111. this.getAnchorList()
  112. },
  113. onShareAppMessage() {
  114. const shareData = {
  115. type: 1,
  116. productId: this.productInfo.productId,
  117. inviteUserId: this.userId,
  118. jumpState: this.jumpState
  119. }
  120. return shareDataResult(shareData, this.productInfo.name, this.imageList[0])
  121. },
  122. onLoad() {
  123. this.initNavbarButton()
  124. setTimeout(() => (this.isRequest = false), 2000)
  125. },
  126. methods: {
  127. // 分享事件
  128. onShare() {
  129. this.posterData = {
  130. porductName: '肌本演绎360愉悦修护套组标准版防晒修复补水',
  131. productPrice: 500,
  132. productOriginPrice: 800,
  133. productImage: 'https://picsum.photos/1000/1000?random=1'
  134. }
  135. this.$refs.sharePopup.open()
  136. },
  137. // 轮播图事件
  138. onSwiperClick() {
  139. uni.previewImage({
  140. urls: this.imageList,
  141. current: this.current,
  142. loop: true
  143. })
  144. },
  145. // 轮播图切换
  146. onSwiperChange(current) {
  147. this.current = current
  148. },
  149. // 初始化导航按钮
  150. initNavbarButton() {
  151. const navbarButton = navbarButtonGroup[this.navbarType]
  152. console.log(navbarButton)
  153. this.leftButton = navbarButton.left
  154. this.rightButton = navbarButton.right
  155. },
  156. // 导航菜单右侧按钮点击
  157. navbarRightClick(index) {
  158. if (this.navbarType !== 'normal') {
  159. this.$refs.receiveBuyPopup.open()
  160. }
  161. },
  162. // 导航栏菜单左侧按钮点击
  163. navbarLeftClick(index) {
  164. if (index === 0) {
  165. this.$router.switchTab('home')
  166. }
  167. if (index === 2) {
  168. this.$router.navigateTo('cart/cart')
  169. }
  170. },
  171. // 顶部tab切换
  172. onTabChange(index) {
  173. // const selector = `.product-detail #anchor-${index}`
  174. const offset = this.anchorList[index].top
  175. uni.pageScrollTo({
  176. scrollTop: this.scorllTop + offset - 40 - 10,
  177. duration: 300
  178. })
  179. },
  180. // 初始化锚点
  181. getAnchorList: debounce(
  182. function() {
  183. const query = uni.createSelectorQuery().in(this)
  184. query
  185. .selectAll('.anchor')
  186. .boundingClientRect(data => {
  187. this.anchorList = data
  188. this.setCurrentTabIndex()
  189. console.log(this.anchorList)
  190. })
  191. .exec()
  192. },
  193. 300,
  194. false
  195. ),
  196. // 设置tab索引
  197. setCurrentTabIndex() {
  198. this.anchorList.forEach((item, index) => {
  199. if (item.bottom < 100) {
  200. this.currentTab = index
  201. }
  202. })
  203. }
  204. }
  205. }
  206. </script>
  207. <style lang="scss" scoped>
  208. .product-detail {
  209. min-height: 100vh;
  210. padding-bottom: 100rpx;
  211. box-sizing: border-box;
  212. .section {
  213. margin: 24rpx 0;
  214. background-color: #fff;
  215. &.detail {
  216. padding: 24rpx;
  217. }
  218. &.service-items {
  219. padding: 24rpx;
  220. }
  221. .title {
  222. margin-bottom: 24rpx;
  223. font-size: 26rpx;
  224. font-weight: bold;
  225. }
  226. .section-empty {
  227. height: 1200rpx;
  228. font-size: 24rpx;
  229. color: #999;
  230. }
  231. }
  232. .navbar {
  233. line-height: 1;
  234. text-align: center;
  235. &.group,
  236. &.normal {
  237. .prefix {
  238. display: none !important;
  239. }
  240. }
  241. .left-btn {
  242. color: #ff457b;
  243. &.text1 {
  244. font-size: 24rpx;
  245. margin-bottom: 4rpx;
  246. }
  247. .text2 {
  248. font-size: 24rpx;
  249. font-weight: bold;
  250. }
  251. .prefix {
  252. font-size: 20rpx;
  253. }
  254. }
  255. .right-btn {
  256. color: #fff;
  257. &.text1 {
  258. font-size: 24rpx;
  259. margin-bottom: 4rpx;
  260. }
  261. .text2 {
  262. font-size: 24rpx;
  263. font-weight: bold;
  264. }
  265. .prefix {
  266. font-size: 20rpx;
  267. }
  268. }
  269. }
  270. }
  271. </style>