vue中利⽤iscroll.js解决pc端滚动问题
项⽬中经常遇到区域超出部分会出现滚动条,滚动条在pc端可以通过⿏标滚轮控制上下,在移动端可以通过⿏标拖动页⾯进⾏滚动,这两种场景都是符合⽤户习惯,然⽽这种滚动条⼀般都是竖【vertical】项滚动条,如果pc端出现横向滚动条【horizontal】,在不做处理的情况下,你只能⽤⿏标拖动横向滚动条按钮【scrollerbar】展⽰滚动区域,⽽且为了美观,⼀般滚动条会进⾏样式编写或者隐藏,那么横向区域默认情况下就没法滚动。
⼆、描述
现为了解决pc端滚动区域能像移动端⼀样,能够通过⿏标拖动滚动区域直接进⾏滚动,如图所⽰
pc端滚动⽰例图
滚动实例⽤到知识点如下:
1. 采⽤vue-cli3+iscroll.js组合的⽅式;
2. 使⽤ vue ⾃定义指令实现 iscroll 实例化和参数配置;
3. 实现横向滚动区域和竖向滚动区域之间的联动;
4. 实现横向滚动条居中显⽰和使⽤scrollIntoView()⽅法的差别
三、⾃定义指令 v-iscroll
1、新建指令⽂件
这⾥使⽤ vue ⾃定义指令初始化 iscroll 实例,在 vue-cli3 项⽬⽬录下新建vIscroll.js,⽂件代码如下:
const IScroll = require('iscroll')
const VIScroll = {
install: function (Vue, options) {
Vue.directive('iscroll', {
inserted: function (el, binding, vnode) {
let callBack
let iscrollOptions = options
<!--vue组件中绑定的两个参数 option、instance-->
const option = binding.value && binding.value.option
const func = binding.value && binding.value.instance
// 判断输⼊参数
const optionType = option ? [].toString.call(option) : undefined
const funcType = func ? [].toString.call(func) : undefined
/
/ 兼容 google 浏览器拖动
el.addEventListener('touchmove', function (e) {
e.preventDefault()
})
// 将参数配置到new IScroll(el, iscrollOptions)中
if (optionType === '[object Object]') {
iscrollOptions = option
}
if (funcType === '[object Function]') {
callBack = func
}
/
/ 使⽤vnode绑定iscroll是为了让iscroll对象能够夸状态传递,避免iscroll重复建⽴
// 这⾥⾯跟官⽅⽹站 const myScroll = new IScroll('#wrapper',option) 初始化⼀样
vnode.scroll = new IScroll(el, iscrollOptions)
// 如果指令传递函数进来,把iscroll实例传递出去
if (callBack) callBack(vnode.scroll)
},
componentUpdated: function (el, binding, vnode, oldVnode) {
// 将scroll绑定到新的vnode上,避免多次绑定
vnode.scroll = oldVnode.scroll
// 使⽤ settimeout 让refresh跳到事件流结尾,保证refresh时数据已经更新完毕
setTimeout(() => {
fresh()
}, 0)
},
unbind: function (el, binding, vnode, oldVnode) {
// 解除绑定时要把iscroll销毁
vnode.scroll = oldVnode.scroll
vnode.scroll.destroy()
vnode.scroll = null
}
})
}
}
这⾥附上 iscroll.js 5 官⽅⽂档地址, iscroll npm 包地址,相关属性和⽅法⾃⾏查看。
2、加载引⽤指令
⾸先在 main.js 中加载指令:
import Vue from 'vue'
import App from './App.vue'
import "./assets/reset.css"
// 加载scroll指令
import VIscroll from './directive/vIscroll'
Vue.use(VIscroll)
new Vue({
render: h => h(App),
}).$mount('#app')
使⽤指令,摘⾃ tabList.vue 组件部分代码如下:
<template>
<div class="tab-container">
<div
class="scroll-container"
v-iscroll="{
option: iscrollConf,
instance: getIscroll
}"
ref="scrollContainer"
>
<ul
class="tab-li-container"
ref="tabLiContainer"
>
<li
class="tab-li-item"
v-for="(item, index) in list"
:
key="item.id"
:id="item.id"
ref="tabItem"
@click="tabEvent(item, index)"
>
<div
class="item"
:class="{
'item-active': currentId == item.id
}"
>{{item.num}}</div>
</li>
</ul>
</div>
<div
class="tab-left"
@click="tabBtnEvent('left')"
><</div>
<div
class="tab-right"
@click="tabBtnEvent('right')"
>></div>
</div>
</template>
<script>
export default {
props: ['list'],
data () {
return {
iscrollConf: {
bounce: true,
mouseWheel: true,
click: true,
scrollX: true,
scrollY: false
},
currentId: null,
currentIndex: 0,
myScroll: null
}
},
mounted () {
this.$refs.tabLiContainer.style.width = this.$refs.tabItem[0].offsetWidth * this.list.length + 'px'
this.$nextTick(() => {
})
},
methods: {
tabEvent (item, currentIndex) {
<!--点击某个li 按钮事件处理逻辑-->
},
tabBtnEvent (direction) {
<!--左右切换逻辑事件-->
},
getIscroll (iscroll) {
}
},
watch: {
list: {
handler (l) {
this.currentId = l[0].id
},
immediate: true,
deep: true
}
}
}
网站底部代码js特效</script>
<style scoped>
// 样式
</style>
上述代码中 v-iscroll 指令传⼊两个字段参数:
option:配置iscroll参数,这⾥⾯注意scrollX,scrollY两个属性,代表的是横向还是竖向滚动;instance:回调⽅法的调⽤, vIscroll.js 中执⾏回调⽅法,通过该组件⽅法 getIscroll() 获取到 iscroll 的实例。
3、上下滚动区域联动
上⾯的代码可以解决开篇场景中的问题,现在实现上下区域联动,通过点击横向滚动条某个按钮,使
其变成选中状态,然后竖向滚动条对应的项跳到⾸位,如图所以:
联动⽰例图
3-1、联动实现⽅法
点击按钮的⽅法:
tabEvent (item, currentIndex) {
this.currentId = item.id
this.currentIndex = currentIndex
<!--这⾥实现按钮始终居中显⽰,暂时省略,下⾯补充-->
...
<!--传给竖向滚动组件-->
this.$emit("switchTab", this.currentId, this.currentIndex)
},
竖向滚动区域组件【App.vue】代码部分如下,并对 switchTab() ⽅法进⾏详细注释:
<template>
<div id="app">
<TabList
:list="list"
@switchTab="switchTab"
></TabList>
<!-- v-iscroll="defalutOption" -->
<div
v-iscroll="{
option: defalutOption,
instance: getIscroll
}"
class="tab-content-container"
ref="detailItemContainer"
>
<ul class="tab-list-container">
<li
v-for="item in list"
:key="item.id"
class="list-item"
ref="detailItem"
>
<div>{{item.value}}</div>
</li>
</ul>
</div>
</div>
</template>
<script>
import TabList from './components/tabList.vue'
export default {
name: 'App',
components: {
TabList,
},
data () {
return {
list: [
{ id: 1, value: '这是第1题', num: 1 },
<!--...省略数据展⽰-->
{ id: 16, value: '这是第16题', num: 16 }
],
defalutOption: {
bounce: true,
mouseWheel: true,
click: true,
scrollX: false,
scrollY: true
},
myScroll: null
}
},
methods: {
switchTab (currentId, currentIndex) {
<!--对选中的当前项,这⾥就是“3”按钮对应的“这是第3题”,求出它距离⽗元素的上边距offsetTop值-->
const offsetTop = this.$refs.detailItem[currentIndex].offsetTop
<!--滚动的范围不能超过这个滚动体的底部,这⾥⾯⽤到iscroll的属性maxScrollY-->
const y = offsetTop >= Math.Scroll.maxScrollY) ? Scroll.maxScrollY : -offsetTop
<!--调⽤iscroll的⽅法进⾏滚动到相应的位置-->
},
<!--获取实例-->
getIscroll (iscroll) {
}
}
}
</script>
<style scoped>
<!--样式-->
.
..
</style>
这⾥⾯⽤到的都是 iscroll 插件⾃带的属性和⽅法进⾏滚动边界的判断和滚动,⽐⽤ JavaScript ⽅法⽅便的多,⽽且⽤了iscroll作为滚动容器,已经在vIscroll.js禁⽤了相关浏览器默认事件。
3-2、居中显⽰
这⾥ JavaScript 有个 scrollIntoView() ⽅法,官⽅⽂档链接,这个⽅法让当前的元素滚动到浏览器窗⼝的可视区域内。关键缺点是,如果横向滚动和竖向滚动都同时⽤到这个⽅法,只能保证⼀个滚动区域有效,另⼀个会不滚动。
使⽤ scrollIntoView() ⽅法配置如下:
this.$refs.tabItem[this.currentIndex].scrollIntoView({
behavior: "smooth",
inline: "center",
block: 'nearest'
})
这⾥在横向滚动区域添加了⼀对左右按钮,实现切换功能,如图所⽰:
切换按钮⽰例图
切换按钮事件⽅法就是通过改变上⼀个、下⼀个按钮下标,调⽤⽅法,实现切换功能,切换事件⽅法逻辑如下:
tabBtnEvent (direction) {
const max = this.$refs.tabItem.length
if (direction === 'left' && this.currentIndex > 0) {
this.currentIndex--
}
if (direction === 'right' && this.currentIndex < max - 1) {
this.currentIndex++
}
<!--调⽤单击按钮事件-->
this.tabEvent(this.$refs.tabItem[this.currentIndex], this.currentIndex)
},
下⾯对单击按钮事件添加居中逻辑,详细代码和解析图如下,可以对⽐查看:
居中计算图
tabEvent (item, currentIndex) {
this.currentId = item.id
this.currentIndex = currentIndex
// 获取滚动容器的长度的⼀半,即中间点
const scrollContainerHalfWidth = this.$refs.scrollContainer.offsetWidth / 2
// 获取单个item的⼀半长度
const tabItemHalfWidth = this.$refs.tabItem[currentIndex].offsetWidth / 2
// 求取插值,就是开始到中间开始位置的距离
const halfDistance = scrollContainerHalfWidth - tabItemHalfWidth
// 求取当前item的相对总长度的偏移量
const currentItemOffsetLeft = this.$refs.tabItem[currentIndex].offsetLeft
// scroll 移动到中间的值
const x = halfDistance - currentItemOffsetLeft
this.$emit("switchTab", this.currentId, this.currentIndex)
},
4、总结
1、整个实例⽤的都是iscroll插件相关属性实现的滚动,避免同时使⽤JavaScript⽅法造成的代码混乱;
2、利⽤⾃定义指令的⽅式有效的避免了传统实例化iscroll带来的代码冗余,使其⽅便简洁;
3、本实例滚动选项都是字符串,如果出现图⽚的情况,合理使⽤fresh() ⽅法,在正确的时期重新计算滚动区域,避免滚动边界受限;总结
以上所述是⼩编给⼤家介绍的vue中利⽤iscroll.js解决pc端滚动问题,希望对⼤家有所帮助!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论