category.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. <template>
  2. <view class="content">
  3. <view class="scroll-top flex_item">
  4. <scroll-view class="scroll-list" scroll-x>
  5. <view class="scoll-box" v-for="ls in flist" :class="{ active: ls.id === currentId }" @click="tabtap(ls.id)">
  6. <view class="scoll-img"><image :src="ls.pic"></image></view>
  7. <view class="scoll-name">{{ ls.cate_name }}</view>
  8. </view>
  9. </scroll-view>
  10. <view class="search-box" @click="Toseach">
  11. <view class="search"><image src="../../static/image/img22.png" mode="scaleToFill"></image></view>
  12. <view>搜索</view>
  13. </view>
  14. </view>
  15. <view class="scroll-view flex-tpl" :style="{ height: pageHeight + 'px' }">
  16. <scroll-view scroll-y class="left-aside">
  17. <view v-for="item in slist" class="f-item" :class="{ active_top: item.id === erjiid }" @click="changeSlist(item)">{{ item.cate_name }}</view>
  18. </scroll-view>
  19. <scroll-view :scroll-with-animation="scrollAnimation" scroll-y class="right-aside" @scroll="asideScroll" :scroll-top="tabScrollTop">
  20. <view class="tlist-box" v-for="ls in slist" :id="'main-' + ls.id">
  21. <view class="tlistname" v-if="ls.list">{{ ls.name }}</view>
  22. <view class="tlist-list flex_item" v-if="ls.goods" v-for="item in ls.goods" @click="ToDetail(item)">
  23. <view class="tlist-img">
  24. <image class="img" :src="item.image" :lazy-load="true" mode="scaleToFill"></image>
  25. </view>
  26. <view class="sell-out" v-if="item.stock == 0"><text>已售罄</text></view>
  27. <view class="tlist-info">
  28. <view class="name clamp2">{{ item.store_name }}</view>
  29. <!-- <view class="info clamp">{{ item.store_info }}</view> -->
  30. <view class="tipBox">
  31. <view class="tip clamp" v-if="item.keyword != ''">
  32. <text >{{ item.keyword }}</text>
  33. </view>
  34. </view>
  35. <view class="tlist-price flex">
  36. <view class="price-box">
  37. <view class="stock flex_item" v-if="item.stock > 0">
  38. <view class="stock-num clamp">库存剩{{ item.stock }}</view>
  39. </view>
  40. <view class="price">
  41. ¥
  42. <text class="blod">{{ item.price }}</text>
  43. <text class="fen">/{{item.unit_name}}</text>
  44. </view>
  45. </view>
  46. <view class="gocar position-relative" @click.stop="Addcar(item)">
  47. <image src="/static/image/img21.png" mode="scaleToFill"></image>
  48. <view class="corner" v-if="item.cart_num > 0">
  49. <text>{{ item.cart_num }}</text>
  50. </view>
  51. </view>
  52. </view>
  53. <view class="bottom_border"></view>
  54. </view>
  55. </view>
  56. </view>
  57. </scroll-view>
  58. </view>
  59. </view>
  60. </template>
  61. <script>
  62. import { mapState, mapMutations } from 'vuex';
  63. import { category_layer,category_goods } from '@/api/water.js';
  64. import { cartAdd } from '@/api/product.js';
  65. import { saveUrl } from '@/utils/loginUtils';
  66. export default {
  67. data() {
  68. return {
  69. sizeCalcState: false,
  70. tabScrollTop: 0,
  71. currentId: '', //一级选择id,
  72. erjiid: '', //二级选择id
  73. flist: [], //一级分类列表
  74. slist: [], //二级分类列表
  75. yijishow: true, //一级界面显示
  76. sanjishow: false, //三级界面隐藏
  77. bili: 1, //设置页面比例
  78. pageHeight: 0, //保存滚轮页面高度
  79. CategoryID: '',
  80. userInfo: '',
  81. onload: true, //保存数据判断是否是第一次打开页面
  82. scrollAnimation: true //是否开启动画
  83. };
  84. },
  85. onLoad(option) {
  86. if (option.spread) {
  87. uni.setStorageSync('spread', option.spread);
  88. }
  89. saveUrl();
  90. uni.showLoading({
  91. title: '加载中'
  92. });
  93. this.loadData();
  94. },
  95. onShow() {
  96. let obj = this;
  97. const categoryId = uni.getStorageSync('categoryId') || '';
  98. if (obj.currentId != categoryId && categoryId != '' && !obj.onload) {
  99. obj.tabtap(categoryId);
  100. }
  101. // 初次数据加载完毕
  102. obj.onload = false;
  103. },
  104. onReady() {
  105. // 初始化获取页面宽度
  106. uni.createSelectorQuery()
  107. .select('.content')
  108. .fields(
  109. {
  110. size: true
  111. },
  112. data => {
  113. // 获取页面百分比
  114. this.bili = data.width / 750;
  115. console.log(data, 2);
  116. this.pageHeight = data.height - 185 * this.bili;
  117. console.log(this.pageHeight, 33);
  118. }
  119. )
  120. .exec();
  121. },
  122. // #ifndef MP
  123. // 监听导航栏输入框点击事件
  124. onNavigationBarSearchInputClicked(e) {
  125. uni.navigateTo({
  126. url: '/pages/product/search'
  127. });
  128. },
  129. // #endif
  130. //下拉刷新
  131. onPullDownRefresh() {
  132. let obj = this;
  133. //监听下拉刷新动作的执行方法,每次手动下拉刷新都会执行一次
  134. setTimeout(function() {
  135. obj.loadData();
  136. uni.stopPullDownRefresh(); //停止下拉刷新动画
  137. }, 1000);
  138. },
  139. computed: {
  140. ...mapState(['GetInfo']),
  141. },
  142. methods: {
  143. // 载入数据
  144. async loadData() {
  145. let obj = this;
  146. obj.loading = true;
  147. category_layer({})
  148. .then(({ data }) => {
  149. obj.flist = data.list;
  150. obj.currentId = data.first;
  151. obj.erji();
  152. })
  153. .catch(err => {
  154. console.log(err);
  155. });
  156. },
  157. // 二级数据加载
  158. erji() {
  159. let obj = this;
  160. category_goods({
  161. pid: obj.currentId
  162. })
  163. .then(({ data }) => {
  164. obj.slist = data.slist.map(function(s) {
  165. return s;
  166. });
  167. obj.erjiid = obj.slist[0].id;
  168. obj.$nextTick(e => {
  169. // 重新开启动画效果
  170. uni.hideLoading();
  171. // 数据加载完成后重新计算高度
  172. obj.calcSize()
  173. obj.scrollAnimation = true;
  174. });
  175. })
  176. .catch(err => {
  177. uni.hideLoading();
  178. console.log(err);
  179. });
  180. },
  181. //分享
  182. // #ifdef MP
  183. onShareAppMessage: function(res) {
  184. let userInfo = uni.getStorageSync('userInfo');
  185. // 来自页面内分享按钮
  186. let pages = getCurrentPages();
  187. // 获取当前页面
  188. let page = pages[pages.length - 1];
  189. let path = '/pages/category/category?';
  190. // 保存邀请人
  191. path += 'spread=' + userInfo.uid;
  192. let data = {
  193. path: path,
  194. imageUrl: this.GetInfo.img,
  195. title: this.GetInfo.title
  196. };
  197. console.log(data)
  198. return data;
  199. },
  200. // #endif
  201. //加入购物车
  202. Addcar(item) {
  203. let obj = this;
  204. cartAdd({
  205. cartNum: '1', //商品数量
  206. uniqueId: '', //商品标签
  207. new: 0, //商品是否新增加到购物车1为不加入0为加入
  208. mer_id: '',
  209. productId: item.id //商品编号
  210. })
  211. .then(function(e) {
  212. uni.showToast({
  213. title: '成功加入购物车',
  214. type: 'top',
  215. duration: 500,
  216. icon: 'none'
  217. });
  218. obj.erji();
  219. })
  220. .catch(e => {
  221. console.log(e);
  222. });
  223. },
  224. //一级分类点击
  225. tabtap(item) {
  226. uni.showLoading({
  227. title: '加载中'
  228. });
  229. let obj = this;
  230. // 关闭动画效果
  231. obj.scrollAnimation = false;
  232. // 设置顶部高度为0
  233. obj.$nextTick(function(){
  234. // 等待渲染完毕在执行高度修改否则动画效果依然存在
  235. obj.tabScrollTop = 0;
  236. })
  237. // 获取当前点击的id
  238. obj.currentId = item;
  239. // 二级分类分类保存id
  240. obj.erjiid = item;
  241. uni.setStorageSync('categoryId', item);
  242. // 重置分类滚轮绑定高度
  243. obj.sizeCalcState = false;
  244. // 加载二级方法
  245. setTimeout(function() {
  246. obj.erji();
  247. });
  248. },
  249. //二级点击
  250. changeSlist(item) {
  251. let obj = this;
  252. // 判断有没有初始化页面高度对象数据
  253. console.log(obj.sizeCalcState)
  254. if (!obj.sizeCalcState) {
  255. obj.calcSize();
  256. }
  257. // 获取当前点击的id
  258. obj.erjiid = item.id;
  259. let index = obj.slist.findIndex(sitem => sitem.id === item.id);
  260. setTimeout(function() {
  261. obj.tabScrollTop = obj.slist[index].top;
  262. }, 10);
  263. },
  264. // 商品详情页
  265. ToDetail(item) {
  266. if (item.stock < 1) {
  267. this.$api.msg('该商品已售罄');
  268. } else {
  269. uni.navigateTo({
  270. url: `/pages/product/product?id=` + item.id
  271. });
  272. }
  273. },
  274. Toseach() {
  275. uni.navigateTo({
  276. url: `/pages/product/search`
  277. });
  278. },
  279. //右侧栏滚动
  280. asideScroll(e) {
  281. // 判断有没有初始化页面高度对象数据
  282. if (!this.sizeCalcState) {
  283. this.calcSize();
  284. }
  285. let scrollTop = e.detail.scrollTop;
  286. let box = 0; //列表包裹框高度初始化
  287. let bottom = 10; //距离页面底部多少像素左侧列表切换到最后一个一级分类
  288. // 查询当前页面对象
  289. let view = uni.createSelectorQuery().select('.right-aside');
  290. view.fields(
  291. {
  292. id: true,
  293. dataset: true,
  294. rect: true,
  295. size: true,
  296. scrollOffset: true
  297. },
  298. function(e) {
  299. // 保存包裹框高度
  300. box = e.height;
  301. }
  302. ).exec();
  303. // 获取所有距离顶部大于滚轮距离页面高度的所有分类
  304. let tabs = this.slist.filter(item => item.top <= scrollTop).reverse();
  305. if (tabs.length > 0) {
  306. // 判断是否已经到达滚轮底部
  307. if (box + scrollTop + bottom >= e.detail.scrollHeight) {
  308. this.erjiid = this.slist[this.slist.length - 1].id;
  309. } else {
  310. this.erjiid = tabs[0].id;
  311. }
  312. }
  313. },
  314. //计算右侧栏每个tab的高度等信息
  315. calcSize() {
  316. let h = this.bili * 215;
  317. this.slist.forEach(item => {
  318. let view = uni.createSelectorQuery().select('#main-' + item.id);
  319. view.fields(
  320. {
  321. size: true
  322. },
  323. data => {
  324. item.top = Math.ceil(h);
  325. h += data.height;
  326. item.bottom = Math.ceil(h);
  327. }
  328. ).exec();
  329. });
  330. this.sizeCalcState = true;
  331. }
  332. }
  333. };
  334. </script>
  335. <style lang="scss">
  336. page {
  337. background-color: #ffffff;
  338. height: 100%;
  339. .content {
  340. background-color: #ffffff;
  341. height: 100%;
  342. }
  343. }
  344. //顶部分类
  345. .scroll-top {
  346. width: 100%;
  347. font-size: 24rpx;
  348. height: 170rpx;
  349. padding: 0px 25rpx;
  350. box-shadow: 0 1px 5px rgba(0, 0, 0, 0.06);
  351. .scroll-list {
  352. width: 80%;
  353. overflow: hidden;
  354. white-space: nowrap;
  355. .scoll-box {
  356. margin-right: 15rpx;
  357. text-align: center;
  358. display: inline-block;
  359. .scoll-img {
  360. width: 130rpx;
  361. height: 85rpx;
  362. border-radius: 100%;
  363. image {
  364. width: 85rpx;
  365. height: 100%;
  366. border-radius: 100%;
  367. }
  368. }
  369. .scoll-name {
  370. padding-top: 15rpx;
  371. }
  372. &.active {
  373. color: $base-color;
  374. }
  375. }
  376. }
  377. .search-box {
  378. text-align: center;
  379. margin-left: 50rpx;
  380. .search {
  381. width: 85rpx;
  382. height: 85rpx;
  383. border-radius: 100%;
  384. margin-bottom: 15rpx;
  385. image {
  386. width: 100%;
  387. height: 100%;
  388. border-radius: 100%;
  389. }
  390. }
  391. }
  392. }
  393. .flex-tpl {
  394. display: flex;
  395. justify-content: space-between;
  396. }
  397. .scroll-view {
  398. margin-top: 15rpx;
  399. .left-aside {
  400. width: 190rpx;
  401. background-color: rgba(245, 246, 248, 1);
  402. overflow: hidden;
  403. height: 100%;
  404. display: block;
  405. overflow-y: scroll;
  406. }
  407. }
  408. .f-item {
  409. display: flex;
  410. align-items: center;
  411. justify-content: center;
  412. width: 100%;
  413. height: 100rpx;
  414. font-size: 24rpx;
  415. color: $font-color-base;
  416. position: relative;
  417. &.active_top {
  418. background: #ffffff;
  419. font-size: 26rpx;
  420. font-weight: 500;
  421. color: rgba(51, 51, 51, 1);
  422. &:before {
  423. content: '';
  424. position: absolute;
  425. left: 0;
  426. top: 50%;
  427. transform: translateY(-50%);
  428. height: 36rpx;
  429. width: 8rpx;
  430. background-color: $base-color;
  431. border-radius: 0 4px 4px 0;
  432. opacity: 0.8;
  433. }
  434. }
  435. }
  436. .right-aside {
  437. overflow: hidden;
  438. padding: 0rpx 20rpx;
  439. height: 100%;
  440. display: block;
  441. overflow-y: scroll;
  442. width: 100%;
  443. .image {
  444. width: 100%;
  445. padding-bottom: 15rpx;
  446. .imageLV {
  447. width: 100%;
  448. height: 200rpx;
  449. }
  450. }
  451. .tlist-box {
  452. .tlistname {
  453. font-size: 24rpx;
  454. padding: 25rpx 25rpx;
  455. border-top: 2rpx solid rgba(238, 238, 238, 1);
  456. border-bottom: 2rpx solid rgba(238, 238, 238, 1);
  457. }
  458. .tlist-list.flex_item {
  459. height: 0;
  460. min-height: 240rpx;
  461. align-items: stretch;
  462. }
  463. .tlist-list {
  464. padding: 25rpx 0rpx;
  465. position: relative;
  466. .tlist-img {
  467. width: 190rpx;
  468. position: relative;
  469. .img {
  470. width: 190rpx;
  471. height: 190rpx;
  472. }
  473. }
  474. .sell-out {
  475. position: absolute;
  476. width: 190rpx;
  477. height: 190rpx;
  478. background: rgba(255, 255, 255, 0.4);
  479. text-align: center;
  480. text {
  481. line-height: 190rpx;
  482. background: rgba(0, 0, 0, 0.5);
  483. color: #ffffff;
  484. padding: 10rpx 25rpx;
  485. border-radius: 25rpx;
  486. font-size: 20rpx;
  487. }
  488. }
  489. .tlist-info {
  490. font-size: 24rpx;
  491. width: 0;
  492. flex-grow: 1;
  493. padding-left: 25rpx;
  494. padding-right: 25rpx;
  495. height: 100%;
  496. position: relative;
  497. line-height: 1;
  498. .bottom_border {
  499. position: absolute;
  500. border-bottom: 1px solid #eeeeee;
  501. left: 25rpx;
  502. bottom: 0;
  503. height: 2rpx;
  504. width: 100%;
  505. }
  506. .name {
  507. color: #141821;
  508. font-weight: 500;
  509. font-size: 26rpx;
  510. line-height: 1.2;
  511. }
  512. .info {
  513. margin: 10rpx 0rpx;
  514. height: 30rpx;
  515. color: #979797;
  516. font-size: 24rpx;
  517. }
  518. .tipBox {
  519. height: 50rpx;
  520. margin: 10rpx 0;
  521. .tip {
  522. padding: 10rpx 0rpx;
  523. text {
  524. border: 2rpx solid #ff1a27;
  525. color: #ff1a27;
  526. border-radius: 5rpx;
  527. font-size: 18rpx;
  528. padding: 5rpx 10rpx;
  529. margin-right: 15rpx;
  530. }
  531. }
  532. }
  533. .tlist-price {
  534. position: absolute;
  535. left: 0rpx;
  536. padding-left: 25rpx;
  537. padding-right: 25rpx;
  538. bottom: 10rpx;
  539. width: 100%;
  540. .stock {
  541. font-size: 26rpx;
  542. color: $font-color-light;
  543. .stock-num {
  544. padding-left: 7rpx;
  545. font-size: 22rpx;
  546. border-radius: 5rpx;
  547. height: 32rpx;
  548. line-height: 32rpx;
  549. }
  550. }
  551. .price-box {
  552. .price {
  553. color: #ff1a27;
  554. .blod {
  555. font-size: 35rpx;
  556. font-weight: bold;
  557. }
  558. .fen {
  559. color: #838691;
  560. }
  561. }
  562. }
  563. .gocar {
  564. width: 50rpx;
  565. height: 50rpx;
  566. align-self: flex-end;
  567. image {
  568. width: 100%;
  569. height: 100%;
  570. }
  571. }
  572. }
  573. }
  574. }
  575. }
  576. .tlist {
  577. .cate {
  578. padding: 25rpx 0rpx;
  579. color: #666666;
  580. font-size: 24rpx;
  581. }
  582. }
  583. }
  584. .s-item {
  585. display: flex;
  586. align-items: center;
  587. height: 70rpx;
  588. padding-top: 8rpx;
  589. font-size: 28rpx;
  590. color: $font-color-dark;
  591. }
  592. .t-list {
  593. display: flex;
  594. flex-wrap: wrap;
  595. border-radius: 15rpx;
  596. width: 100%;
  597. background: #fff;
  598. padding-top: 12rpx;
  599. &:after {
  600. content: '';
  601. flex: 99;
  602. height: 0;
  603. }
  604. }
  605. .t-item {
  606. flex-shrink: 0;
  607. display: flex;
  608. justify-content: center;
  609. align-items: center;
  610. flex-direction: column;
  611. width: 171rpx;
  612. font-size: 26rpx;
  613. color: #666;
  614. padding-bottom: 20rpx;
  615. image {
  616. width: 140rpx;
  617. height: 140rpx;
  618. }
  619. }
  620. </style>