uniapp實(shí)現(xiàn)左右聯(lián)動(dòng)商品分類頁面
零、前因
我們?cè)谌粘5拈_發(fā)種,這種頁面在項(xiàng)目當(dāng)中經(jīng)常會(huì)用得到,所以本篇文章會(huì)比較注重描述其思路,順帶附上其代碼,以便以后在任何代碼環(huán)境下都能使用上,先介紹一下實(shí)現(xiàn)思路:
- 點(diǎn)擊左側(cè)類別,右側(cè)會(huì)跳轉(zhuǎn)到對(duì)應(yīng)的分類;
- 右側(cè)滾動(dòng)到頂部區(qū)域,左側(cè)自動(dòng)高亮對(duì)應(yīng)的類別。
要求就這么多,可以先看下效果如何:
一、搭建結(jié)構(gòu)
重點(diǎn):使用uniapp的scroll-view
組件,如果是小程序原生開發(fā)也是這個(gè)組件;其次如果是html開發(fā),就自己實(shí)現(xiàn)一個(gè)溢出滾動(dòng)。
廢話不多說,上代碼:
<template> <view class="u-wrap"> <view class="u-menu-wrap"> <scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop" :scroll-into-view="itemId"> <view v-for="(item,index) in tabbar" :key="index" class="u-tab-item" :class="[current == index ? 'u-tab-item-active' : '']" @tap.stop="swichMenu(index)"> <text class="u-line-1">{{item.name}}</text> </view> </scroll-view> <scroll-view :scroll-top="scrollRightTop" scroll-y scroll-with-animation class="right-box" @scroll="rightScroll"> <view class="page-view"> <view class="class-item" :id="'item' + index" v-for="(item , index) in tabbar" :key="index"> <view class="item-title"> <text>{{item.name}}</text> </view> <view class="item-container"> <view class="thumb-box" v-for="(item1, index1) in item.foods" :key="index1" @click="featureC(item1.cat, item1.name)"> <image v-if="item1.icon != ''" class="item-menu-image" :src="item1.icon" mode=""></image> <view v-else class="item-menu-image row-c" style="background-color: #F4F6F8;"><text style="font-size: 20rpx;color: #d0d0d0;">加載失敗</text></view> <view class="item-menu-name">{{item1.name}}</view> </view> </view> </view> </view> </scroll-view> </view> </view> </template>
JavaScript業(yè)務(wù)邏輯代碼:
data() { return { scrollTop: 0, //tab標(biāo)題的滾動(dòng)條位置 oldScrollTop: 0, // tab標(biāo)題的滾動(dòng)條舊位置 current: 0, // 預(yù)設(shè)當(dāng)前項(xiàng)的值 menuHeight: 0, // 左邊菜單的高度 menuItemHeight: 0, // 左邊菜單item的高度 itemId: '', // 欄目右邊scroll-view用于滾動(dòng)的id tabbar: JSON.parse(uni.getStorageSync('categroy')), // 渲染的數(shù)據(jù),放在最后供你們測(cè)試 arr: [], // 儲(chǔ)存距離頂部高度的數(shù)組 scrollRightTop: 0, // 右邊欄目scroll-view的滾動(dòng)條高度 timer: null // 定時(shí)器 } }
CSS代碼:
.u-wrap { /* #ifdef H5 */ height: calc(100vh - var(--window-top)); /* #endif */ display: flex; flex-direction: column; height: 100vh; } .u-search-box { padding: 18rpx 30rpx; } .u-menu-wrap { flex: 1; display: flex; overflow: hidden; } .u-tab-view { width: 200rpx; height: 100%; } .u-tab-item { height: 110rpx; background: #f6f6f6; box-sizing: border-box; display: flex; align-items: center; justify-content: center; font-size: 26rpx; color: #444; font-weight: 400; line-height: 1; } .u-tab-item-active { position: relative; color: #06A446; font-size: 30rpx; font-weight: 500; background: #D6FFE7; } .u-tab-item-active::before { content: ""; position: absolute; border-left: 4px solid #06A446; height: 52rpx; left: 0; top: 29rpx; } .u-tab-view { height: 100%; } .right-box { background-color: rgb(250, 250, 250); } .page-view { padding: 16rpx; } .class-item { margin-bottom: 30rpx; background-color: #fff; padding: 16rpx; border-radius: 8rpx; } .class-item:last-child { min-height: 100vh; } .item-title { font-size: 26rpx; color: $u-main-color; font-weight: bold; } .item-menu-name { margin-top: 8rpx; font-weight: normal; font-size: 24rpx; color: $u-main-color; } .item-container { display: flex; flex-wrap: wrap; } .thumb-box { width: 33.333333%; display: flex; align-items: center; justify-content: center; flex-direction: column; margin-top: 20rpx; } .item-menu-image { width: 120rpx; height: 120rpx; }
二、添加邏輯層業(yè)務(wù)
分別獲取左側(cè)和右側(cè)每一個(gè)類別的高度
我們知道,在uniapp里面沒有window對(duì)象和dom元素,所以如果我們要獲取頁面上的一些節(jié)點(diǎn)信息時(shí),需要通過
uni.createSelectorQuery()
這個(gè)API來獲取,這里不再贅述。—— 《傳送地址》
/** * 獲取一個(gè)目標(biāo)元素的高度 * @elClass 元素的類名 * @dataVal 儲(chǔ)存高度的對(duì)象 */ methods: { getElRect(elClass, dataVal) { new Promise((resolve, reject) => { const query = uni.createSelectorQuery().in(this); query.select('.' + elClass).fields({ size: true }, res => { // 如果節(jié)點(diǎn)尚未生成,res值為null,循環(huán)調(diào)用執(zhí)行 if (!res) { setTimeout(() => { this.getElRect(elClass); }, 10); return; } this[dataVal] = res.height; resolve(); }).exec(); }) } }
計(jì)算右側(cè)每個(gè)分類距離頂部的高度并保存
onReady() { this.getMenuItemTop() }, mehods: { /** * 獲取右邊菜單每個(gè)item到頂部的距離 * 儲(chǔ)存到 arr 數(shù)組里面用于后面滾動(dòng)判斷 */ getMenuItemTop() { new Promise(resolve => { let selectorQuery = uni.createSelectorQuery(); selectorQuery.selectAll('.class-item').boundingClientRect((rects) => { // 如果節(jié)點(diǎn)尚未生成,rects值為[](因?yàn)橛胹electAll,所以返回的是數(shù)組),循環(huán)調(diào)用執(zhí)行 if(!rects.length) { setTimeout(() => { this.getMenuItemTop(); }, 10); return ; } rects.forEach((rect) => { // 視情況而定,這里減去rects[0].top,是因?yàn)榈谝豁?xiàng)頂部可能不是貼到導(dǎo)航欄(比如有個(gè)搜索框的情況) // this.arr.push(rect.top - rects[0].top); this.arr.push(rect.top) resolve(); }) }).exec() }) }, }
監(jiān)聽右側(cè)元素滾動(dòng)時(shí)交互的狀態(tài)
節(jié)點(diǎn)布局交叉狀態(tài) API 可用于監(jiān)聽兩個(gè)或多個(gè)組件節(jié)點(diǎn)在布局位置上的相交狀態(tài)。這一組API常??梢杂糜谕茢嗄承┕?jié)點(diǎn)是否可以被用戶看見、有多大比例可以被用戶看見。這里也不再贅述,不懂的直接閱讀文檔 —— 《傳送地址》
methods: { /** * 觀測(cè)元素相交狀態(tài) * 檢測(cè)右邊scroll-view的id為itemxx的元素與right-box的相交狀態(tài) * 如果跟.right-box底部相交,就動(dòng)態(tài)設(shè)置左邊欄目的活動(dòng)狀態(tài) */ async observer() { this.tabbar.map((val, index) => { let observer = uni.createIntersectionObserver(this); observer.relativeTo('.right-box', { top: 0 }).observe('#item' + index, res => { if (res.intersectionRatio > 0) { let id = res.id.substring(4); this.leftMenuStatus(id); } }) }) }, /** * 設(shè)置左邊菜單的滾動(dòng)狀態(tài) * @index 傳入的 ID */ async leftMenuStatus(index) { this.current = index; // 如果為0,意味著尚未初始化 if (this.menuHeight == 0 || this.menuItemHeight == 0) { await this.getElRect('menu-scroll-view', 'menuHeight'); await this.getElRect('u-tab-item', 'menuItemHeight'); } // 將菜單活動(dòng)item垂直居中 this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2; } }
實(shí)現(xiàn)左側(cè)菜單點(diǎn)擊聯(lián)動(dòng)右側(cè)滾動(dòng)
methods: { /** * 點(diǎn)擊左邊的欄目切換 * @index 傳入的 ID */ async swichMenu(index) { if(this.arr.length == 0) { await this.getMenuItemTop(); } if (index == this.current) return; this.scrollRightTop = this.oldScrollTop; this.$nextTick(function(){ this.scrollRightTop = this.arr[index]; this.current = index; this.leftMenuStatus(index); }) }, }
實(shí)現(xiàn)右側(cè)菜單滾動(dòng)聯(lián)動(dòng)左側(cè)高亮
methods: { /** * 右邊菜單滾動(dòng) * 如果不存在height2,意味著數(shù)據(jù)循環(huán)已經(jīng)到了最后一個(gè),設(shè)置左邊菜單為最后一項(xiàng)即可 */ async rightScroll(e) { this.oldScrollTop = e.detail.scrollTop; if(this.arr.length == 0) { await this.getMenuItemTop(); } if(this.timer) return ; if(!this.menuHeight) { await this.getElRect('menu-scroll-view', 'menuHeight'); } setTimeout(() => { // 節(jié)流 this.timer = null; // scrollHeight為右邊菜單垂直中點(diǎn)位置 // let scrollHeight = e.detail.scrollTop + this.menuHeight / 2; // scrollHeight為右邊菜單頭部位置 let scrollHeight = e.detail.scrollTop + 20; for (let i = 0; i < this.arr.length; i++) { let height1 = this.arr[i]; let height2 = this.arr[i + 1]; if (!height2 || scrollHeight >= height1 && scrollHeight < height2) { this.leftMenuStatus(i); return ; } } }, 10) } }
三、最后tabbar數(shù)據(jù)
[ { "name":"蔬菜水果", "foods":[ { "cat":383, "name":"蔬菜", "icon":"http://nq348.com/uploads/category/20220315/1aeed6fa43b54cd68cce0c4883160f91.png", "key":"蔬菜" }, { "cat":384, "name":"食用菌", "icon":"http://nq348.com/uploads/category/20220418/09839c618b35b510d50151f9a17793ee.png", "key":"食用菌" }, { "cat":385, "name":"水果", "icon":"http://nq348.com/uploads/category/20220418/5294ad2fc7effc9629cbfdb8baf41773.png", "key":"水果" } ] }, { "name":"畜禽養(yǎng)殖", "foods":[ { "cat":388, "name":"禽類", "icon":"http://nq348.com/uploads/category/20220418/da31895fc5a9aacf93fea6f27f08afd7.png", "key":"禽類" }, { "cat":389, "name":"畜類", "icon":"http://nq348.com/uploads/category/20220418/6352081e3f3b36f9360a933676e9452c.png", "key":"畜類" }, { "cat":391, "name":"蛋類", "icon":"http://nq348.com/uploads/category/20220418/d2e7ab4224679c0c796ba3ddd8a68e2f.png", "key":"蛋類" }, { "cat":390, "name":"水產(chǎn)", "icon":"http://nq348.com/uploads/category/20220418/52a1f1baa7617ef4d4e1a4b344b2fce7.png", "key":"水產(chǎn)" } ] }, { "name":"糧油副食", "foods":[ { "cat":393, "name":"米面糧油", "icon":"http://nq348.com/uploads/category/20220418/1bb32e319ecf5aa352b7fe26fc265004.png", "key":"米面糧油" }, { "cat":394, "name":"堅(jiān)果干果", "icon":"http://nq348.com/uploads/category/20220418/6ded13eae4a3b113b5225ca8b99bbfdd.png", "key":"堅(jiān)果干果" }, { "cat":395, "name":"加工食品", "icon":"http://nq348.com/uploads/category/20220418/1e1c10838799de5834aa77f0f9eb8f40.png", "key":"加工食品" }, { "cat":396, "name":"茶煙酒", "icon":"http://nq348.com/uploads/category/20220418/c43cd994e49023c7efdf2b18b1bca30b.png", "key":"茶煙酒" } ] }, { "name":"花卉苗木", "foods":[ { "cat":398, "name":"鮮花盆景", "icon":"http://nq348.com/uploads/category/20220418/b21c44045daaa8b8d148981ba9efc2e0.png", "key":"鮮花盆景" }, { "cat":399, "name":"果樹苗", "icon":"http://nq348.com/uploads/category/20220418/63ee2b902ff0f4d638d8a5ad770f7641.png", "key":"果樹苗" }, { "cat":400, "name":"蔬瓜種子", "icon":"http://nq348.com/uploads/category/20220418/2df521877616ee44fd01aae0434a5815.png", "key":"蔬瓜種子" }, { "cat":401, "name":"經(jīng)濟(jì)作物", "icon":"http://nq348.com/uploads/category/20220418/f85be72a98694befd889f30de45a1d64.png", "key":"經(jīng)濟(jì)作物" } ] }, { "name":"中草藥材", "foods":[ { "cat":403, "name":"全草類", "icon":"http://nq348.com/uploads/category/20220418/01812c1a83f5db7eafbf3bdae927f134.png", "key":"全草類" }, { "cat":405, "name":"根莖皮葉花", "icon":"http://nq348.com/uploads/category/20220418/dca8dcc814401474d4f19ae7394cc209.png", "key":"根莖皮葉花" }, { "cat":406, "name":"滋補(bǔ)品類", "icon":"http://nq348.com/uploads/category/20220418/33b965295811fdd6f5e672e9a3ce34a2.png", "key":"滋補(bǔ)品類" }, { "cat":404, "name":"果實(shí)籽仁類", "icon":"http://nq348.com/uploads/category/20220418/1dc8c46c66b4625d458a7f45787ecef9.png", "key":"果實(shí)籽仁類" } ] }, { "name":"其他", "foods":[ { "cat":434, "name":"包裝", "icon":"http://nq348.com/uploads/category/20220418/ebdfd326333344825adbe81dbd89e2c9.png", "key":"包裝" }, { "cat":435, "name":"安全溯源", "icon":"http://nq348.com/uploads/category/20220418/03230c63f066f46005abf5f576df0ed1.png", "key":"安全溯源" }, { "cat":436, "name":"農(nóng)用百貨", "icon":"http://nq348.com/uploads/category/20220418/93393f2df3264faba86bb449a0c10a79.png", "key":"農(nóng)用百貨" }, { "cat":437, "name":"倉儲(chǔ)物流", "icon":"http://nq348.com/uploads/category/20220418/f553505ebabbcb1bf762b288716cf1e7.png", "key":"倉儲(chǔ)物流" } ] } ]
總結(jié)
到此這篇關(guān)于uniapp實(shí)現(xiàn)左右聯(lián)動(dòng)商品分類頁面的文章就介紹到這了,更多相關(guān)uniapp左右聯(lián)動(dòng)商品分類頁面內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用Promise自定義一個(gè)GET請(qǐng)求的函數(shù)示例代碼
這篇文章主要給大家介紹了關(guān)于如何利用Promise自定義一個(gè)GET請(qǐng)求的函數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Promise具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03JS實(shí)現(xiàn)自動(dòng)閱讀單詞(有道單詞本添加功能)
有道單詞客戶Duan沒有自動(dòng)閱讀的功能, 本文用強(qiáng)大的js實(shí)現(xiàn)了簡(jiǎn)單的自動(dòng)下一個(gè)單詞的功能,需要的朋友可以參考下2016-11-11JS獲取當(dāng)前網(wǎng)址、主機(jī)地址項(xiàng)目根路徑
本文為大家提供JS如何獲取當(dāng)前網(wǎng)址、主機(jī)地址之后的目錄及項(xiàng)目根路徑的方法,喜歡的朋友可以收藏下2013-11-11javascript精確統(tǒng)計(jì)網(wǎng)站訪問量實(shí)例代碼
網(wǎng)站一般都有訪問量統(tǒng)計(jì)工具,比較高效實(shí)用的工具多種多樣,這篇文章主要介紹了javascript精確統(tǒng)計(jì)網(wǎng)站訪問量實(shí)例代碼,感興趣的小伙伴們可以參考一下2015-12-12JavaScript函數(shù)節(jié)流概念與用法實(shí)例詳解
這篇文章主要介紹了JavaScript函數(shù)節(jié)流概念與用法,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript函數(shù)節(jié)流的概念、功能,并分析了函數(shù)節(jié)流的用法與使用技巧,需要的朋友可以參考下2016-06-06