list.vue 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. <template>
  2. <view class="content">
  3. <view class="navbar" :style="{position:headerPosition,top:headerTop}">
  4. <view class="nav-item" :class="{current: filterIndex === 0}" @click="tabClick(0)">
  5. 综合排序
  6. </view>
  7. <view class="nav-item" :class="{current: filterIndex === 1}" @click="tabClick(1)">
  8. 销量优先
  9. </view>
  10. <view class="nav-item" :class="{current: filterIndex === 2}" @click="tabClick(2)">
  11. <text>价格</text>
  12. <view class="p-box">
  13. <text :class="{active: priceOrder === 1 && filterIndex === 2}" class="yticon icon-shang"></text>
  14. <text :class="{active: priceOrder === 2 && filterIndex === 2}" class="yticon icon-shang xia"></text>
  15. </view>
  16. </view>
  17. <text class="cate-item yticon icon-fenlei" @click="toggleCateMask('show')"></text>
  18. </view>
  19. <view class="goods-list">
  20. <view
  21. v-for="(item, index) in goodsList" :key="index"
  22. class="goods-item"
  23. @click="navToDetailPage(item)"
  24. >
  25. <view class="image-wrapper">
  26. <image :src="item.image" mode="aspectFill"></image>
  27. </view>
  28. <text class="title clamp">{{item.title}}</text>
  29. <view class="price-box">
  30. <text class="price">{{item.sales_price}}</text>
  31. <text> {{item.sales}} 人已购</text>
  32. </view>
  33. </view>
  34. </view>
  35. <uni-load-more :status="loadingType"></uni-load-more>
  36. <view class="cate-mask" :class="cateMaskState===0 ? 'none' : cateMaskState===1 ? 'show' : ''" @click="toggleCateMask">
  37. <view class="cate-content" @click.stop.prevent="stopPrevent" @touchmove.stop.prevent="stopPrevent">
  38. <scroll-view scroll-y class="cate-list">
  39. <view v-for="item in cateList" :key="item.id">
  40. <view class="cate-item b-b two" :class="{active: item.id==fId}" @click="changeFirst(item.id)">{{item.name}}</view>
  41. <view
  42. v-for="tItem in item.child" :key="tItem.id"
  43. class="cate-item b-b"
  44. :class="{active: tItem.id==sId}"
  45. @click="changeSecond(tItem)">
  46. {{tItem.name}}
  47. </view>
  48. </view>
  49. </scroll-view>
  50. </view>
  51. </view>
  52. </view>
  53. </template>
  54. <script>
  55. import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
  56. export default {
  57. components: {
  58. uniLoadMore
  59. },
  60. data() {
  61. return {
  62. cateMaskState: 0, //分类面板展开状态
  63. headerPosition:"fixed",
  64. headerTop:"0px",
  65. loadingType: 'more', //加载更多状态
  66. filterIndex: 0,
  67. fId: 0, // 已选一级分类
  68. sId: 0, // 已选二级分类id
  69. priceOrder: 0, //1 价格从低到高 2价格从高到低
  70. cateList: [],
  71. goodsList: [],
  72. page:1
  73. };
  74. },
  75. computed:{
  76. },
  77. onShareAppMessage(e){
  78. return{
  79. path: '/pages/product/list?fid='+this.fId+'&sid='+this.sId
  80. };
  81. },
  82. onLoad(options){
  83. // #ifdef H5
  84. this.headerTop = document.getElementsByTagName('uni-page-head')[0].offsetHeight+'px';
  85. // #endif
  86. this.fId = options.fid;
  87. this.sId = options.sid ? options.sid : 0;
  88. this.loadCateList(options.fid,options.sid);
  89. this.loadData();
  90. },
  91. onPageScroll(e){
  92. //兼容iOS端下拉时顶部漂移
  93. if(e.scrollTop>=0){
  94. this.headerPosition = "fixed";
  95. }else{
  96. this.headerPosition = "absolute";
  97. }
  98. },
  99. //下拉刷新
  100. onPullDownRefresh(){
  101. this.loadData('refresh');
  102. },
  103. //加载更多
  104. onReachBottom(){
  105. this.loadData();
  106. },
  107. methods: {
  108. //加载分类
  109. async loadCateList(fid, sid){
  110. const that = this;
  111. //let list = await this.$api.json('cateList');
  112. let list = await this.$api.request('/category/all');
  113. let cateList = list.filter(item=>item.pid == 0);
  114. cateList.forEach(item=>{
  115. let tempList = list.filter(val=>val.pid == item.id);
  116. item.child = tempList;
  117. });
  118. this.cateList = cateList;
  119. },
  120. //加载商品 ,带下拉刷新和上滑加载
  121. async loadData(type='add', loading){
  122. //没有更多直接返回
  123. if(type === 'add'){
  124. if(this.loadingType === 'nomore'){
  125. return;
  126. }
  127. this.loadingType = 'loading';
  128. }else{
  129. this.loadingType = 'more'
  130. }
  131. let by = this.filterIndex == 0 ? 'weigh' : (this.filterIndex == 1 ? 'sales':'sales_price');
  132. let desc = 'desc';
  133. if (this.filterIndex == 2) {
  134. desc = this.priceOrder === 1 ? 'desc': 'asc';
  135. }
  136. if(type === 'refresh'){
  137. this.goodsList = [];
  138. this.page = 1;
  139. }
  140. let goodsList = await this.$api.request('/product/lists', 'GET', {fid:this.fId,sid:this.sId,page:this.page,by:by,desc:desc});
  141. uni.stopPullDownRefresh();
  142. if (!goodsList) {
  143. this.loadingType = 'nomore';
  144. return;
  145. }
  146. this.goodsList = this.goodsList.concat(goodsList);
  147. //判断是否还有下一页,有是more 没有是nomore
  148. this.loadingType = goodsList.length > 20 ? 'nomore' : 'more';
  149. if(goodsList.length < 20){
  150. this.loadingType = 'nomore';
  151. }else{
  152. this.loadingType = 'more';
  153. this.page++;
  154. }
  155. if(type === 'refresh'){
  156. if(loading == 1){
  157. uni.hideLoading()
  158. }else{
  159. uni.stopPullDownRefresh();
  160. }
  161. }
  162. },
  163. //筛选点击
  164. tabClick(index){
  165. if(this.filterIndex === index && index !== 2){
  166. return;
  167. }
  168. this.filterIndex = index;
  169. if(index === 2){
  170. this.priceOrder = this.priceOrder === 1 ? 2: 1;
  171. }else{
  172. this.priceOrder = 0;
  173. }
  174. uni.pageScrollTo({
  175. duration: 300,
  176. scrollTop: 0
  177. })
  178. this.loadData('refresh', 1);
  179. uni.showLoading({
  180. title: '正在加载'
  181. })
  182. },
  183. //显示分类面板
  184. toggleCateMask(type){
  185. let timer = type === 'show' ? 10 : 300;
  186. let state = type === 'show' ? 1 : 0;
  187. this.cateMaskState = 2;
  188. setTimeout(()=>{
  189. this.cateMaskState = state;
  190. }, timer)
  191. },
  192. // 点击一级分类
  193. changeFirst(id){
  194. this.page = 1;
  195. this.fId = id;
  196. this.sId = 0;
  197. this.toggleCateMask();
  198. uni.pageScrollTo({
  199. duration: 300,
  200. scrollTop: 0
  201. });
  202. this.loadData('refresh', 1);
  203. uni.showLoading({
  204. title: '正在加载'
  205. });
  206. },
  207. // 点击二级分类
  208. changeSecond(item){
  209. this.page = 1;
  210. this.fId = item.pid;
  211. this.sId = item.id;
  212. this.toggleCateMask();
  213. uni.pageScrollTo({
  214. duration: 300,
  215. scrollTop: 0
  216. });
  217. this.loadData('refresh', 1);
  218. uni.showLoading({
  219. title: '正在加载'
  220. });
  221. },
  222. //详情
  223. navToDetailPage(item){
  224. uni.navigateTo({
  225. url: `/pages/product/product?id=${item.product_id}`
  226. });
  227. },
  228. stopPrevent(){}
  229. },
  230. }
  231. </script>
  232. <style lang="scss">
  233. page, .content{
  234. background: $page-color-base;
  235. }
  236. .content{
  237. padding-top: 96upx;
  238. }
  239. .navbar{
  240. position: fixed;
  241. left: 0;
  242. top: var(--window-top);
  243. display: flex;
  244. width: 100%;
  245. height: 80upx;
  246. background: #fff;
  247. box-shadow: 0 2upx 10upx rgba(0,0,0,.06);
  248. z-index: 10;
  249. .nav-item{
  250. flex: 1;
  251. display: flex;
  252. justify-content: center;
  253. align-items: center;
  254. height: 100%;
  255. font-size: 30upx;
  256. color: $font-color-dark;
  257. position: relative;
  258. &.current{
  259. color: $base-color;
  260. &:after{
  261. content: '';
  262. position: absolute;
  263. left: 50%;
  264. bottom: 0;
  265. transform: translateX(-50%);
  266. width: 120upx;
  267. height: 0;
  268. border-bottom: 4upx solid $base-color;
  269. }
  270. }
  271. }
  272. .p-box{
  273. display: flex;
  274. flex-direction: column;
  275. .yticon{
  276. display: flex;
  277. align-items: center;
  278. justify-content: center;
  279. width: 30upx;
  280. height: 14upx;
  281. line-height: 1;
  282. margin-left: 4upx;
  283. font-size: 26upx;
  284. color: #888;
  285. &.active{
  286. color: $base-color;
  287. }
  288. }
  289. .xia{
  290. transform: scaleY(-1);
  291. }
  292. }
  293. .cate-item{
  294. display: flex;
  295. justify-content: center;
  296. align-items: center;
  297. height: 100%;
  298. width: 80upx;
  299. position: relative;
  300. font-size: 44upx;
  301. &:after{
  302. content: '';
  303. position: absolute;
  304. left: 0;
  305. top: 50%;
  306. transform: translateY(-50%);
  307. border-left: 1px solid #ddd;
  308. width: 0;
  309. height: 36upx;
  310. }
  311. }
  312. }
  313. /* 分类 */
  314. .cate-mask{
  315. position: fixed;
  316. left: 0;
  317. top: var(--window-top);
  318. bottom: 0;
  319. width: 100%;
  320. background: rgba(0,0,0,0);
  321. z-index: 95;
  322. transition: .3s;
  323. .cate-content{
  324. width: 630upx;
  325. height: 100%;
  326. background: #fff;
  327. float:right;
  328. transform: translateX(100%);
  329. transition: .3s;
  330. }
  331. &.none{
  332. display: none;
  333. }
  334. &.show{
  335. background: rgba(0,0,0,.4);
  336. .cate-content{
  337. transform: translateX(0);
  338. }
  339. }
  340. }
  341. .cate-list{
  342. display: flex;
  343. flex-direction: column;
  344. height: 100%;
  345. .cate-item{
  346. display: flex;
  347. align-items: center;
  348. height: 90upx;
  349. padding-left: 30upx;
  350. font-size: 28upx;
  351. color: #555;
  352. position: relative;
  353. }
  354. .two{
  355. height: 64upx;
  356. color: #303133;
  357. font-size: 30upx;
  358. background: #f8f8f8;
  359. }
  360. .active{
  361. color: $base-color;
  362. }
  363. }
  364. /* 商品列表 */
  365. .goods-list{
  366. display:flex;
  367. flex-wrap:wrap;
  368. padding: 0 30upx;
  369. background: #fff;
  370. .goods-item{
  371. display:flex;
  372. flex-direction: column;
  373. width: 48%;
  374. padding-bottom: 40upx;
  375. &:nth-child(2n+1){
  376. margin-right: 4%;
  377. }
  378. }
  379. .image-wrapper{
  380. width: 100%;
  381. height: 330upx;
  382. border-radius: 3px;
  383. overflow: hidden;
  384. image{
  385. width: 100%;
  386. height: 100%;
  387. opacity: 1;
  388. }
  389. }
  390. .title{
  391. font-size: $font-lg;
  392. color: $font-color-dark;
  393. line-height: 80upx;
  394. }
  395. .price-box{
  396. display: flex;
  397. align-items: center;
  398. justify-content: space-between;
  399. padding-right: 10upx;
  400. font-size: 24upx;
  401. color: $font-color-light;
  402. }
  403. .price{
  404. font-size: $font-lg;
  405. color: $uni-color-primary;
  406. line-height: 1;
  407. &:before{
  408. content: '¥';
  409. font-size: 26upx;
  410. }
  411. }
  412. }
  413. </style>