CateFive.vue 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. <template>
  2. <view class="clearfix" :class="['qn-page-' + theme]">
  3. <view class="float_left">
  4. <scroll-view scroll-y class="left-aside" :style="{ height: 'calc(100vh - 112rpx - ' + (isBang ? '84px' : '50px') + ')' }">
  5. <view v-for="item in cate_list" :key="item.id" class="f-item b-b ellipsis" :class="{ active: item.id === current_item.id }" @click="tabtap(item)">
  6. <view v-if="item.id === current_item.id" class="active-line primary-bg"></view>
  7. {{ item.title }}
  8. </view>
  9. </scroll-view>
  10. </view>
  11. <view class="float_right">
  12. <!-- 二级下拉菜单 -->
  13. <view class="two-cate">
  14. <scroll-view :scroll-x="true" scroll-with-animation class="two-cate-scroll" :scroll-left="two_cate_scroll">
  15. <view
  16. v-for="(item, index) in current_item.children"
  17. :key="index"
  18. :class="[tow_current === index ? 'primary-btn-pain' : '']"
  19. class="cate-two-li"
  20. @click="twoCateChange(index, item)"
  21. >
  22. {{ item.title }}
  23. </view>
  24. </scroll-view>
  25. </view>
  26. <scroll-view
  27. scroll-y
  28. scroll-with-animation
  29. class="right-aside"
  30. :style="{ height: 'calc(100vh - 188rpx - ' + (isBang ? '84px' : '50px') + ')' }"
  31. :scroll-top="scroll_right_top"
  32. @scroll="rightScroll"
  33. >
  34. <view v-for="(titem, tindex) in current_item.children" :key="tindex" class="cate-ul" :id="'item' + tindex">
  35. <block v-if="titem.children.length">
  36. <view class="cate-name">{{ titem.title }}</view>
  37. <view class="clearfix">
  38. <view
  39. class="cate-li"
  40. v-for="(item, index) in titem.children"
  41. :key="index"
  42. @click="goPage('/pagesT/productDetail/productDetail?id=' + item.id + '&name=' + item.title)"
  43. >
  44. <view class="cate-img-view">
  45. <image v-if="item.images" :src="item.images" mode="aspectFill" class="cate-img"></image>
  46. <view class="ibonfont ibonleimupinleifenleileibie cate-img-icon" v-else></view>
  47. </view>
  48. <view class="cate-tit ellipsis">{{ item.title }}</view>
  49. </view>
  50. </view>
  51. </block>
  52. </view>
  53. </scroll-view>
  54. </view>
  55. </view>
  56. </template>
  57. <script>
  58. export default {
  59. data() {
  60. return {
  61. cate_list: [],
  62. tow_current: 0,
  63. current_item: {},
  64. scroll_right_top: 0, // 右边三级分类栏目scroll-view的滚动条高度
  65. old_scroll_top: 0,
  66. option_arr: [], // 把3级分类的每一块位置信息存储到数组中
  67. two_cate_scroll: 0, // 2级分类滚动
  68. menu_width: 0, // 2级分类菜单的宽度
  69. menu_item_width: 0, // 2级分类菜单item的宽度
  70. timer: null, // 定时器
  71. menu_height: 0 // 3级菜单高度
  72. };
  73. },
  74. computed: {
  75. isBang() {
  76. return this.$_utils.modelmes();
  77. },
  78. userId() {
  79. return this.$store.state.userStatus.id;
  80. }
  81. },
  82. created() {
  83. this.getAllCategory();
  84. },
  85. methods: {
  86. // 分类列表 getAllCategory
  87. getAllCategory() {
  88. this.$u.api
  89. .getAllCategory({
  90. userCenterId: this.userId || 0
  91. })
  92. .then(({ data }) => {
  93. this.cate_list = data;
  94. if (data.length) {
  95. this.current_item = data[0];
  96. }
  97. this.getMenuItemTop();
  98. });
  99. },
  100. // 一级分类切换
  101. tabtap(row) {
  102. this.current_item = row;
  103. this.tow_current = 0;
  104. },
  105. // 2级分类切换
  106. async twoCateChange(index, row) {
  107. if (this.option_arr.length == 0) {
  108. await this.getMenuItemTop();
  109. }
  110. if (row.id == this.two_id) return;
  111. this.scroll_right_top = this.old_scroll_top;
  112. this.$nextTick(() => {
  113. this.scroll_right_top = this.option_arr[index];
  114. this.tow_current = index;
  115. this.twoMenuStatus(index, 1);
  116. });
  117. },
  118. // 3级分类列表滚动
  119. async rightScroll(e) {
  120. this.old_scroll_top = e.detail.scrollTop;
  121. // if(this.option_arr.length == 0) {
  122. // await this.getMenuItemTop();
  123. // }
  124. // if(this.timer) return ;
  125. // if(!this.menu_height) {
  126. // await this.getElRect('right-aside', 'menu_height','height');
  127. // }
  128. // setTimeout(() => { // 节流
  129. // this.timer = null;
  130. // // scrollHeight为右边菜单垂直中点位置
  131. // let scrollHeight = e.detail.scrollTop + this.menu_height / 2;
  132. // for (let i = 0; i < this.option_arr.length; i++) {
  133. // let height1 = this.option_arr[i];
  134. // let height2 = this.option_arr[i + 1];
  135. // // 如果不存在height2,意味着数据循环已经到了最后一个,设置2级菜单为最后一项即可
  136. // if (!height2 || scrollHeight >= height1 && scrollHeight < height2) {
  137. // this.twoMenuStatus(i);
  138. // return ;
  139. // }
  140. // }
  141. // }, 10)
  142. },
  143. // 设置2级分类的滚动状态
  144. async twoMenuStatus(index) {
  145. this.tow_current = index;
  146. // 如果为0,意味着尚未初始化
  147. if (this.menu_width == 0 || this.menu_item_width == 0) {
  148. await this.getElRect('two-cate-scroll', 'menu_width', 'width');
  149. await this.getElRect('cate-two-li', 'menu_item_width', 'width');
  150. }
  151. // 将菜单活动item居中
  152. this.two_cate_scroll = index * this.menu_width + this.menu_item_width / 2 - this.menu_width / 2;
  153. },
  154. // 获取3级分类列表菜单每个item到顶部的距离
  155. getMenuItemTop() {
  156. new Promise(resolve => {
  157. let selectorQuery = uni.createSelectorQuery().in(this);
  158. //添加节点的布局位置的查询请求
  159. selectorQuery
  160. .selectAll('.cate-ul')
  161. .boundingClientRect(rects => {
  162. // 如果节点尚未生成,rects值为[](因为用selectAll,所以返回的是数组),循环调用执行
  163. if (!rects.length) {
  164. setTimeout(() => {
  165. this.getMenuItemTop();
  166. }, 10);
  167. return;
  168. }
  169. rects.forEach(rect => {
  170. // 这里减去rects[0].top,是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)
  171. this.option_arr.push(rect.top - rects[0].top);
  172. resolve();
  173. });
  174. })
  175. .exec();
  176. });
  177. },
  178. // 获取一个目标元素的宽度
  179. getElRect(elClass, dataVal, option) {
  180. new Promise((resolve, reject) => {
  181. const query = uni.createSelectorQuery().in(this);
  182. query
  183. .select('.' + elClass)
  184. .fields(
  185. {
  186. size: true
  187. },
  188. res => {
  189. // 如果节点尚未生成,res值为null,循环调用执行
  190. if (!res) {
  191. setTimeout(() => {
  192. this.getElRect(elClass, dataVal);
  193. }, 10);
  194. return;
  195. }
  196. this[dataVal] = res[option];
  197. resolve();
  198. }
  199. )
  200. .exec();
  201. });
  202. }
  203. }
  204. };
  205. </script>
  206. <style lang="scss">
  207. .left-aside {
  208. width: 200upx;
  209. background-color: #f5f6f7;
  210. /* #ifdef H5||MP */
  211. height: calc(100vh - 130upx);
  212. /*#endif*/
  213. /* #ifdef APP-PLUS */
  214. height: 100vh;
  215. /*#endif*/
  216. .f-item {
  217. -webkit-line-clamp: 1;
  218. width: 100%;
  219. height: 80upx;
  220. line-height: 80rpx;
  221. padding-left: 48rpx;
  222. margin-bottom: 10rpx;
  223. font-size: 26upx;
  224. color: #4b4b4b;
  225. position: relative;
  226. &.active {
  227. color: #000000;
  228. font-size: 32upx;
  229. font-weight: bold;
  230. background-color: #ffffff;
  231. border-radius: 100rpx 0 0 100rpx;
  232. }
  233. .active-line {
  234. position: absolute;
  235. left: 28rpx;
  236. top: 50%;
  237. transform: translateY(-50%);
  238. height: 24upx;
  239. width: 4upx;
  240. border-radius: 4rpx;
  241. }
  242. }
  243. }
  244. .two-cate {
  245. .two-cate-scroll {
  246. width: 550upx;
  247. padding: 14rpx 0;
  248. white-space: nowrap;
  249. .cate-two-li {
  250. padding: 0 32rpx;
  251. display: inline-block;
  252. font-size: 24rpx;
  253. margin-left: 16rpx;
  254. border: 1px solid #f5f6f7;
  255. background-color: #f5f6f7;
  256. border-radius: 50rpx;
  257. height: 48rpx;
  258. line-height: 48rpx;
  259. &:last-child {
  260. margin-right: 40rpx;
  261. }
  262. &:first-child {
  263. margin-left: 40rpx;
  264. }
  265. }
  266. }
  267. }
  268. .right-aside {
  269. /* #ifdef H5||MP */
  270. height: calc(100vh - 140upx);
  271. /*#endif*/
  272. /* #ifdef APP-PLUS */
  273. height: 100vh;
  274. /*#endif*/
  275. width: 550upx;
  276. .cate-name {
  277. padding-top: 20rpx;
  278. padding-left: 40rpx;
  279. font-size: 26rpx;
  280. font-weight: 600;
  281. color: #000000;
  282. }
  283. .cate-li {
  284. float: left;
  285. width: 130upx;
  286. text-align: center;
  287. margin: 20upx 0 20rpx 40rpx;
  288. .cate-img-view {
  289. width: 130rpx;
  290. height: 104rpx;
  291. background: #f5f7f7;
  292. border-radius: 8px;
  293. margin-bottom: 24rpx;
  294. .cate-img {
  295. width: 84upx;
  296. height: 84upx;
  297. border-radius: 8upx;
  298. display: block;
  299. margin: 0 auto;
  300. transform: translateY(10rpx);
  301. }
  302. .cate-img-icon {
  303. font-size: 80upx;
  304. width: 84upx;
  305. line-height: 84upx;
  306. color: #eeeeee;
  307. height: 84upx;
  308. border-radius: 8upx;
  309. margin: 0 auto;
  310. transform: translateY(10rpx);
  311. }
  312. }
  313. .cate-tit {
  314. font-size: 24upx;
  315. font-weight: 400;
  316. color: #3a3a3a;
  317. width: 100%;
  318. -webkit-line-clamp: 1;
  319. }
  320. }
  321. }
  322. </style>