当前位置:   article > 正文

uniapp分类菜单选择或滚动联动_uni-app分类

uni-app分类
  1. <template>
  2. <view class="u-wrap">
  3. <view class="u-menu-wrap">
  4. <scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop"
  5. :scroll-into-view="itemId">
  6. <view v-for="(item, index) in tabbar" :key="index" class="u-tab-item"
  7. :class="[current == index ? 'u-tab-item-active' : '']" @tap.stop="swichMenu(index)">
  8. <text class="u-line-1">{{ item.name }}</text>
  9. </view>
  10. </scroll-view>
  11. <scroll-view :scroll-top="scrollRightTop" scroll-y scroll-with-animation class="right-box"
  12. @scroll="rightScroll">
  13. <view class="page-view">
  14. <view class="class-item" :id="'item' + index" v-for="(item, index) in tabbar" :key="index">
  15. <view class="item-title">
  16. <text>{{ item.name }}</text>
  17. </view>
  18. <view class="item-container">
  19. <view class="thumb-box" v-for="(item1, index1) in item.foods" :key="index1"
  20. @click="featureC(item1.cat, item1.name)">
  21. <img style="width: 162rpx;
  22. height: 162rpx;border-radius: 25rpx;" src="@/static/imgs/mpbg.jpg" alt="">
  23. <view class="contBox">
  24. <view class="title">{{ item1.name }}</view>
  25. <view class="intro">{{ item1.name }}</view>
  26. <view class="btnBox">
  27. <view class="btn">查看</view>
  28. </view>
  29. </view>
  30. </view>
  31. </view>
  32. </view>
  33. </view>
  34. </scroll-view>
  35. </view>
  36. </view>
  37. </template>
  38. <script>
  39. export default {
  40. data() {
  41. return {
  42. scrollTop: 0, //tab标题的滚动条位置
  43. oldScrollTop: 0, // tab标题的滚动条旧位置
  44. current: 0, // 预设当前项的值
  45. menuHeight: 0, // 左边菜单的高度
  46. menuItemHeight: 0, // 左边菜单item的高度
  47. itemId: '', // 栏目右边scroll-view用于滚动的id
  48. tabbar: [
  49. {
  50. "name": "案例类型",
  51. "foods": [
  52. {
  53. "cat": 383,
  54. "name": "港珠澳大桥",
  55. "icon": "http://nq348.com/uploads/category/20220315/1aeed6fa43b54cd68cce0c4883160f91.png",
  56. "key": "蔬菜"
  57. },
  58. {
  59. "cat": 384,
  60. "name": "港珠澳大桥",
  61. "icon": "http://nq348.com/uploads/category/20220418/09839c618b35b510d50151f9a17793ee.png",
  62. "key": "食用菌"
  63. },
  64. {
  65. "cat": 385,
  66. "name": "港珠澳大桥",
  67. "icon": "http://nq348.com/uploads/category/20220418/5294ad2fc7effc9629cbfdb8baf41773.png",
  68. "key": "水果"
  69. }
  70. ]
  71. },
  72. {
  73. "name": "畜禽养殖",
  74. "foods": [
  75. {
  76. "cat": 388,
  77. "name": "禽类",
  78. "icon": "http://nq348.com/uploads/category/20220418/da31895fc5a9aacf93fea6f27f08afd7.png",
  79. "key": "禽类"
  80. },
  81. {
  82. "cat": 389,
  83. "name": "畜类",
  84. "icon": "http://nq348.com/uploads/category/20220418/6352081e3f3b36f9360a933676e9452c.png",
  85. "key": "畜类"
  86. },
  87. {
  88. "cat": 391,
  89. "name": "蛋类",
  90. "icon": "http://nq348.com/uploads/category/20220418/d2e7ab4224679c0c796ba3ddd8a68e2f.png",
  91. "key": "蛋类"
  92. },
  93. {
  94. "cat": 390,
  95. "name": "水产",
  96. "icon": "http://nq348.com/uploads/category/20220418/52a1f1baa7617ef4d4e1a4b344b2fce7.png",
  97. "key": "水产"
  98. }
  99. ]
  100. },
  101. {
  102. "name": "粮油副食",
  103. "foods": [
  104. {
  105. "cat": 393,
  106. "name": "米面粮油",
  107. "icon": "http://nq348.com/uploads/category/20220418/1bb32e319ecf5aa352b7fe26fc265004.png",
  108. "key": "米面粮油"
  109. },
  110. {
  111. "cat": 394,
  112. "name": "坚果干果",
  113. "icon": "http://nq348.com/uploads/category/20220418/6ded13eae4a3b113b5225ca8b99bbfdd.png",
  114. "key": "坚果干果"
  115. },
  116. {
  117. "cat": 395,
  118. "name": "加工食品",
  119. "icon": "http://nq348.com/uploads/category/20220418/1e1c10838799de5834aa77f0f9eb8f40.png",
  120. "key": "加工食品"
  121. },
  122. {
  123. "cat": 396,
  124. "name": "茶烟酒",
  125. "icon": "http://nq348.com/uploads/category/20220418/c43cd994e49023c7efdf2b18b1bca30b.png",
  126. "key": "茶烟酒"
  127. }
  128. ]
  129. },
  130. {
  131. "name": "花卉苗木",
  132. "foods": [
  133. {
  134. "cat": 398,
  135. "name": "鲜花盆景",
  136. "icon": "http://nq348.com/uploads/category/20220418/b21c44045daaa8b8d148981ba9efc2e0.png",
  137. "key": "鲜花盆景"
  138. },
  139. {
  140. "cat": 399,
  141. "name": "果树苗",
  142. "icon": "http://nq348.com/uploads/category/20220418/63ee2b902ff0f4d638d8a5ad770f7641.png",
  143. "key": "果树苗"
  144. },
  145. {
  146. "cat": 400,
  147. "name": "蔬瓜种子",
  148. "icon": "http://nq348.com/uploads/category/20220418/2df521877616ee44fd01aae0434a5815.png",
  149. "key": "蔬瓜种子"
  150. },
  151. {
  152. "cat": 401,
  153. "name": "经济作物",
  154. "icon": "http://nq348.com/uploads/category/20220418/f85be72a98694befd889f30de45a1d64.png",
  155. "key": "经济作物"
  156. }
  157. ]
  158. },
  159. {
  160. "name": "中草药材",
  161. "foods": [
  162. {
  163. "cat": 403,
  164. "name": "全草类",
  165. "icon": "http://nq348.com/uploads/category/20220418/01812c1a83f5db7eafbf3bdae927f134.png",
  166. "key": "全草类"
  167. },
  168. {
  169. "cat": 405,
  170. "name": "根茎皮叶花",
  171. "icon": "http://nq348.com/uploads/category/20220418/dca8dcc814401474d4f19ae7394cc209.png",
  172. "key": "根茎皮叶花"
  173. },
  174. {
  175. "cat": 406,
  176. "name": "滋补品类",
  177. "icon": "http://nq348.com/uploads/category/20220418/33b965295811fdd6f5e672e9a3ce34a2.png",
  178. "key": "滋补品类"
  179. },
  180. {
  181. "cat": 404,
  182. "name": "果实籽仁类",
  183. "icon": "http://nq348.com/uploads/category/20220418/1dc8c46c66b4625d458a7f45787ecef9.png",
  184. "key": "果实籽仁类"
  185. }
  186. ]
  187. },
  188. {
  189. "name": "其他",
  190. "foods": [
  191. {
  192. "cat": 434,
  193. "name": "包装",
  194. "icon": "http://nq348.com/uploads/category/20220418/ebdfd326333344825adbe81dbd89e2c9.png",
  195. "key": "包装"
  196. },
  197. {
  198. "cat": 435,
  199. "name": "安全溯源",
  200. "icon": "http://nq348.com/uploads/category/20220418/03230c63f066f46005abf5f576df0ed1.png",
  201. "key": "安全溯源"
  202. },
  203. {
  204. "cat": 436,
  205. "name": "农用百货",
  206. "icon": "http://nq348.com/uploads/category/20220418/93393f2df3264faba86bb449a0c10a79.png",
  207. "key": "农用百货"
  208. },
  209. {
  210. "cat": 437,
  211. "name": "仓储物流",
  212. "icon": "http://nq348.com/uploads/category/20220418/f553505ebabbcb1bf762b288716cf1e7.png",
  213. "key": "仓储物流"
  214. }
  215. ]
  216. }
  217. ], // 渲染的数据,放在最后供你们测试
  218. arr: [], // 储存距离顶部高度的数组
  219. scrollRightTop: 0, // 右边栏目scroll-view的滚动条高度
  220. timer: null // 定时器
  221. }
  222. },
  223. onReady() {
  224. this.getMenuItemTop()
  225. },
  226. methods: {
  227. getElRect(elClass, dataVal) {
  228. new Promise((resolve, reject) => {
  229. const query = uni.createSelectorQuery().in(this);
  230. query.select('.' + elClass).fields({
  231. size: true
  232. }, res => {
  233. // 如果节点尚未生成,res值为null,循环调用执行
  234. if (!res) {
  235. setTimeout(() => {
  236. this.getElRect(elClass);
  237. }, 10);
  238. return;
  239. }
  240. this[dataVal] = res.height;
  241. resolve();
  242. }).exec();
  243. })
  244. },
  245. getMenuItemTop() {
  246. new Promise(resolve => {
  247. let selectorQuery = uni.createSelectorQuery();
  248. selectorQuery.selectAll('.class-item').boundingClientRect((rects) => {
  249. // 如果节点尚未生成,rects值为[](因为用selectAll,所以返回的是数组),循环调用执行
  250. if (!rects.length) {
  251. setTimeout(() => {
  252. this.getMenuItemTop();
  253. }, 10);
  254. return;
  255. }
  256. rects.forEach((rect) => {
  257. // 视情况而定,这里减去rects[0].top,是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)
  258. // this.arr.push(rect.top - rects[0].top);
  259. this.arr.push(rect.top)
  260. resolve();
  261. })
  262. }).exec()
  263. })
  264. },
  265. /**
  266. * 观测元素相交状态
  267. * 检测右边scroll-view的id为itemxx的元素与right-box的相交状态
  268. * 如果跟.right-box底部相交,就动态设置左边栏目的活动状态
  269. */
  270. async observer() {
  271. this.tabbar.map((val, index) => {
  272. let observer = uni.createIntersectionObserver(this);
  273. observer.relativeTo('.right-box', {
  274. top: 0
  275. }).observe('#item' + index, res => {
  276. if (res.intersectionRatio > 0) {
  277. let id = res.id.substring(4);
  278. this.leftMenuStatus(id);
  279. }
  280. })
  281. })
  282. },
  283. /**
  284. * 设置左边菜单的滚动状态
  285. * @index 传入的 ID
  286. */
  287. async leftMenuStatus(index) {
  288. this.current = index;
  289. // 如果为0,意味着尚未初始化
  290. if (this.menuHeight == 0 || this.menuItemHeight == 0) {
  291. await this.getElRect('menu-scroll-view', 'menuHeight');
  292. await this.getElRect('u-tab-item', 'menuItemHeight');
  293. }
  294. // 将菜单活动item垂直居中
  295. this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
  296. },
  297. /**
  298. * 点击左边的栏目切换
  299. * @index 传入的 ID
  300. */
  301. async swichMenu(index) {
  302. if (this.arr.length == 0) {
  303. await this.getMenuItemTop();
  304. }
  305. if (index == this.current) return;
  306. this.scrollRightTop = this.oldScrollTop;
  307. this.$nextTick(function () {
  308. this.scrollRightTop = this.arr[index];
  309. this.current = index;
  310. this.leftMenuStatus(index);
  311. })
  312. },
  313. /**
  314. * 右边菜单滚动
  315. * 如果不存在height2,意味着数据循环已经到了最后一个,设置左边菜单为最后一项即可
  316. */
  317. async rightScroll(e) {
  318. this.oldScrollTop = e.detail.scrollTop;
  319. if (this.arr.length == 0) {
  320. await this.getMenuItemTop();
  321. }
  322. if (this.timer) return;
  323. if (!this.menuHeight) {
  324. await this.getElRect('menu-scroll-view', 'menuHeight');
  325. }
  326. setTimeout(() => { // 节流
  327. this.timer = null;
  328. // scrollHeight为右边菜单垂直中点位置
  329. // let scrollHeight = e.detail.scrollTop + this.menuHeight / 2;
  330. // scrollHeight为右边菜单头部位置
  331. let scrollHeight = e.detail.scrollTop + 20;
  332. for (let i = 0; i < this.arr.length; i++) {
  333. let height1 = this.arr[i];
  334. let height2 = this.arr[i + 1];
  335. if (!height2 || scrollHeight >= height1 && scrollHeight < height2) {
  336. this.leftMenuStatus(i);
  337. return;
  338. }
  339. }
  340. }, 10)
  341. }
  342. }
  343. }
  344. </script>
  345. <style scoped>
  346. page {
  347. background: #fff !important;
  348. }
  349. .u-wrap {
  350. /* #ifdef H5 */
  351. height: calc(100vh - var(--window-top));
  352. /* #endif */
  353. display: flex;
  354. flex-direction: column;
  355. height: 100vh;
  356. background: #fff;
  357. }
  358. .u-search-box {
  359. padding: 18rpx 30rpx;
  360. }
  361. .u-menu-wrap {
  362. flex: 1;
  363. display: flex;
  364. overflow: hidden;
  365. }
  366. .u-tab-view {
  367. width: 158rpx;
  368. height: 100%;
  369. }
  370. .u-tab-item {
  371. width: 158rpx;
  372. height: 152rpx;
  373. background: #f8f8f8;
  374. box-sizing: border-box;
  375. display: flex;
  376. align-items: center;
  377. justify-content: center;
  378. font-size: 24rpx;
  379. color: #9a9a9a;
  380. font-weight: 400;
  381. line-height: 1;
  382. }
  383. .u-tab-item-active {
  384. position: relative;
  385. color: #302e27;
  386. font-size: 24rpx;
  387. font-weight: 500;
  388. background: #ffffff;
  389. }
  390. .u-tab-item-active::before {
  391. content: "";
  392. position: absolute;
  393. border-left: 4px solid #294994;
  394. height: 52rpx;
  395. left: 0;
  396. top: 50rpx;
  397. }
  398. .u-tab-view {
  399. height: 100%;
  400. }
  401. .right-box {
  402. background-color: rgb(250, 250, 250);
  403. }
  404. .page-view {
  405. width: 592rpx;
  406. }
  407. .class-item {
  408. background-color: #fff;
  409. padding: 0 24rpx;
  410. padding-bottom: 10rpx;
  411. margin-bottom: 20rpx;
  412. border-radius: 8rpx;
  413. }
  414. .class-item:last-child {
  415. min-height: 100vh;
  416. }
  417. .item-title {
  418. padding: 18rpx 0;
  419. color: #2d2e2e;
  420. font-size: 24rpx;
  421. position: sticky;
  422. top: 0;
  423. background: #ffffff;
  424. font-weight: 700;
  425. }
  426. .item-container {
  427. /* display: flex; */
  428. /* flex-wrap: wrap; */
  429. }
  430. .thumb-box {
  431. /* width: 33.333333%; */
  432. display: flex;
  433. /* align-items: center; */
  434. justify-content: start;
  435. /* flex-direction: column; */
  436. margin-top: 20rpx;
  437. }
  438. .item-menu-image {
  439. width: 120rpx;
  440. height: 120rpx;
  441. }
  442. .contBox {
  443. width: 406rpx;
  444. padding-left: 22rpx;
  445. }
  446. .title {
  447. width: 100%;
  448. overflow: hidden;
  449. font-weight: 700;
  450. font-size: 24rpx;
  451. margin-bottom: 8rpx;
  452. }
  453. .intro {
  454. color: #a9b7c8;
  455. font-size: 22rpx;
  456. height: 80rpx;
  457. overflow: hidden;
  458. }
  459. .btnBox {
  460. display: flex;
  461. justify-content: flex-end;
  462. }
  463. .btn {
  464. height: 36rpx;
  465. padding: 0 10rpx;
  466. text-align: center;
  467. line-height: 36rpx;
  468. font-size: 24rpx;
  469. border-radius: 25rpx;
  470. background: #294994;
  471. color: #fff;
  472. }
  473. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/312464
推荐阅读
相关标签
  

闽ICP备14008679号