npm install @better-scroll/core --save
// or
yarn add @better-scroll/core
index
import React, { useRef, useEffect, useState } from 'react'
import styles from './style.less'
import { BS, debounce } from './utils/index'
const index = () =>
{
const [rollingArea, setRollingArea] = useState(0) // 滚动位置
const [bsContainer, setBsContainer] = useState(null) // 保存 BS
const [scrollName, setScrollTitle] = useState("正在加载中")
const scrollRef = useRef()
useEffect(() =>
{ // 发送数据请求 设置订阅/启动定时器 手动更改 DOM 等 ~ // scrolled 记录滚动 pullUp 记录上拉
BS('wrapper', setBsContainer, { payload: { params: null, callback: { scrolled, pullUp } } }) // 传递三个参数 DOM节点、用于保存 BS 对象、 payload:传递一个 params 暂时没作用 callback 用于 接收传递过来的值
window.addEventListener('resize', debounce(function ()
{
console.log('屏幕调整大小');
}, 1000))
// BS(scrollRef.current) // 发送 Ref 也可以发送 DOM 节点 BS('wrapper')
return () =>
{ // 组件卸载之前 做一些收尾工作 比如清楚定时器/取消订阅 等 ~
}
}, []) // 检测数组内变量 如果为空 则监控全局
// 滚动事件
const scrolled = debounce((roll, bs) =>
{ // roll 滚动位置 bs BScroll 对象
const { x, y } = roll // x y 轴的距离
// bs && bs.refresh() // 按钮因为没有写到 content 也就不会影响到滚动的高度 所以也就不需要加 refresh
setRollingArea(y) // 保存 Y 轴位置
}, 100) // 展示的慢 因为加了防抖函数
const pullUp = (title) =>
{
setScrollTitle(title)
}
const btnClick = debounce(() =>
{
bsContainer.scrollTo(200, -1000, 2000) // X轴 Y轴 时间
}, 1000)
const btnBack = () =>
{
bsContainer.scrollTo(750, 0, 2000) // X轴 Y轴 时间
}
console.log(scrollName, 'scrollName');
return (
<div className={styles.container}>
{rollingArea <= -1000 ? (<button onClick={btnBack} className={styles.btn} >点击返回顶部</button>) : null}
<div id='wrapper' ref={scrollRef} className={styles.wrapper}>
<div className={styles.content}>
<div className={styles.dd}>{scrollName}</div>
<button onClick={btnClick}>按钮点击</button>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
<div>12</div>
<div>13</div>
<div>14</div>
<div>15</div>
<div>16</div>
<div>17</div>
<div>18</div>
<div>19</div>
<div>20</div>
<div>21</div>
<div>22</div>
<div>23</div>
<div>24</div>
<div>25</div>
<div>26</div>
<div>27</div>
<div>28</div>
<div>29</div>
<div>30</div>
<div>31</div>
<div>32</div>
<div>33</div>
<div>34</div>
<div>35</div>
<div>36</div>
<div>37</div>
<div>38</div>
<div>39</div>
<div>40</div>
<div>41</div>
<div>42</div>
<div>43</div>
<div>44</div>
<div>45</div>
<div>46</div>
<div>47</div>
<div>48</div>
<div>49</div>
<div>50</div>
<div>51</div>
<div>52</div>
<div>53</div>
<div>54</div>
<div>55</div>
<div>56</div>
<div>57</div>
<div>58</div>
<div>59</div>
<div>60</div>
<div>61</div>
<div>62</div>
<div>63</div>
<div>64</div>
<div>65</div>
<div>66</div>
<div>67</div>
<div>68</div>
<div>69</div>
<div>70</div>
<div>71</div>
<div>72</div>
<div>73</div>
<div>74</div>
<div>75</div>
<div>76</div>
<div>77</div>
<div>78</div>
<div>79</div>
<div>80</div>
<div>81</div>
<div>82</div>
<div>83</div>
<div>84</div>
<div>85</div>
<div>86</div>
<div>87</div>
<div>88</div>
<div>89</div>
<div>90</div>
<div>91</div>
<div>92</div>
<div>93</div>
<div>94</div>
<div>95</div>
<div>96</div>
<div>97</div>
<div>98</div>
<div>99</div>
<div>100</div>
</div>
</div>
</div >
)
}
export default index
utils
import BScroll from '@better-scroll/core' // BScroll 核心
import MouseWheel from '@better-scroll/mouse-wheel' // 引入滚轮
import PullDown from '@better-scroll/pull-down' // 上拉
// import Scrollbar from '@better-scroll/scroll-bar'
// BScroll.use(Scrollbar)
BScroll.use(MouseWheel) // 下载滚轮插件
BScroll.use(PullDown) // 下载上拉
export const BS = (wrapper, setBsContainer = false, action = false,) =>
{
const { payload } = action
if (wrapper)
{
if (typeof wrapper === 'string')
{
let wrapperRef = document.querySelector('#' + wrapper)
deploy(wrapperRef ? wrapperRef : null, setBsContainer ? setBsContainer : null, payload ? payload.callback : null)
} else
{
deploy(wrapper ? wrapper : null, setBsContainer ? setBsContainer : null, payload ? payload.callback : null)
}
}
}
const deploy = (wrapper, setBsContainer, callback) =>
{
console.log(setBsContainer, 'setBsContainer');
console.log(callback, 'callback');
let bs = new BScroll(wrapper, {
probeType: 3, // 默认0 不侦测 0和1 都不侦测 2:在手指滚动的过程中侦测 手指离开后的惯性滚动过程中不侦测 3:只要是滚动 都进行侦测
click: true, // 可以点击 用法:要覆盖本机滚动,BetterScroll必须禁止某些默认浏览器行为,例如鼠标单击。如果您希望您的应用程序响应click事件,则必须将该选项显式设置为true。然后BetterScroll将向其_constructed调度事件添加一个私有属性,该属性的值为true。
pullDownRefresh: true, // 向上拉 可以上拉 请求数据 加载更多
mouseWheel: true, // 鼠标滚轮
})
// 监听事件 滚动 https://better-scroll.github.io/docs/en-US/
if (setBsContainer) setBsContainer(bs) // 用于保存 bs 对象
bs.on('scroll', position =>
{
if (callback)
{
const { scrolled } = callback
scrolled(position, bs) // 发送两个参数 position 位置 bs 对象
}
// 默认情况下 BScroll 是不可以实时监听滚动位置
// console.log(position); // 实时滚动的位置
})
bs.on('pullingDown', () =>
{
// 触发时机:在一次上拉加载的动作后 这个时机一般用来去后端请求数据
// bs.finishPullUp()
// 注意 只能回调一次
console.log('上拉加载更多');
// 先去发送网络请求 请求更多页的数据
// 等数据强求完成 并将数据展示出来
setTimeout(() =>
{
bs.finishPullDown()
if (callback)
{
const { pullUp } = callback
pullUp('猪猪你看到了吗')
}
// bs.refresh()
// bs.finishPullUp() // 可以再次执行
}, 2000) // 两秒拉一次
})
// btn.addEventListener('click', function ()
// {
// console.log('---');
// })
}
// export const DS = (data, HorizontalAxis) =>
// {
// console.log(HorizontalAxis);
// let wrapper = document.querySelector('#' + data)
// if (wrapper)
// {
// new BScroll(wrapper, {
// probeType: 0,
// click: true,
// pullUpLoad: true,
// mouseWheel: true,
// scrollX: true,
// scrollY: false,
// scrollbar: {
// customElements: [HorizontalAxis.current],
// fade: true,
// interactive: true,
// // scrollbarTrackClickable: true
// }
// })
// }
// }
// 防抖函数
export const debounce = (func, delay) =>
{
let timer = null;
return function (...args)
{
if (timer) clearTimeout(timer);
timer = setTimeout(() =>
{
func.apply(this, args);
}, delay);
};
}
css
.container {
position: relative;
width: 100%;
height: 100%;
.wrapper {
position: relative;
margin: 0 auto;
width: 800px;
height: 400px;
background-color: pink;
overflow: hidden;
}
}
.dd {
position: absolute;
width: 100%;
padding: 20px;
box-sizing: border-box;
transform: translateY(-100%) translateZ(0);
text-align: center;
color: #999;
}
.btn {
position: fixed;
top: 100px;
right: 100px;
}