предисловие
Я полагаю, что все знакомы с меню, связанными с левой и правой колонками страницы категорий в мобильном приложении торгового центра. Это касается почти всех страниц категорий торговых центров. Я был на связи с uniapp в течение последних двух дней, и я работаю над проектом торгового центра, у которого есть такой спрос, а затем мы используем uniapp для его реализации.
Давайте посмотрим на окончательный рендеринг: "нужно:"
- "Левое и правое меню должны иметь возможность прокручиваться независимо друг от друга;"
- "Щелкните меню слева и перейдите к соответствующему блоку справа;"
- "Сдвиньте меню справа, и соответствующий пункт меню слева активен;"
- "Прокрутите вправо, когда левая соответствующая классификация находится вне поля зрения, должны следовать меню влево / прокрутка вниз."
Затем он будет внедряться постепенно в соответствии с потребностями.
1. Используйте компонент прокрутки uniapp для реализации двух меню с независимой прокруткой слева и справа.
Это очень просто, всего два скролл-вьюшки слева и справа, 20% слева и 80% справа, здесь следует отметить, что внешние слои левого и правого скролл-вью могут содержать только один родительский вид , иначе они будут прокручиваться синхронно.
<view class="d-flex h-100" >
<scroll-view class="left-scroll flex-1 border-right" scroll-y>
<view v-for="i in 50" :key="i">{{i}}</view>
</scroll-view>
<scroll-view class="right-scroll flex-3" scroll-y>
<view v-for="i in 50" :key="i">{{i}}</view>
</scroll-view>
</view>
После завершения добавьте активный стиль к пункту меню навигации слева, и сделайте соответствующую оптимизацию перехода, иначе клик будет очень тугим. Затем смоделируйте данные.
<script>
export default {
data(){
return {
activeIndex:0,// 左边当前菜单项的索引
cate: [],//左边导航菜单
list:[]// 右边菜单
}
},
created(){
this.getData()
},
methods:{
getData() {
for (let i = 0; i < 20; i++) {
this.cate.push({
name: '分类' + i
})
}
},
// 点击左边导航栏
changeCate(index) {
this.activeIndex = index
},
}
}
</script>
Следующий шаг — написать макет меню справа и смоделировать данные. Здесь следует обратить внимание на оформление структуры данных справа (которую нужно связать с бэкендом) Во-первых, категорий много, каждая категория имеет имя категории и несколько элементов (массивов), и каждый элемент объект (содержащий несколько элементов). свойство), поэтому используйте двойной цикл for для обхода, подробности см. в коде."html"
<scroll-view scroll-y class="right-scroll flex-3">
<view class="row right-scroll-item" v-for="(item,index) in list" :key="index">
<view class="w-100 text-center text-muted font-md">{{item.name}}</view>
<view class="span24-8 text-center py-2" v-for="(item2 ,index2) in item.list" :key="index2">
<image :src="item2.src" mode="" style="width: 120upx;height: 120upx;"></image>
<text class="d-block text-light-muted font">{{item2.name}}</text>
</view>
</view>
</scroll-view>
"фиктивные данные"
getData() {
for (let i = 0; i < 20; i++) {
this.cate.push({
name: '分类' + i
})
this.list.push({
name: `—— 产品分类${i} ——`,
list: []
})
}
for (let i = 0; i < this.list.length; i++) {
for (let j = 0; j < 24; j++) {
this.list[i].list.push({
src: '/static/images/demo/demomi.png',
name: `分类${i}-商品${j}`
})
}
}
},
2. Щелкните меню слева и перейдите к соответствующему блоку справа.
下文中的top值指的是当前dom距离屏幕顶部的距离,也是在触发事件时该dom向上滚动的距离
Идея этой части состоит в том, чтобы получить расстояние (верхнее) каждого дома слева и справа от верхней части экрана и поместить его в leftDomsTop[] и rightDomsTop[] для резервного копирования.Когда мы нажимаем левую навигацию пункт меню, мы меняем тот же индекс dom справа в Расстояние прокрутки вверх в вертикальном направлении (расстояние прокрутки - это расстояние от вершины dom, соответствующее индексу) может быть немного извилистым, просто прочитайте еще дважды . Компонент scroll-view в uniapp имеет свойство scroll-top, которое может легко изменить верхнее значение.
Как получить максимальное значение всех узлов Официальный сайт uniapp предоставляет намИнформация об узлеAPI, мы копируем код примера официального сайта и трансформируем его: (Примечание: получение информации об узле необходимо сделать после того, как дом повешен, поэтому он должен быть вmounted
Написанная в функции ловушки, соответствующая функция ловушки uniapponReady
)
onReady() {
const query = uni.createSelectorQuery().in(this);
query.selectAll('.left-scroll-item').boundingClientRect(data => {
this.leftDomsTop = data.map(v => v.top)
console.log('左边top:',this.leftDomsTop)
}).exec();
query.selectAll('.right-scroll-item').boundingClientRect(data => {
this.rightDomsTop = data.map(v => v.top)
console.log('右边top:',this.rightDomsTop)
}).exec();
},
Видно, что с помощью вышеуказанного API мы можем легко получить расстояние (верхнее) каждого узла dom слева и справа от вершины.После получения верхнего значения мы сохраняем два ранее определенных массива.Далее, когда мы нажимаем на левое меню, мы меняем Верхнее значение соответствующего меню справа может реализовать левую и правую связь. Для удобства можно добавить анимацию прокрутки (добавьте свойство scroll-with-animation в scroll-view).
// html
<scroll-view scroll-y class="right-scroll flex-3" :scroll-top="rightScrollTop" scroll-with-animation></scroll-view>
// 点击左边导航栏
changeCate(index) {
this.activeIndex = index
// 右边scroll-view滚动到对应区块
this.rightScrollTop = this.rightDomsTop[index]
// console.log(this.rightScrollTop)
},
Взгляните на эффект:
Здесь следует отметить, что изменение верхнего значения меню справа может привести к сбою.Если вы столкнулись с этим, обратитесь к двум решениям, приведенным на официальном сайте.портал
3. Сдвиньте меню справа, активируется соответствующий пункт меню слева.
В этой части, отслеживая событие прокрутки правого меню (@scroll="onRightScroll"), мы можем получить массив верхних значений прокручиваемого справа домена, а затем сопоставить дом с тем же индексом слева, и присвойте значение index свойству activeIndex.
// 监听右边滚动事件
async onRightScroll(e) {
// 匹配当前scrollTop所处的索引
this.rightDomsTop.forEach((v, k) => {
if (v < e.detail.scrollTop + 3) {
this.activeIndex = k
return false
}
})
}
В это время мы все ближе и ближе подходим к цели, давайте взглянем на текущий эффект:
4. При прокрутке справа налево и соответствующей категории вне поля зрения меню слева также прокручивается вверх/вниз.
Сначала коротко о принципе, мы можем следить за изменением activeIndex левого пункта меню, когда левое состояние активно, то leftDomsTop[activeIndex] дома + высота самого дома (cateItemHeight) > высота вида прокрутки слева (H) + само себя. Когда установлено верхнее значение (ST), мы позволяем узлу dom прокручивать свое собственное расстояние по высоте (cateItemHeight), и то же самое верно для прокрутки вверх, текст очень извилисто? Объедините диаграмму и формулу, чтобы понять:
Затем нам нужно получить информацию об узле, требуемую выше:
- Сначала мы получаем информацию о размере и расположении каждого DOM слева через UNIAPP, так что вы можете получить высоту каждого DOM и значение TOP (Leftscrolltop).
onReady() {
const query = uni.createSelectorQuery().in(this);
query.selectAll('.left-scroll-item').fields({
size:true,// 尺寸
rect:true // 布局信息
},data => {
this.cateItemHeight = data.map(v => {
this.cateItemHeight = v.height
return v.top
})
}).exec();
},
- Затем получите информацию об узле прокрутки слева и проследите за изменением activeIndex, а затем оцените в соответствии с вышеизложенным.
wacth:{
activeIndex(newValue,oldValue){
// 获取左边scroll-view的高度,top值
const query = uni.createSelectorQuery().in(this);
query.selectAll('#leftScroll').fields({
size:true,
scrollOffset:true,// 滚动状态
},data =>{
let H = data.height
let ST = data.scrollTop
// 下边
if ((this.leftDomsTop[newValue] + this.cateItemHeight) > (H + ST)) {
return this.leftScrollTop = this.leftDomsTop[newValue] + this.cateItemHeight - H
}
// 上边
if (ST > this.cateItemHeight) {
this.leftScrollTop = this.leftDomsTop[newValue]
}
})
}
}
На этом все требования выполнены, и вы можете вернуться к визуализации в начале статьи. Далее давайте оптимизируем код, так как мы получили информацию об узле в watch и onReady и написали много повторяющегося кода, мы можем инкапсулировать полученную информацию об узле в метод, который можно вызывать там, где он используется.
// 获取节点信息
getElInfo(obj = {}) {
return new Promise((res, rej) => {
let option = {
size: obj.size ? true : false,
rect: obj.rect ? true : false,
scrollOffset: obj.scrollOffset ? true : false,
}
const query = uni.createSelectorQuery().in(this);
let q = obj.all ? query.selectAll(`.${obj.all}-scroll-item`) : query.select('#leftScroll')
q.fields(option, data => {
res(data)
}).exec();
})
},
💕 После прочтения трех вещей:
- Нравится | Можно
点击——>收藏——>退出
За один раз, но не забудьте поставить лайк 🤭 - Подписывайтесь | Нажмите, чтобы подписаться, не теряйтесь в следующий раз😘
- так же доступноGitHubПолучить все исходники моих статей 🤗