goods-detail.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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. uni.pageScrollTo({
  174. selector: `#anchor-${index}`,
  175. duration: 300,
  176. success: () => {
  177. uni.pageScrollTo({
  178. scrollTop: this.scorllTop - 40 - 10,
  179. duration: 300
  180. })
  181. }
  182. })
  183. },
  184. // 初始化锚点
  185. getAnchorList: debounce(
  186. function() {
  187. const query = uni.createSelectorQuery().in(this)
  188. query
  189. .selectAll('.anchor')
  190. .boundingClientRect(data => {
  191. this.anchorList = data
  192. this.setCurrentTabIndex()
  193. })
  194. .exec()
  195. },
  196. 300,
  197. false
  198. ),
  199. // 设置tab索引
  200. setCurrentTabIndex() {
  201. this.anchorList.forEach((item, index) => {
  202. if (item.bottom < 100) {
  203. this.currentTab = index
  204. }
  205. })
  206. }
  207. }
  208. }
  209. </script>
  210. <style lang="scss" scoped>
  211. .product-detail {
  212. min-height: 100vh;
  213. padding-bottom: 100rpx;
  214. box-sizing: border-box;
  215. .section {
  216. margin: 24rpx 0;
  217. background-color: #fff;
  218. &.detail {
  219. padding: 24rpx;
  220. }
  221. &.service-items {
  222. padding: 24rpx;
  223. }
  224. .title {
  225. margin-bottom: 24rpx;
  226. font-size: 26rpx;
  227. font-weight: bold;
  228. }
  229. .section-empty {
  230. height: 1200rpx;
  231. font-size: 24rpx;
  232. color: #999;
  233. }
  234. }
  235. .navbar {
  236. line-height: 1;
  237. text-align: center;
  238. &.group,
  239. &.normal {
  240. .prefix {
  241. display: none !important;
  242. }
  243. }
  244. .left-btn {
  245. color: #ff457b;
  246. &.text1 {
  247. font-size: 24rpx;
  248. margin-bottom: 4rpx;
  249. }
  250. .text2 {
  251. font-size: 24rpx;
  252. font-weight: bold;
  253. }
  254. .prefix {
  255. font-size: 20rpx;
  256. }
  257. }
  258. .right-btn {
  259. color: #fff;
  260. &.text1 {
  261. font-size: 24rpx;
  262. margin-bottom: 4rpx;
  263. }
  264. .text2 {
  265. font-size: 24rpx;
  266. font-weight: bold;
  267. }
  268. .prefix {
  269. font-size: 20rpx;
  270. }
  271. }
  272. }
  273. }
  274. </style>