話不多說,上demo
<template> <div id="app"> <header>左右列表雙向聯動</header> <div class="content"> <!-- 左側列表 --> <ul class="left_title" ref="left"> <li class="title_item" v-for="(item, index) in cateData" :key="index" :class="currentIndex === index ? 'active' : ''" @click="change(index)" > {{ item.name }} </li> </ul> <!-- 右側內容區域 --> <div class="right_content"> <div class="container" ref="container"> <div ref="foodsUI" class="foodsUI"> <div class="list"> <div class="name">健康蔬菜</div> <ul> <li>蘋果</li> <li>西紅柿</li> <li>番茄</li> </ul> </div> <div class="list"> <div class="name">時令蔬菜</div> <ul> <li>蘋果</li> <li>西紅柿</li> <li>番茄</li> </ul> </div> <div class="list"> <div class="name">撥草</div> <ul> <li>蘋果</li> <li>西紅柿</li> <li>番茄</li> </ul> </div> <div class="list"> <div class="name">1</div> <ul> <li>蘋果</li> <li>西紅柿</li> <li>番茄</li> </ul> </div> <div class="list"> <div class="name">2</div> <ul> <li>蘋果</li> <li>西紅柿</li> <li>番茄</li> </ul> </div> <div class="list"> <div class="name">3</div> <ul> <li>蘋果</li> <li>西紅柿</li> <li>番茄</li> </ul> </div> <div class="list"> <div class="name">4</div> <ul> <li>蘋果</li> <li>西紅柿</li> <li>番茄</li> </ul> </div> <div class="list"> <div class="name">5</div> <ul> <li>蘋果</li> <li>西紅柿</li> <li>番茄</li> </ul> </div> <div class="list"> <div class="name">6</div> <ul> <li>蘋果</li> <li>西紅柿</li> <li>番茄</li> </ul> </div> </div> </div> </div> </div> </div> </template> <script> import BScroll from 'better-scroll' export default { data() { return { scroll: '', // 右側滑動的y軸坐標(滑動過程中的實時變化) scrollY: 0, foodsScroll: '', // 所有右側分類li的top組成的數組 tops: [], cateData: [ { name: '健康蔬菜' }, { name: '時令蔬菜' }, { name: '撥草' }, { name: '1' }, { name: '2' }, { name: '3' }, { name: '4' }, { name: '5' }, { name: '6' } ] } }, methods: { // 初始化滾動 initScroll() { const container = this.$refs.container this.scroll = new BScroll(container) /* eslint-disable no-new */ new BScroll('.left_title', { click: true }) // 監聽右側列表 this.foodsScroll = new BScroll('.container', { // 慣性滑動不會被觸發 probeType: 2, click: true }) // 給右側列表綁定scroll監聽 this.foodsScroll.on('scroll', ({ x, y }) => { // math.abs絕對值 this.scrollY = Math.abs(y) console.log(x, y) }) // 給右側列表綁定滾動結束監聽,滾動結束后改變左側列表背景顏色 this.foodsScroll.on('scrollEnd', ({ x, y }) => { this.scrollY = Math.abs(y) }) }, // 初始化tops _initTops() { // 1.初始化tops const tops = [] let top = 0 tops.push(top) // 2.搜集 // 找到所有分類的li const lis = this.$refs.foodsUI.getElementsByClassName('list') Array.prototype.slice.call(lis).forEach(li => { top += li.clientHeight tops.push(top) }) // 3。更新數據 this.tops = tops console.log(this.tops) }, // 點擊左側列表右側滾動到相應位置 change(index) { // 得到目標scrollY const y = this.tops[index] // 立即更新scrollY this.scrollY = y // 平滑滑動右側列表 this.foodsScroll.scrollTo(0, -y, 300) } }, computed: { // 計算當前分類的下表 currentIndex() { // 得到條件數據 const { scrollY, tops } = this // 根據條件計算產出一個結果 const index = tops.findIndex((top, index) => { return scrollY >= top && scrollY < tops[index + 1] }) // 返會結果 return index } }, mounted() { this.$nextTick(() => { this.initScroll() this._initTops() }) } } </script> <style scoped> header { height: 50px; width: 100%; background-color: green; color: #fff; font-size: 18px; display: flex; justify-content: center; align-items: center; } .content { display: flex; } .left_title { flex: 1; margin-right: 5px; } .title_item { height: 35px; width: 100%; border: 1px solid #ccc; display: flex; justify-content: center; align-items: center; font-size: 18px; border-bottom: none; } .title_item :last-child { border-bottom: 1px solid #ccc; } .right_content { flex: 3; position: relative; } .name { text-align: center; padding: 20px; font-size: 28px; } .list li{ font-size: 20px; } .container { overflow: hidden; height: calc(100vh - 50px); } .active { background-color: red; color: #fff; } .list { height: 200px; border: 1px solid #ccc; } .foodsUI { padding-bottom: 400px; } </style>