list.vue 8.5 KB

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