vue-music(8) list组件和list组件中的快速入口bar的联动
程序员文章站
2022-03-07 17:24:49
...
list组件整体式一个大Scroll组件,点击每个歌手,进入歌手页面,此处用到的是二级路由
二级路由
<li @click="selectItem(item)" v-for="item in group.items" :key="item.id" class="list-group-item">
添加点击事件
selectItem (item) {
this.$emit('select', item) // 向外派发点击事件 创出被点击的内容 父组件监听,把点击的歌手item当实参传出
},
父组件
<list :data="list" @select="selectSinger" ref="list"></list>
...
二级路由的跳转
selectSinger (item) {
this.$router.push({ // 跳转路由
path: `/singer/${item.id}` // 此处id前面不需要加 ‘ :’
})
this.setSinger(item) // 2.实现数据提交到state
},
在 router/index.js 配置二级路由
router: [
{
path: '/singer',
component: 'Singer',
children: [
{
path: ':id', // 注意冒号不要掉
component: 'SingerDetail'
}
]
}
]
左边列表和右边快速入口bar的联动
在bar的div上添加 事件@touchMove, @touchstart, 实现滑动效果。为了取消冒泡,添.stop.prevent
<div class="list-shortcut" @touchstart.stop.prevent="onShortCutTouchStart" @touchmove.stop.prevent="onShortCutTouchMove">
<ul>
<li v-for="(item,index) in shortCutList" :key="item.id" class="item" :class="{'current':currentIndex===index}" :data-index="index">{{item}}</li>
</ul>
</div>
created () {
this.touch = {} // 定义一个对象用来接收移动的属性
this.listernScroll = true
this.listHeight = []
this.probeType = 3 // bs 类型
},
data () {
return {
// click: true,
scrollY: -1,
currentIndex: 0,
diff: -1
}
},
。。。
onShortCutTouchStart(e){
let touchIndex = getData(e.target, 'index') // 调用getData函数,添加index属性
this.touch.y1 = e.touches[0].pageY // 第一次触摸的y坐标
this.touch.chapter = touchIndex // 触摸到第几个字母
this._scrollTo(touchIndex) //执行跳转函数
}
onShortCutTouchMove(e){\
this.touch.y2 = e.touches[0].pageY // 触摸中的y坐标、
let dleta = (this.touch.y2 - this.touch.y1) / CHAPTER_HEIGHT | 0 // CHAPTER_HEIGHT是字母的高度,根据样式来的。 |0 向下取整 => 得到移动的字母数
let touchIndex = parseInt(this.touch.chapter) + delta // 从记录的起始字母开始移动
this._scrollTo(touchIndex)
},
scroll (position) {
this.scrollY = position.y // bs自带函数 获得实时滚动的y坐标
},
_scrollTo(index){
if (!index) { // 没有点击到bar的字母,不会执行跳转
return
}
// 如果 touchmove 超出范围
if (index < 0) {
index = 0
} else if (index > this.listHeight[index - 2]) {
index = this.listHeight[index - 2]
}
// 使整个的scroll跳转到特定的index位点上,而index是根据右边bar滑动或点击而来的,这样完成左右联动
this.$refs.listView.scrollToElement(this.$refs.listGroup[index], 0) // 0 是缓动时间 scrollToElement是Bscroll 组件中封装的函数,能跳转到指定位置
this.scrollY = -this.listHeight[index] // 改变scrollY实时滚动的y坐标,随之改变 currentindex 高亮显示 因为向下滑动,所以为负值
}
...
function getData (el, name, value) {
const prefix = 'data-'
const newName = prefix + name
if (value) { // 如果有这个值 就获取 返回
return el.setAttribute(newName, value) // 添加自定义属性
}
if (!value) { // 如果没有这个值, 就设置并返回
return el.getAttribute(newName)
}
}
...
watch: {
data () {
setTimeout(() => {
this._calculateHeight() // 监视data,计算高度,渲染数据
}, 20)
},
scrollY (newY) {
const listHeight = this.listHeight
// 1. 当滑动到最上面
if (newY > 0) {
this.currentIndex = 0 // 高亮第一个元素 字母
return
}
// 2. 当在中间部分滚动,length之所以 -1 是因为 为了照顾最后一个元素,当初高度列表定义必须多一个
for (let i = 0; i < listHeight.length - 1; i++) {
let height1 = listHeight[i]
let height2 = listHeight[i + 1]
if (-newY >= height1 && -newY < height2) { // newY 为负值
this.currentIndex = i
this.diff = height2 + newY
return
}
}
// 3. 最后一个
this.currentIndex = listHeight.length - 2
},
// 实现当两个list字母碰撞时,有过渡效果
diff (newValue) {
let fixedTop = (newValue > 0 && newValue < TITLE_HEIGHT) ? newValue - TITLE_HEIGHT : 0
if (this.fixedTop === fixedTop) {
return // 判断如果两个title区块没有碰到,是不会触发 DOM 操作的
}
this.fixedTop = fixedTop
this.$refs.fixed.style.transform = `translate3d(0,${fixedTop}px,0)`
}
},