需要达到的效果:右侧内容左右滚动时,左侧边栏不动,上下滑动时整体内容上下滚动
安装并引入
import BScroll from 'better-scroll'
因为滚动默认是纵向的,所以不需要多设置其他参数
首先在 HTML 部分设置滚动外层容器(centent)和滚动内容(content-box),设置外层 div 的高度比如 100vh,content-box 高度由内容撑开。打开控制台查看是否 content-box 高度大于 content 高度,如果是,基本就没问题。
<div ref="wrapper" class="content">
<div class="content-box">
<ul>
...
ul>
div>
div>
let scroll = new BScroll(this.$refs.wrapper)
2.横向滚动
在纵向滚动的基础上添加横向滚动,需要注意的是样式的设定。为了让右边内容左右滚动的时候左边侧栏能够固定,所以我的办法是左边侧栏和右边滚动内容分开来写。
左边侧栏宽度设为 90px,右边内容宽度动态获取。right-detail 里的 ul 宽度要比 right-detail 的宽度值大。要使右边 ul 里的内容横向排列(比如 li)可以使用 white-space: nowrap; 同时还要注意其他样式的设定。具体样式看文章末尾贴的代码。
<div ref="wrapper" :style="{ width: originWidth + 'px' }" class="content">
<div>
<p class="title">
界面标题
p>
<div class="box-content">
<div class="left-name">
<ul>
<li>
<span>固定的左边标题span>
li>
<li v-for="(item, index) in 数据" :key="index">
<span>{{ 动态左边侧栏}}span>
li>
ul>
div>
<div class="right-detail" ref="listWrapper" :style="{ width: originWidth - 90 + 'px' }">
<ul>
<li>
...固定的右边标题或者动态获取的
li>
<li v-for="(item, index) in 数据" :key="index">
...动态的右边内容区域
li>
ul>
div>
div>
div>
div>
data() {
return {
originWidth: '',
}
},
mounted() {
this.$nextTick(() => {
this.listScroll()
})
},
methods: {
listScroll() {
let originWidth = document.getElementsByClassName('page')[0].clientWidth
this.originWidth = originWidth
let scroll = new BScroll(this.$refs.wrapper)
let horizontalScroll = new BScroll(this.$refs.listWrapper, {
scrollX: true,
eventPassthrough: 'vertical',
})
},
}
需要注意这里 eventPassthrough 的值是’vertical’,而不是 ‘horizontal’。freeScroll、scrollX、eventPassthrough(horizontal)都是支持横向滚动,但是彼此之间会互斥。
以上就实现了纵向横向的滚动效果。
3.添加效果:横向滚动左边侧栏右侧显示阴影,纵向滚动列表表头吸顶
因为左边侧栏和右边内容区域是分开写的,上下滚动需要吸顶,左右滚动侧栏不动,加上 scroll 组件包裹的容器使用的样式是 transform 导致 fixed 失效。所以我的做法是在滚动层最外面另外做一个吸顶 ”狸猫换太子“。监听滚动距离,显示隐藏吸顶和样式。
<div v-if="fixedShow" :class="topFixShadow" class="top-fix">
<div class="left-name">
<ul :class="boxShadow">
<li class="fix-name">
<span>固定的左边标题span>
li>
ul>
div>
<div :style="{ 'margin-left': left + 'px' }" class="right-detail top-right-detail">
<ul>
<li>
...固定的右边标题或者动态获取的
li>
ul>
div>
div>
<div ref="wrapper" :style="{ width: originWidth + 'px' }" class="content">
<div>
<p class="title">
界面标题
p>
<div class="box-content">
<div class="left-name">
<ul :class="boxShadow">
<li :class="showTitle">
<span>固定的左边标题span>
li>
<li v-for="(item, index) in 数据" :key="index">
<span>{{ 动态左边侧栏 }}span>
li>
ul>
div>
<div ref="listWrapper" :style="{ width: originWidth - 90 + 'px' }" class="right-detail">
<ul>
<li :class="showTitle">
...固定的右边标题或者动态获取的
li>
<li v-for="(item, index) in 数据" :key="index">
...动态的右边内容区域
li>
ul>
div>
div>
div>
div>
data() {
return {
originWidth: '',
boxShadow: '',
fixName: '',
left: '',
fixedShow: false,
topFixShadow: '',
showTitle: '',
}
},
mounted() {
this.$nextTick(() => {
this.listScroll()
})
},
methods: {
listScroll() {
let originWidth = document.getElementsByClassName('page')[0].clientWidth
this.originWidth = originWidth
let scroll = new BScroll(this.$refs.wrapper, {
click: true,
probeType: 3,
})
scroll.on('scroll', ({ x, y }) => {
if (y < -34) { // 纵向滚动到一定距离时,吸顶显示,原设吸顶display:none。
this.fixedShow = true
this.showTitle = 'show-title'
this.topFixShadow = 'top-fix-shadow'
} else {
this.fixedShow = false
this.showTitle = ''
this.topFixShadow = ''
}
})
let horizontalScroll = new BScroll(this.$refs.listWrapper, {
scrollX: true,
click: true,
probeType: 3,
eventPassthrough: 'vertical',
})
horizontalScroll.on('scroll', ({ x, y }) => {
if (x < 0) { // 当横向滚动时,设置左边侧栏阴影,并使外部的吸顶随着滚动距离移动。
this.boxShadow = 'box-shadow'
this.left = x
} else {
this.boxShadow = ''
}
})
},
}
需要注意的是 probeType 为 1 的时候,会非实时(屏幕滑动超过一定时间后)派发 scroll 事件;当 probeType 为 2 的时候,会在屏幕滑动的过程中实时的派发 scroll 事件;当 probeType 为 3 的时候,不仅在屏幕滑动的过程中,而且在 momentum 滚动动画运行过程中实时派发 scroll 事件。如果没有设置该值,其默认值为 0,即不派发 scroll 事件。
全部样式:
.page {
height: 100%;
display: flex;
flex-direction: column;
.content {
flex: 1;
overflow: hidden;
position: relative;
.title {
padding: 9px 12px;
}
}
}
.top-fix {
display: flex;
position: relative;
z-index: 9999;
}
.top-right-detail {
flex: 1;
}
.top-fix-shadow {
box-shadow: 3px 3px 3px #ddd;
}
.show-title {
display: none;
}
.box-content {
flex: 1;
border-top: 0.5px solid #ddd;
border-bottom: 1px solid #ddd;
overflow: scroll;
z-index: 999;
zoom: 1;
}
.left-name {
width: 90px;
float: left;
position: relative;
z-index: 9999;
li {
text-align: center;
&:not(:last-child) {
border-bottom: 1px solid #ddd;
}
}
li:nth-child(even) {
background-color: #f4f4f4;
}
span {
line-height: 33px;
font-size: 14px;
color: #777777;
}
}
.scroll-content {
width: 100%;
}
.right-detail {
float: left;
height: auto;
width: auto;
overflow: hidden;
ul {
white-space: nowrap;
float: left;
li {
span {
width: 70px;
display: inline-block;
text-align: center;
line-height: 33px;
font-size: 14px;
color: #777777;
}
&:not(:last-child) {
border-bottom: 1px solid #ddd;
}
}
li:nth-child(even) {
background-color: #f4f4f4;
}
}
}
.box-content:after {
content: '';
display: block;
visibility: hidden;
clear: both;
height: 0;
}
.fix-name {
width: 90px;
height: 33px;
background-color: #f9f9f9;
}
.box-shadow {
box-shadow: 2px 0px 2px #ddd;
}
关注公众号bug人生回复资料即可获得前端视频资料