# 核心滚动
在 BetterScroll 2.0 的设计当中,我们抽象了核心滚动部分,它作为 BetterScroll 的最小使用单元,压缩体积比 1.0
小了将近三分之一,往往你可能只需要完成一个纯粹的滚动需求,那么你只需要引入这一个库,方式如下:
npm install @better-scroll/core --save
import BScroll from '@better-scroll/core'
const bs = new BScroll('.div')
# 上手
BetterScroll 有多种滚动模式。
垂直滚动
<template> <div class="core-container"> <div class="scroll-wrapper" ref="scroll"> <div class="scroll-content"> <div class="scroll-item" v-for="(item, index) in emojis" :key="index" @click="clickHandler(item)">{{item}}</div> </div> </div> </div> </template>
<script type="text/ecmascript-6"> import BScroll from '@better-scroll/core' export default { data () { return { emojis: [ '😀 😁 😂 🤣 😃', '😄 😅 😆 😉 😊', '😫 😴 😌 😛 😜', '👆🏻 😒 😓 😔 👇🏻', '😑 😶 🙄 😏 😣', '😞 😟 😤 😢 😭', '🤑 😲 🙄 🙁 😖', '👍 👎 👊 ✊ 🤛', '🙄 ✋ 🤚 🖐 🖖', '👍🏼 👎🏼 👊🏼 ✊🏼 🤛🏼', '☝🏽 ✋🏽 🤚🏽 🖐🏽 🖖🏽', '🌖 🌗 🌘 🌑 🌒', '💫 💥 💢 💦 💧', '🐠 🐟 🐬 🐳 🐋', '😬 😐 😕 😯 😶', '😇 😏 😑 😓 😵', '🐥 🐣 🐔 🐛 🐤', '💪 ✨ 🔔 ✊ ✋', '👇 👊 👍 👈 👆', '💛 👐 👎 👌 💘', '👍🏼 👎🏼 👊🏼 ✊🏼 🤛🏼', '☝🏽 ✋🏽 🤚🏽 🖐🏽 🖖🏽', '🌖 🌗 🌘 🌑 🌒', '💫 💥 💢 💦 💧', '🐠 🐟 🐬 🐳 🐋', '😬 😐 😕 😯 😶', '😇 😏 😑 😓 😵', '🐥 🐣 🐔 🐛 🐤', '💪 ✨ 🔔 ✊ ✋', '👇 👊 👍 👈 👆', '💛 👐 👎 👌 💘' ] } }, mounted() { this.init() }, beforeDestroy() { this.bs.destroy() }, methods: { init() { this.bs = new BScroll(this.$refs.scroll, { probeType: 3, click: true }) this.bs.on('scrollStart', () => { console.log('scrollStart-') }) this.bs.on('scroll', ({ y }) => { console.log('scrolling-') }) this.bs.on('scrollEnd', (pos) => { console.log(pos) }) }, clickHandler (item) { window.alert(item) } } } </script>
<style lang="stylus" rel="stylesheet/stylus" scoped> .core-container .scroll-wrapper height 400px position relative overflow hidden .scroll-item height 50px line-height 50px font-size 24px font-weight bold border-bottom 1px solid #eee text-align center &:nth-child(2n) background-color #f3f5f7 &:nth-child(2n+1) background-color #42b983 </style>
WARNING
BetterScroll 实时派发 scroll 事件,是需要设置
probeType
为 3。水平滚动
<template> <div class="horizontal-container"> <div class="scroll-wrapper" ref="scroll"> <div class="scroll-content"> <div class="scroll-item" v-for="(item, index) in emojis" :key="index">{{item}}</div> </div> </div> </div> </template>
<script type="text/ecmascript-6"> import BScroll from '@better-scroll/core' export default { data () { return { emojis: [ '👉🏼 😁 😂 🤣 👈🏼', '😄 😅 😆 😉 😊', '😫 😴 😌 😛 😜', '👆🏻 😒 😓 😔 👇🏻', '😑 😶 🙄 😏 😣', '😞 😟 😤 😢 😭', '🤑 😲 ☹️ 🙁 😖', '👍 👎 👊 ✊ 🤛', '☝️ ✋ 🤚 🖐 🖖', '👍🏼 👎🏼 👊🏼 ✊🏼 🤛🏼', '☝🏽 ✋🏽 🤚🏽 🖐🏽 🖖🏽', '🌖 🌗 🌘 🌑 🌒' ] } }, mounted() { this.init() }, beforeDestroy() { this.bs.destroy() }, methods: { init() { this.bs = new BScroll(this.$refs.scroll, { scrollX: true, probeType: 3 // listening scroll event }) this.bs.on('scrollStart', () => { console.log('scrollStart-') }) this.bs.on('scroll', ({ y }) => { console.log('scrolling-') }) this.bs.on('scrollEnd', () => { console.log('scrollingEnd') }) } } } </script>
<style lang="stylus" rel="stylesheet/stylus" scoped> .horizontal-container .scroll-wrapper position relative width 90% margin 80px auto white-space nowrap border 3px solid #42b983 border-radius 5px overflow hidden .scroll-content display inline-block .scroll-item height 50px line-height 50px font-size 24px display inline-block text-align center padding 0 10px </style>
WARNING
BetterScroll 实现横向滚动,对 CSS 是比较苛刻的。首先你要保证 wrapper 不换行,并且 content 的 display 是 inline-block。
.scroll-wrapper // ... white-space nowrap .scroll-content // ... display inline-block
freeScroll(水平与垂直同时滚动)
<template> <div class="free-scroll-container"> <div class="free-scroll-wrapper"> <div class="scroll-wrapper" ref="wrapper"> <div class="scroll-content"> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> </div> </div> </div> </div> </template>
<script> import BScroll from '@better-scroll/core' export default { mounted () { this.init() }, methods: { init () { this.bs = new BScroll(this.$refs.wrapper, { freeScroll: true, bounce: { bottom: false, left: false, right: false, top: false } }) } } } </script>
<style lang="stylus" scoped> .free-scroll-container position: relative width: 100% height: 100% .free-scroll-wrapper position: relative width: 100% height: 100% border: 1px solid rgb(96, 108, 113) box-sizing: border-box .scroll-wrapper position: absolute top: 0 left: 0 right: 0 bottom: 0 overflow: hidden .scroll-content background-color: #efeff4 width: 1500px height: 1000px p font-size: 16px padding: 20px line-height: 200% margin: 0 </style>
# 动态 content 2.0.4
对于 2.0.4
版本,已经具备了探测 content 元素变成其他元素的能力,可以查看下面的例子。
<template>
<div class="core-dynamic-content-container">
<div class="scroll-wrapper" ref="scroll">
<div class="scroll-content c1" key="1" v-if="!switcher">
<div class="scroll-item" v-for="n in nums1" :key="n">{{n}}</div>
</div>
<div class="scroll-content c2" key="2" v-else>
<div class="scroll-item" v-for="n in nums2" :key="n">{{nums2 - n + 1}}</div>
</div>
</div>
<button class="btn" @click="handleClick">switch content element</button>
</div>
</template>
<script type="text/ecmascript-6">
import BScroll from '@better-scroll/core'
export default {
data () {
return {
nums1: 30,
nums2: 60,
switcher: false
}
},
mounted() {
this.init()
},
beforeDestroy() {
this.bs.destroy()
},
methods: {
handleClick() {
this.switcher = !this.switcher
// wait for Vue rerender
this.$nextTick(() => {
this.bs.refresh()
})
},
init() {
this.bs = new BScroll(this.$refs.scroll, {
probeType: 3
})
this.bs.on('contentChanged', (content) => {
console.log('--- newContent ---')
console.log(content)
})
this.bs.on('scroll', () => {
console.log('scrolling-')
})
this.bs.on('scrollEnd', () => {
console.log('scrollingEnd')
})
}
}
}
</script>
<style lang="stylus" scoped>
.core-dynamic-content-container
text-align center
.scroll-wrapper
height 300px
overflow hidden
.scroll-item
height 50px
line-height 50px
font-size 24px
font-weight bold
border-bottom 1px solid #eee
text-align center
&:nth-child(2n)
background-color #f3f5f7
&:nth-child(2n+1)
background-color #42b983
.btn
margin 40px auto
padding 10px
color #fff
border-radius 4px
font-size 20px
background-color #666
</style>
# specifiedIndexAsContent 2.0.4
对于 2.0.4
版本,可以指定 wrapper 的某一个 children 作为 content,在之前的版本,BetterScroll只会处理 wrapper 的第一个子元素。详细的文档在这。
<template>
<div class="core-specified-content-container">
<div class="scroll-wrapper" ref="scroll">
<div class="ignore-content">
The Blue area is not taken as BetterScroll's content
</div>
<div class="scroll-content">
<div class="scroll-item" v-for="n in nums" :key="n">{{n}}</div>
</div>
</div>
</div>
</template>
<script type="text/ecmascript-6">
import BScroll from '@better-scroll/core'
export default {
data () {
return {
nums: 30
}
},
mounted() {
this.init()
},
beforeDestroy() {
this.bs.destroy()
},
methods: {
init() {
window.bs = this.bs = new BScroll(this.$refs.scroll, {
specifiedIndexAsContent: 1,
probeType: 3
})
this.bs.on('scroll', () => {
console.log('scrolling-')
})
this.bs.on('scrollEnd', () => {
console.log('scrollingEnd')
})
}
}
}
</script>
<style lang="stylus" scoped>
.core-specified-content-container
text-align center
.scroll-wrapper
height 400px
overflow hidden
border 1px solid #42b983
.ignore-content
padding 20px
color white
font-size 20px
font-weight bold
background-color #2c3e50
.scroll-item
height 50px
line-height 50px
font-size 24px
font-weight bold
border-bottom 1px solid #eee
text-align center
&:nth-child(2n)
background-color #f3f5f7
&:nth-child(2n+1)
background-color #42b983
</style>
# quadrant 2.3.0
对于 2.3.0
版本,如果 BetterScroll 的 wrapper DOM 的父元素或者祖先元素发生旋转,可以通过 quadrant
选项来修正用户的交互行为。
- 竖向滚动强制变换成横向滚动
<template>
<div class="vertical-rotated-container">
<div class="description">Horizontal layout via CSS</div>
<div class="scroll-wrapper" ref="scroll">
<div class="scroll-content">
<div class="scroll-item" v-for="num in nums" :key="num">{{num}}</div>
</div>
</div>
</div>
</template>
<script type="text/ecmascript-6">
import BScroll from '@better-scroll/core'
export default {
data () {
return {
nums: 8
}
},
mounted() {
this.init()
},
beforeDestroy() {
this.bs.destroy()
},
methods: {
init() {
this.bs = new BScroll(this.$refs.scroll, {
// v2.3.0
quadrant: 2 // rotate90
})
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus" scoped>
/* horizontal by CSS */
.scroll-wrapper
transform rotate(90deg)
.vertical-rotated-container
.description
text-align center
.scroll-wrapper
height 250px
width 100px
position relative
overflow hidden
margin 0 auto
border 1px solid #ccc
.scroll-item
height 100px
width 100px
line-height 100px
font-size 24px
font-weight bold
text-align center
&:nth-child(2n)
background-color #f3f5f7
&:nth-child(2n+1)
background-color #42b983
</style>
- 横向滚动强制翻转
<template>
<div class="horizontal-rotated-container">
<div class="description">Flipping layout via CSS</div>
<div class="scroll-wrapper" ref="scroll">
<div class="scroll-content">
<div class="scroll-item" v-for="num in nums" :key="num">{{num}}</div>
</div>
</div>
</div>
</template>
<script type="text/ecmascript-6">
import BScroll from '@better-scroll/core'
export default {
data () {
return {
nums: 8
}
},
mounted() {
this.init()
},
beforeDestroy() {
this.bs.destroy()
},
methods: {
init() {
this.bs = new BScroll(this.$refs.scroll, {
scrollX: true,
scrollY: false,
// v2.3.0
quadrant: 3 // rotate180
})
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus" scoped>
/* flipping by CSS */
.scroll-wrapper
transform rotate(180deg)
.horizontal-rotated-container
.description
margin-bottom 40px
text-align center
.scroll-wrapper
height 100px
width 250px
position relative
overflow hidden
white-space nowrap
margin 0 auto
border 1px solid #ccc
.scroll-content
display inline-block
.scroll-item
height 100px
width 100px
line-height 100px
font-size 24px
font-weight bold
text-align center
display inline-block
&:nth-child(2n)
background-color #f3f5f7
&:nth-child(2n+1)
background-color #42b983
</style>
# 温馨提示
TIP
任何时候如果出现无法滚动的情况,都应该首先查看 content 元素高度/宽度是否大于 wrapper 的高度/宽度。这是内容能够滚动的前提条件。
如果内容存在图片的情况,可能会出现 DOM 元素渲染时图片还未下载,因此内容元素的高度小于预期,出现滚动不正常的情况。此时你应该在图片加载完成后,比如 onload 事件回调中,调用 bs.refresh
方法,它会重新计算最新的滚动距离。