Vue(用better-scroll實現滑動效果)
一、前言
1、效果演示
2、實現分析
3、具體實現
4、完整代碼
二、主要內容
1、效果演示
(1)文字說明:滑動右側左側對應的類別顯示高亮,點擊左側的類別名稱右側滑動到對應的位置
(2)圖示
2、實現分析
(1)分析:滑動右側的時候左側對應的類高亮,高亮顯示是通過current類來控制的,當右邊滑動到不同個類的時候,同時更新左側的current的顯示。
(2)要做的事情: ①current來設置當前高亮, ②要實時監聽scrollY, ③將右側每一個類的頂部位置記錄下來
(3)根據滑動的位置scrollY,與記錄的每個類的頂部,來計算當前下標
3、具體實現
第零步:在data中定義兩個屬性,分別來接收滑動的scrollY的值,和右側每個分類的位置
data(){ return{ scrollY:0, tops:[] //存放每一個類的初始位置 } }
第一步:用到better-scroll庫(http://ustbhuangyi.github.io/better-scroll/doc/api.html)
/*下載better-scroll庫*/ npm install better-scroll -S
第二步:在組件中引入這個庫,並且分別創建左右兩個滑動列表,註意這個滑動列表時後臺數據異步請求完成之後才創建的,所以在this.$nextTick()裏面創建這兩個滑動列表
mounted(){ //異步請求可以傳過去兩個參數, this.$store.dispatch(‘getShopGoods‘,()=>{ //數據請求完之後再執行這裏了 //初始化左邊滾動this.$nextTick(()=>{ new BScroll(‘.menu-wrapper‘,{ click:true }) //創建右邊的滾動 this.foodswrapper = new BScroll(‘.foods-wrapper‘,{ click:true, probeType:3 }) }) }) }
第三步:將獲取當前scrollY的函數,和獲取右側top的函數提取出來,定義在method中
methods:{ //獲取scrollY _initScrollY() //獲取右側tops _initTops() }
第四步:實現_initScrollY()
//初始化BScroll _initScrollY(){ new BScroll(‘.menu-wrapper‘,{ click:true //滑動列表默認是沒有點擊的,必須加上這個才能出發點擊事件 }) //創建右邊的 this.foodswrapper = new BScroll(‘.foods-wrapper‘,{ click:true, probeType:2 //這裏可以取4個值:默認為0, 1, 2 , 3具體解釋參考官方文檔 }) //給右側綁定的BScroll綁定監聽事件,獲取滑動過程中的位置 this.foodswrapper.on(‘scroll‘,({x,y})=>{ console.log(x,y)//默認沒有分發滾動事件 this.scrollY=Math.abs(y); }) //獲取停下來的位置 //給右側綁定的BScrollEnd綁定監聽事件,獲取滑動結束時的位置 this.foodswrapper.on(‘scrollEnd‘,({x,y})=>{ //console.log(x,y)//默認沒有分發滾動事件 this.scrollY=Math.abs(y); }) }
第五步:實現_initTops()
先分析:
代碼:
//初始化數組,獲取到每個li 的坐標 ,_initTops(){ var tops=[] //定義一個空數組 let top=0; tops[0]=0 //第一個li的坐標為0 var lis = this.$refs.foodsUl.children; //獲取到了每個li Array.prototype.slice.call(lis).forEach((li,index)=>{ top = top + li.clientHeight//當前的位置,等於上一個的位置,加上這一個的高度 tops.push(top) }) this.tops=tops console.log(tops) },
第六步:計算currentIndex
computed:{ currentIndex(){ //如果滑動的位置在當前這個和下一個之間,返回的是這個的下標 /*比如: tops=[0, 5, 12,18,23] 如果scrollY=4 ----返回0 scrollY=8-----返回1 */ return this.tops.findIndex((top,index)=>{ return this.scrollY>=top && this.scrollY<this.tops[index+1] }) } }
有了前面幾步,就可以很容易的實現我們想要的功能
(1)滑動右側,左側高亮,只需在左側加current類的時候,判斷計算的currentIndex是否等於當前的index
<ul> <!--current--> <li class="menu-item " v-for="(good,index) in goods" :key="index" :class="{current:index===currentIndex}" @click="clickMenuItem(index)"> <span class="text bottom-border-1px"> <img class="icon" :src="good.icon" v-if="good.icon" > {{good.name}} </span> </li> </ul>
(2)點擊左側,右側滑動到相應的位置
註冊點擊事件:
<!--current--> <li class="menu-item " v-for="(good,index) in goods" :key="index" :class="{current:index===currentIndex}" @click="clickMenuItem(index)"> <span class="text bottom-border-1px"> <img class="icon" :src="good.icon" v-if="good.icon" > {{good.name}} </span> </li>
methods中定義這個點擊事件‘’
//將當前的index傳進來 clickMenuItem(index){ //先得到目標位置scrollY const top = this.tops[index]; // 立即更新scrollY,更新當前分類,點擊的分類項成為當前 this.scrollY=top //平滑滾動右側列表 this.foodswrapper.scrollTo(0, -top, 3); }
4、完整代碼
<template> <div> <div class="goods"> <div class="menu-wrapper" > <ul> <!--current--> <li class="menu-item " v-for="(good,index) in goods" :key="index" :class="{current:index===currentIndex}" @click="clickMenuItem(index)"> <span class="text bottom-border-1px"> <img class="icon" :src="good.icon" v-if="good.icon" > {{good.name}} </span> </li> </ul> </div> <div class="foods-wrapper"> <ul ref="foodsUl"> <li class="food-list-hook" v-for="(good, index) in goods" :key="index" > <h1 class="title">{{good.name}}</h1> <ul> <li class="food-item bottom-border-1px" v-for="(food, index) in good.foods" :key="index"> <div class="icon"> <img width="57" height="57" :src="food.icon"> </div> <div class="content"> <h2 class="name">{{food.name}}</h2> <p class="desc">{{food.description}}</p> <div class="extra"> <span class="count">月售{{food.sellCount}}份</span> <span>好評率{{food.rating}}%</span> </div> <div class="price"> <span class="now">¥{{food.price}}</span> <span class="old" v-if="food.oldPrice">¥{{food.oldPrice}}</span> </div> <div class="cartcontrol-wrapper"> CartControl </div> </div> </li> </ul> </li> </ul> </div> </div> food </div> </template> <script> import {mapState} from ‘vuex‘ import BScroll from ‘better-scroll‘ export default { data(){ return{ scrollY:0, tops:[] //存放每一個類的初始位置 } }, //這裏的數據是異步顯示的,所以我們要等數據異步請求之後再創建這個滑動列表 mounted(){ //異步請求可以傳過去兩個參數, this.$store.dispatch(‘getShopGoods‘,()=>{ //數據請求完之後再執行這裏了 //初始化滾動 this.$nextTick(()=>{ //初始化,並且實時獲取滾動坐標 this._initScrollY() //初始化右邊的數組 this._initTops(); }) }) }, methods:{ //初始化BScroll _initScrollY(){ new BScroll(‘.menu-wrapper‘,{ click:true }) //創建右邊的 this.foodswrapper = new BScroll(‘.foods-wrapper‘,{ click:true, probeType:3 }) //給右側綁定的BScroll綁定監聽事件,但是你會發現並沒有調用 this.foodswrapper.on(‘scroll‘,({x,y})=>{ console.log(x,y)//默認沒有分發滾動事件 this.scrollY=Math.abs(y); }) //獲取停下來的位置 //給右側綁定的BScroll綁定監聽事件,但是你會發現並沒有調用 this.foodswrapper.on(‘scrollEnd‘,({x,y})=>{ //console.log(x,y)//默認沒有分發滾動事件 this.scrollY=Math.abs(y); }) } //初始化數組,獲取到每個li 的坐標 ,_initTops(){ var tops=[] //定義一個空數組 let top=0; tops[0]=0 //第一個li的坐標為0 var lis = this.$refs.foodsUl.children; //獲取到了每個li Array.prototype.slice.call(lis).forEach((li,index)=>{ top = top + li.clientHeight//當前的位置,等於上一個的位置,加上這一個的高度 tops.push(top) }) this.tops=tops console.log(tops) }, //將當前的index傳進來 clickMenuItem(index){ //先得到目標位置scrollY const top = this.tops[index]; // 立即更新scrollY,更新當前分類,點擊的分類項成為當前 this.scrollY=top //平滑滾動右側列表 this.foodswrapper.scrollTo(0, -top, 3); } }, computed:{ ...mapState([‘goods‘]), currentIndex(){ return this.tops.findIndex((top,index)=>{ return this.scrollY>=top && this.scrollY<this.tops[index+1] }) } } } </script> <style lang="stylus" rel="stylesheet/stylus"> @import "../../../common/stylus/mixins.styl" .goods display: flex position: absolute top: 195px bottom: 46px width: 100% background: #fff; overflow: hidden .menu-wrapper flex: 0 0 80px width: 80px background: #f3f5f7 .menu-item display: table height: 54px width: 56px padding: 0 12px line-height: 14px &.current position: relative z-index: 10 margin-top: -1px background: #fff color: $green font-weight: 700 .text border-none() .icon display: inline-block vertical-align: top width: 12px height: 12px margin-right: 2px background-size: 12px 12px background-repeat: no-repeat .text display: table-cell width: 56px vertical-align: middle bottom-border-1px(rgba(7, 17, 27, 0.1)) font-size: 12px .foods-wrapper flex: 1 .title padding-left: 14px height: 26px line-height: 26px border-left: 2px solid #d9dde1 font-size: 12px color: rgb(147, 153, 159) background: #f3f5f7 .food-item display: flex margin: 18px padding-bottom: 18px bottom-border-1px(rgba(7, 17, 27, 0.1)) &:last-child border-none() margin-bottom: 0 .icon flex: 0 0 57px margin-right: 10px .content flex: 1 .name margin: 2px 0 8px 0 height: 14px line-height: 14px font-size: 14px color: rgb(7, 17, 27) .desc, .extra line-height: 10px font-size: 10px color: rgb(147, 153, 159) .desc line-height: 12px margin-bottom: 8px .extra .count margin-right: 12px .price font-weight: 700 line-height: 24px .now margin-right: 8px font-size: 14px color: rgb(240, 20, 20) .old text-decoration: line-through font-size: 10px color: rgb(147, 153, 159) .cartcontrol-wrapper position: absolute right: 0 bottom: 12px </style>完整代碼滑動
三、總結
Vue(用better-scroll實現滑動效果)