vue-music笔记之歌手列表左右两栏联动学习记录

better-scroll实现左右两栏联动

首先对两栏进行基本样式的布局

给右侧字母栏,添加监听事件onShortcutTouchStart,首先传入一个事件参数,利用getData方法获取当前点击元素data-index的值

getData (el, name, val) {
  let prefix = 'data-'
  name = prefix + name
  if (val) {
    //  有值就设置属性
    return el.setAttribute(name, val)
  } else {
    // 这里是获取属性值
    return el.getAttribute(name)
  }
}

e.target代表当前点击元素,点击右侧对应元素,左侧滚动到对应元素

// 点击右侧栏, 滚动的位置
onShortcutTouchStart (e) {
  let anchorIndex = getData(e.target, 'index') // 获取当前点击元素的索引,这个索引是字符串
  let firstTouch = e.touches[0] // 记录刚开始触碰的位置
  this.touch.y1 = firstTouch.pageY // 记录y轴方向的位置
  this.touch.anchorIndex = anchorIndex // 设置点击的索引,共享在两个函数之间
  this._scrollTo(anchorIndex)// 传入当前元素的索引值,滚动到对应元素的位置
},

给右侧字母栏,添加监听事件onShortcutTouchMove事件,实现在右侧滑动,左侧依然跟着联动

    // 在右边触摸移动的位置
    onShortcutTouchMove (e) {
      let firstTouch = e.touches[0] // 记录滑动后松手的位置
      this.touch.y2 = firstTouch.pageY // 手指停止移动的位置
      let delta = Math.floor((this.touch.y2 - this.touch.y1) / ANCHOR_HEIGHT) // 计算偏移了锚点
      let anchorIndex = parseInt(this.touch.anchorIndex) + delta // 将获得的字符串索引,转化成数字 开始锚点加上偏移锚点
      // console.log(delta)
      this._scrollTo(anchorIndex)// 滚动到对应元素的位置
    },

实现左侧滑动,右侧字母栏,对应字母高亮

首先定义,滑动距离scrollY和当前高亮字母索引currentIndex(默认为0)

然定义计算高度方法

   // 计算左侧每组li对应的高度
    _calculateHeight () {
      this.listHeight = []
      const list = this.$refs.listGroup // 拿到所有左侧每个字母li
      let height = 0 // 刚开始高度为 0
      this.listHeight.push(height) // 每个字母li对应的高度
      for (var  
        let item = list[i]
        height += item.clientHeight
        this.listHeight.push(height)
      }
    }
  }
}

在watch 里观测data值变化,调用计算高度的方法

观测scrllY的变化,在里面确定currentIndex的值,实现联动

scrollY (newY) {
  const listHeight = this.listHeight
  // 当滚动到顶部,newY>0
  if (newY > 0) {
    this.currentIndex = 0
  }
  // 在中键部分滚动第一个元素是上线第二个元素的下限,类推所以i总的数目会比列表数要多一个,所以listHeight.length-1
  for (let i = 0; i < listHeight.length - 1; i++) {
    let height1 = listHeight[i]
    let height2 = listHeight[i + 1]
    if (!height2 || (-newY >= height1 && -newY < height2)) {
      this.currentIndex = i
      return
    }
    console.log('索引' + this.currentIndex)
    this.currentIndex = 0
  }
  // 当滚动到底部, 且-newY大于最后一个元素的上限
  this.currentIndex = listHeight.length - 2
  console.log('热门高亮')
}

 

//实现联动的关键是在初始化scroll组件的时候,派发一个scroll事件,并传递一个pos对象,通过监听scroll事件来改变scrollY的值

if (this.listenScroll) {
  let me = this // 保存vue实例上下文
  // 监听滚动事件
  // console.log('监听滚动事件')
  this.scroll.on('scroll', (pos) => {
    console.log(pos)
    me.$emit('scroll', pos) // 派发一个scroll事件,这里如果用this,默认指向scroll
  })
}

 

总代码代码如下

<template>
  <scroll class="listview" ref="listview" :listen-scroll = 'listenScroll' @scroll="scroll" :probe-type = 'probeType' :data="data">
    <ul>
      <!--每个分组热门、A,B....Z-->
      <li v-for="(group, group_list) in data" :key="group_list" class="list-group" ref="listGroup">
        <h2 class="list-group-title">{{group.title}}</h2>
        <ul>
          <!--每个字母分组对应的歌手-->
          <li v-for="(item, index) in group.items" :key="index" class="list-group-item">
            <img class="avatar" v-lazy="item.avatar">
            <span class="name">{{item.name}}</span>
          </li>
        </ul>
      </li>
    </ul>
    <div class="list-shortcut" @touchstart.stop.prevent="onShortcutTouchStart" @touchmove.stop.prevent="onShortcutTouchMove">
      <ul>
        <li v-for="(item, index) in shortcutlist" :class='{current: currentIndex === index}' :data-index="index" :key="index" class="item">
          {{item}}
        </li>
      </ul>
    </div>
  </scroll>
</template>

<script>
import scroll from 'base/scroll/scroll'
import {getData} from 'common/js/dom'
const ANCHOR_HEIGHT = 18 // 这个高度是样式里每个li的高度
export default {
  name: 'listview',
  props: {
    data: {
      type: Array,
      default () {
        return []
      }
    }
  },
  created () {
    this.touch = {} // 这个touch的为什么不在props里定义,原因是这个值不需要vue观测touch的变化
    this.listenScroll = true
    this.listHeight = []
    this.probeType = 3
  },
  components: {
    scroll
  },
  computed: {
    // 右侧字母列表数组
    shortcutlist () {
      return this.data.map((group) => {
        return group.title.substring(0, 1)
      })
    }
  },
  data () {
    return {
      scrollY: -1, // 观测实时滚动位置
      currentIndex: 0 // 当前应该高亮的位置
    }
  },
  watch: {
    data () {
      setTimeout(() => {
        this._calculateHeight()
      }, 20)
    },
    scrollY (newY) {
      const listHeight = this.listHeight
      for (let i = 0; i < listHeight.length; i++) {
        let height1 = listHeight[i]
        let height2 = listHeight[i + 1]
        if (!height2 || (-newY > height1 && -newY < height2)) {
          this.currentIndex = i
          return
        }
        console.log('索引' + this.currentIndex)
        this.currentIndex = 0
      }
      console.log('热门高亮')
    }
  },
  methods: {
    // 点击右侧栏, 滚动的位置
    onShortcutTouchStart (e) {
      let anchorIndex = getData(e.target, 'index') // 获取当前点击元素的索引,这个索引是字符串
      let firstTouch = e.touches[0] // 记录刚开始触碰的位置
      this.touch.y1 = firstTouch.pageY // 记录y轴方向的位置
      this.touch.anchorIndex = anchorIndex // 设置点击的索引,共享在两个函数之间
      this._scrollTo(anchorIndex)
    },
    // 在右边触摸移动的位置
    onShortcutTouchMove (e) {
      let firstTouch = e.touches[0] // 滑动后松手的位置
      this.touch.y2 = firstTouch.pageY // 手指停止移动的位置y坐标
      let delta = Math.floor((this.touch.y2 - this.touch.y1) / ANCHOR_HEIGHT) // 计算偏移了锚点
      let anchorIndex = parseInt(this.touch.anchorIndex) + delta // 将获得的字符串索引,转化成数字 开始锚点加上偏移锚点
      // console.log(delta)
      this._scrollTo(anchorIndex)
    },
    // better-scroll会派发一个pos参数出来
    scroll (pos) {
      this.scrollY = pos.y // 滚动到的位置
    },
    // 滚动到当前点击元素的位置
    _scrollTo (index) {
      this.$refs.listview.scrollToElement(this.$refs.listGroup[index], 0)// scroll组件的滚动到对应元素的方法
    },
    // 计算左侧每组li对应的高度
    _calculateHeight () {
      this.listHeight = []
      const list = this.$refs.listGroup // 拿到所有li
      let height = 0 // 刚开始高度为 0
      this.listHeight.push(height) // 第一个li对应的高度
      for (var i = 0; i < list.length; i++) {
        let item = list[i]
        height += item.clientHeight
        this.listHeight.push(height)
      }

 

莫忘初心,负重前行。
    }
  
</script>

猜你喜欢

转载自blog.csdn.net/hamsterknight/article/details/81229157