Vue + better-scroll реализует навигацию по алфавитному указателю на мобильных устройствах

внешний интерфейс JavaScript Vue.js

vue + better-scrollРеализовать навигацию по алфавитному указателю в списке мобильных исполнителей. Это можно рассматривать как учебную заметку.Напишите заметку, чтобы понять немного глубже.

Демо:list-view, просмотрите его в мобильном режиме Chrome. После перехода в режим мобильного телефона, если вы не можете провести пальцем, обновите его, и все будет в порядке.

Гитхаб:Мобильная навигация по алфавитному указателю(дерзкая просьба о звезде, хе-хе)

визуализация

Среда конфигурации

Поскольку используются Vue-Cli и лучше-прокрутки, сначала установите Vue-CLI, а затем устанавливать NPMbetter-scroll.

Краткое введение в лучшую прокрутку:

Better-scroll — это подключаемый модуль, ориентированный на удовлетворение потребностей различных сценариев прокрутки на мобильном терминале (ПК уже поддерживается). Его ядром является реализация iscroll для справки.Его дизайн API в основном совместим с iscroll, а некоторые функции и оптимизации производительности были расширены на основе iscroll.

better-scroll реализован на основе нативного JS и не зависит ни от какого фреймворка. Размер скомпилированного кода составляет 63 КБ, сжатый — 35 КБ, а gzip — всего 9 КБ, это очень легкая JS-библиотека.

В дополнение к этим двум также используются scss и vue-lazyload. Препроцессор scss, который всем известен, такой же, как и у других. lazyload реализует ленивую загрузку, вы можете обойтись без нее, в основном для оптимизации работы.

Данные напрямую используют список исполнителей NetEase Cloud,Если вам лень, поместите это прямо в данные.

Я не буду публиковать стили CSS, просто посмотрите исходный код.

Реализовать базовые стили

Прямое использование v-for и двухстороннего вложения для реализации списка исполнителей, а также индексной полосы справа.

HTML-структура:

<ul>
  <li v-for="group in singers" 
  class="list-group" 
  :key="group.id" 
  ref="listGroup">
    <h2 class="list-group-title">{{ group.title }}</h2>
    <ul>
      <li v-for="item in group.items" 
      class="list-group-item" :key="item.id">
        <img v-lazy="item.avatar" class="avatar">
        <span class="name">{{ item.name }}</span>
      </li>
    </ul>
  </li>
</ul>
<div class="list-shortcut">
  <ul>
    <li v-for="(item, index) in shortcutList"
    class="item"
    :data-index="index"
    :key="item.id"
    >
      {{ item }}
    </li>
  </ul>
</div>

Список ярлыков получается путем вычисления свойства, достаточно взять первый символ заголовка.

shortcutList () {
  return this.singers.map((group) => {
    return group.title.substr(0, 1)
  })
}

Используйте лучшую прокрутку

Используйте лучшую прокрутку для прокрутки. Кстати, не забывайте использовать импорт при его использовании.

created () {
  // 初始化 better-scroll 必须要等 dom 加载完毕
  setTimeout(() => {
    this._initSrcoll()
  }, 20)
},
methods: {
  _initSrcoll () {
    console.log('didi')
    this.scroll = new BScroll(this.$refs.listView, {
      // 获取 scroll 事件,用来监听。
      probeType: 3
    })
  }
}

Используйте созданный метод для лучшей инициализации прокрутки и используйте setTimeout, потому что вам нужно дождаться загрузки DOM. В противном случае better-scroll не сможет инициализироваться, если не сможет получить дом.

Здесь метод написан двумя методами, чтобы он не выглядел беспорядочно, и его можно было вызвать напрямую.

При инициализации передайте два probeType: 3, чтобы объяснить: когда probeType равен 3, не только в процессе скольжения экрана, но и в процессе анимации прокрутки по импульсу, работающей в реальном времени для отправки событий прокрутки. Если это значение не установлено, его значение по умолчанию равно 0, то есть событие прокрутки не отправляется.

Добавьте события щелчка и переместите события в индекс, чтобы перейти

Во-первых, вам нужно привязать событие touchstart к индексу (срабатывает при нажатии пальцем на экран), просто используйте v-on напрямую. Затем вам нужно добавить индекс данных в индекс, чтобы вы могли получить значение индекса, используйте:data-index="index".

<div class="list-shortcut">
  <ul>
    <li v-for="(item, index) in shortcutList"
    class="item"
    :data-index="index"
    :key="item.id"
    @touchstart="onShortcutStart"
    @touchmove.stop.prevent="onShortcutMove"
    >
      {{ item }}
    </li>
  </ul>
</div>

Привяжите метод onShortcutStart. Реализуйте функцию скачка индекса щелчка. Привяжите другой метод onShortcutMove для реализации скользящего прыжка.

created () {
  // 添加一个 touch 用于记录移动的属性
  this.touch = {}
  // 初始化 better-scroll 必须要等 dom 加载完毕
  setTimeout(() => {
    this._initSrcoll()
  }, 20)
},
methods: {
  _initSrcoll () {
    this.scroll = new BScroll(this.$refs.listView, {
      probeType: 3,
      click: true
    })
  },
  onShortcutStart (e) {
    // 获取到绑定的 index
    let index = e.target.getAttribute('data-index')
    // 使用 better-scroll 的 scrollToElement 方法实现跳转
    this.scroll.scrollToElement(this.$refs.listGroup[index])

    // 记录一下点击时候的 Y坐标 和 index
    let firstTouch = e.touches[0].pageY
    this.touch.y1 = firstTouch
    this.touch.anchorIndex = index
  },
  onShortcutMove (e) {
    // 再记录一下移动时候的 Y坐标,然后计算出移动了几个索引
    let touchMove = e.touches[0].pageY
    this.touch.y2 = touchMove
    
    // 这里的 16.7 是索引元素的高度
    let delta = Math.floor((this.touch.y2 - this.touch.y1) / 18)

    // 计算最后的位置
    // * 1 是因为 this.touch.anchorIndex 是字符串,用 * 1 偷懒的转化一下
    let index = this.touch.anchorIndex * 1 + delta
    this.scroll.scrollToElement(this.$refs.listGroup[index])
  }
}

Таким образом, функция индекса может быть реализована.

Конечно, это нас не удовлетворит, ведь надо добавить крутых спецэффектов. Например, подсветка индекса или что-то в этом роде~~

Подсветка индекса мобильного контента

эммм, это немного сложно в это время. Но вы можете понять это с терпением.

Нам нужен метод on of better-scroll, который возвращает значение смещения по оси Y при прокрутке содержимого. Поэтому вам нужно добавить некоторый код при инициализации better-scroll. Кстати, не забудьте добавить scrollY в данные и currentIndex (используется для записи позиции выделенного индекса), потому что нам нужно слушать, поэтому добавьте его в данные.

_initSrcoll () {
  this.scroll = new BScroll(this.$refs.listView, {
    probeType: 3,
    click: true
  })

  // 监听Y轴偏移的值
  this.scroll.on('scroll', (pos) => {
    this.scrollY = pos.y
  })
}

Затем вам нужно вычислить высоту содержимого и добавить метод calculateHeight() для вычисления высоты проиндексированного содержимого.

_calculateHeight () {
  this.listHeight = []
  const list = this.$refs.listGroup
  let height = 0
  this.listHeight.push(height)
  for (let i = 0; i < list.length; i++) {
    let item = list[i]
    height += item.clientHeight
    this.listHeight.push(height)
  }
}

// [0, 760, 1380, 1720, 2340, 2680, 2880, 3220, 3420, 3620, 3960, 4090, 4920, 5190, 5320, 5590, 5790, 5990, 6470, 7090, 7500, 7910, 8110, 8870]
// 得到这样的值

Затем прослушайте scrollY в часах и посмотрите код:

watch: {
  scrollY (newVal) {
    // 向下滑动的时候 newVal 是一个负数,所以当 newVal > 0 时,currentIndex 直接为 0
    if (newVal > 0) {
      this.currentIndex = 0
      return
    }
    
    // 计算 currentIndex 的值
    for (let i = 0; i < this.listHeight.length - 1; i++) {
      let height1 = this.listHeight[i]
      let height2 = this.listHeight[i + 1]

      if (-newVal >= height1 && -newVal < height2) {
        this.currentIndex = i
        return
      }
    }
    
    // 当超 -newVal > 最后一个高度的时候
    // 因为 this.listHeight 有头尾,所以需要 - 2
    this.currentIndex = this.listHeight.length - 2
  }
}

После получения currentIndex используйте его в html.

给索引绑定 class -->  :class="{'current': currentIndex === index}"

Наконец, измените currentIndex при обработке скользящего индекса.

Поскольку код можно использовать повторно, а пограничные случаи необходимо обрабатывать,

this.scroll.scrollToElement(this.$refs.listGroup[index])

Перепишите функцию, чтобы уменьшить объем кода.

// 在 scrollToElement 的时候,改变 scrollY,因为有 watch 所以就会计算出 currentIndex
scrollToElement (index) {
  // 处理边界情况
  // 因为 index 通过滑动距离计算出来的
  // 所以向上滑超过索引框框的时候就会 < 0,向上就会超过最大值
  if (index < 0) {
    return
  } else if (index > this.listHeight.length - 2) {
    index = this.listHeight.length - 2
  }
  // listHeight 是正的, 所以加个 -
  this.scrollY = -this.listHeight[index]
  this.scroll.scrollToElement(this.$refs.listGroup[index])
}

lazyload

Между прочим, плагин lazyload также повышает удобство работы пользователей.

инструкции

  1. сначала установить npm
  2. импортировать в main.js, затем в Vue.use
import VueLazyload from 'vue-lazyload'

Vue.use(VueLazyload, {
  loading: require('./common/image/default.jpg')
})

Добавьте загрузочное изображение и используйте требование веб-пакета для получения изображения.

  1. Затем, когда вам нужно его использовать, поместите:src=""заменитьv-lazy=""Реализована функция ленивой загрузки картинок.

Суммировать

Навигация по алфавитному указателю на мобильном терминале реализована так, и это все еще кажется мне очень сложным (для меня).

Главное использовать on of better-scroll для получения значения смещения движения (для достижения выделения), и scrollToElement для перехода в соответствующую позицию (для достижения прыжка). И используйте событие касания, чтобы прослушивать касания, чтобы получить начальную позицию и расстояние скольжения (рассчитать конечную позицию).

награда

  • Узнал о сенсорных событиях
  • Немного более опытен в использовании Better-Scroll
  • Vue тоже умеет, эммм
  • У меня будет опыт, чтобы написать что-то подобное в будущем.

Эта статья была первоначально опубликована вBlog of Jin, добро пожаловать вGitHubПодписывайтесь на меня, чтобы начать и вместе изучать интерфейс.