category.vue 15 KB

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