«Постучать по доске» Uniapp реализует левое и правое меню связи

uni-app
«Постучать по доске» Uniapp реализует левое и правое меню связи

предисловие

Я полагаю, что все знакомы с меню, связанными с левой и правой колонками страницы категорий в мобильном приложении торгового центра. Это касается почти всех страниц категорий торговых центров. Я был на связи с uniapp в течение последних двух дней, и я работаю над проектом торгового центра, у которого есть такой спрос, а затем мы используем uniapp для его реализации.

Давайте посмотрим на окончательный рендеринг: "нужно:"

  1. "Левое и правое меню должны иметь возможность прокручиваться независимо друг от друга;"
  2. "Щелкните меню слева и перейдите к соответствующему блоку справа;"
  3. "Сдвиньте меню справа, и соответствующий пункт меню слева активен;"
  4. "Прокрутите вправо, когда левая соответствующая классификация находится вне поля зрения, должны следовать меню влево / прокрутка вниз."

Затем он будет внедряться постепенно в соответствии с потребностями.

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), и то же самое верно для прокрутки вверх, текст очень извилисто? Объедините диаграмму и формулу, чтобы понять:

Затем нам нужно получить информацию об узле, требуемую выше:

  1. Сначала мы получаем информацию о размере и расположении каждого 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();
   
  },
  1. Затем получите информацию об узле прокрутки слева и проследите за изменением 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();
  })
 },

💕 После прочтения трех вещей:

  1. Нравится | Можно点击——>收藏——>退出За один раз, но не забудьте поставить лайк 🤭
  2. Подписывайтесь | Нажмите, чтобы подписаться, не теряйтесь в следующий раз😘
  3. так же доступноGitHubПолучить все исходники моих статей 🤗