better-scroll学习实践总结

546 阅读4分钟

前提回顾

本文是在学习了better-scroll的1.x版本和2.x本版本之后,通过具体的实践案例来演示better-scroll的使用方式

better-scroll 1.x 地址:better-scroll.github.io/docs-v1/#/z… better-scroll 2.x 地址:better-scroll.github.io/docs/zh-CN/ 2.x的修改 下载方式 npm i better-scroll

指定子元素

插件机制

起步

这里以better-scroll的1.15.2版本举例说明,需注意better-scroll 提供了一个类,实例化的第一个参数是一个原生的 DOM 对象。当然,如果传递的是一个字符串,better-scroll 内部会尝试调用 querySelector 去获取这个 DOM 对象

  • 最基本的起步代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        body {
            margin: 0;
        }
        #wrap {
            /* 使用 better-scroll 时 wrap 必须有一个固定高度 */
            width: 300px;
            height: 80vh;
            border: 1px solid #000;
            overflow: hidden;
        }
        #list {
            width: 200%;
            margin: 0;
            padding: 0;
            list-style: none;
        }
        #list li {
            font: 14px/30px "宋体";
            border-bottom: 1px solid #000;
        }
    </style>
</head>
<body>
    <!--  better-scroll 是作用在外层 wrap 容器上的 -->
 <div id="wrap">
     <!-- better-scroll 默认滑动的是 wrap 下的第0个子元素  -->
    <!-- 滚动的部分是 list 元素 -->
     <ul id="list"></ul>
 </div> 
 
<!-- 引入的是better-scroll的1.15.2版本 -->
<script src="js/bscroll.js"></script> 
<script>
// 给 list 添加内容
{
    let list = document.querySelector("#list");
    list.innerHTML = [...(".".repeat(100))].map((item,index)=>{
        return `<li>这是第${index}个li</li>`;
    }).join("");
}
// 添加 better-scroll
{
    let wrap = document.querySelector("#wrap");
    let bscroll = new BScroll(wrap);
}
</script>   
</body>
</html>
  • 案例效果演示

基础配置

配置项 作用
startX 横轴方向初始化位置
startY 纵轴方向初始化位置
scrollX 当设置为 true 的时候,可以开启横向滚动
scrollY 当设置为 true 的时候,可以开启纵向滚动
tap 因为 better-scroll 会阻止原生的 click 事件,我们可以设置 tap 为 true,它会在区域被点击的时候派发一个 tap 事件,你可以像监听原生事件那样去监听它。如 element.addEventListener('tap', doSomething, false);。如果 tap 设置为字符串, 那么这个字符串就作为自定义事件名称。如 tap: 'myCustomTapEvent'。
bounce 当滚动超过边缘的时候会有一小段回弹动画。设置为 true 则开启动画
momentum 当快速在屏幕上滑动一段距离的时候,会根据滑动的距离和时间计算出动量,并生成滚动动画。设置为 true 则开启动画。
preventDefaultException better-scroll 的实现会阻止原生的滚动,这样也同时阻止了一些原生组件的默认行为。这个时候我们不能对这些元素做 preventDefault,所以我们可以配置 preventDefaultException

注意这里以better-scroll的1.15.2版本举例说明

  • 配置了上表的基础配置后代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        body {
            margin: 0;
        }
        #wrap {
            /* 使用 better-scroll 时 wrap 必须有一个固定高度 */
            margin: auto;
            width: 300px;
            height: 80vh;
            border: 1px solid #000;
            overflow: hidden;
        }
        #list {
            width: 600%;
            margin: 0;
            padding: 0;
            list-style: none;
        }
        #list li {
            font: 14px/30px "宋体";
            border-bottom: 1px solid #000;
        }
    </style>
</head>
<body>
 <div id="wrap">
     <!-- better-scroll 默认滑动的是 wrap 下的第0个子元素  -->
    <ul id="list"></ul>
 </div> 
<script src="js/bscroll.js"></script> 
<script>
// 给 list 添加内容
{
    let list = document.querySelector("#list");
    list.innerHTML = [...(".".repeat(100))].map((item,index)=>{
        return `<li>这是第${index}个li</li>`;
    }).join("");
}
// 添加 better-scroll
{
    let wrap = document.querySelector("#wrap");
    let bscroll = new BScroll(wrap,{
        startX: -10,
        startY: -100,
        scrollX: false,
        scrollY: true,
        tap: true,
        bounce: false,
        momentum: false,
        preventDefaultException: {
            tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/
        }
    });
    let li = document.querySelector("#list li");
    li.addEventListener("tap",function(e){
        console.log(e);
    });
}
</script>   
</body>
</html>
  • 案例效果演示

常用方法

配置项 作用
refresh 重新计算 better-scroll,当 DOM 结构发生变化的时候务必要调用确保滚动的效果正常。
stop 立即停止当前运行的滚动动画
scrollBy(x, y, time, easing) 相对于当前位置偏移滚动 x,y 的距离。
scrollTo(x, y, time, easing) 滚动到指定的位置
scrollToElement(el, time, offsetX, offsetY, easing) 滚动到指定的目标元素

注意这里以better-scroll的1.15.2版本举例说明

  • 配置了上表的基础配置后代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        body {
            margin: 0;
        }
        #wrap {
            /* 使用 better-scroll 时 wrap 必须有一个固定高度 */
            margin: auto;
            width: 300px;
            height: 80vh;
            border: 1px solid #000;
            overflow: hidden;
        }
        #list {
            width: 600%;
            margin: 0;
            padding: 0;
            list-style: none;
        }
        #list li {
            font: 14px/30px "宋体";
            border-bottom: 1px solid #000;
        }
    </style>
</head>
<body>
 <div id="wrap">
     <!-- better-scroll 默认滑动的是 wrap 下的第0个子元素  -->
    <ul id="list"></ul>
 </div> 
<script src="js/bscroll.js"></script> 
<script>
{
    //案例一:


    //如果先初始化了BScroll然后再去添加内容的话
    //会出现滑动失效的问题原因是DOM结构发生了改变
    // let wrap = document.querySelector("#wrap");
    // let bscroll = new BScroll(wrap,{
    //     // startY: -100
    // });

    // let list = document.querySelector("#list");
    // list.innerHTML = [...(".".repeat(100))].map((item,index)=>{
    //     return `<li>这是第${index}个li</li>`;
    // }).join("");

    //bscroll.refresh(); //重新计算
    //当 DOM 结构发生变化的时候务必要调用确保滚动的效果正常
}



{   

    //案例二:
    let list = document.querySelector("#list");
    list.innerHTML = [...(".".repeat(100))].map((item,index)=>{
        return `<li>这是第${index}个li</li>`;
    }).join("");

    let wrap = document.querySelector("#wrap");
    let bscroll = new BScroll(wrap,{
        // startY: -100
    });
    
    //bscroll.refresh(); //重新计算


    setTimeout(()=>{
        //滚动到指定的位置
        //bscroll.scrollTo(0,-400,500);

        //相对于当前位置偏移滚动 x,y 的距离
        bscroll.scrollBy(0,-400,500);

        //滚动到指定的目标元素
        // bscroll.scrollToElement(list.children[30],5000,0,-10);
    },2000);


    // setTimeout(()=>{
    //     bscroll.stop();
    // },100)
}
</script>   
</body>
</html>
  • 案例效果演示

常用事件

配置项 作用
on(type,fn,context) 监听当前实例上的自定义事件。如:scroll, scrollEnd, pullingUp, pullingDown等。
scrollStart 滚动开始时
scroll 滚动过程中,具体时机取决于选项中的 probeType。
scrollCancel 滚动被取消。
scrollEnd 滚动结束。
touchEnd 鼠标/手指离开。
flick 轻拂时。
probeType 有时候我们需要知道滚动的位置。当 probeType 为 1 的时候,会非实时(屏幕滑动超过一定时间后)派发scroll 事件;当 probeType 为 2 的时候,会在屏幕滑动的过程中实时的派发 scroll 事件;当 probeType 为 3 的时候,不仅在屏幕滑动的过程中,而且在 momentum 滚动动画运行过程中实时派发 scroll 事件。如果没有设置该值,其默认值为 0,即不派发 scroll 事件。

注意这里以better-scroll的1.15.2版本举例说明

  • 配置了上表的基础配置后代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        body {
            margin: 0;
        }
        #wrap {
            /* 使用 better-scroll 时 wrap 必须有一个固定高度 */
            margin: auto;
            width: 300px;
            height: 80vh;
            border: 1px solid #000;
            overflow: hidden;
        }
        #list {
            width: 600%;
            margin: 0;
            padding: 0;
            list-style: none;
        }
        #list li {
            font: 14px/30px "宋体";
            border-bottom: 1px solid #000;
        }
    </style>
</head>
<body>
 <div id="wrap">
     <!-- better-scroll 默认滑动的是 wrap 下的第0个子元素  -->
    <ul id="list"></ul>
 </div> 
<script src="js/bscroll.js"></script> 
<script>
// 添加 better-scroll
{
    let list = document.querySelector("#list");
    list.innerHTML = [...(".".repeat(300))].map((item,index)=>{
        return `<li>这是第${index}个li</li>`;
    }).join("");

    let wrap = document.querySelector("#wrap");
    let bscroll = new BScroll(wrap,{
        //如果没有设置该值,其默认值为 0,即不派发 scroll 事件。
        probeType:3
    });

    //on(type,fn,context) 事件名 回调函数 函数执行的上下文环境
    // bscroll.on("beforeScrollStart",function(e){
    //     console.log(e,"开始滚动之前-鼠标按下");
    // });
    // bscroll.on("scrollStart",function(e){
            //只执行一次
    //     console.log(e,"开始滚动-鼠标开始滑动");
    // });
    // bscroll.on("scroll",function(e){
          //触发时机:滚动过程中,具体时机取决于选项中的 probeType。
    //     console.log(e,"滚动中");
    // });
    // bscroll.on("scrollCancel",function(e){
    //     console.log(e,"滚动取消-滚动没法执行的时候执行该事件");
    // });
    bscroll.on("scrollEnd",function(e){
        console.log(e,"滚动结束");
    });
    // bscroll.on("touchEnd",function(e){
    //     console.log(e,"抬起");
    // });
    // bscroll.on("flick",function(e){
    //     console.log(e,"轻抚");
    // });
}
</script>   
</body>
</html>
  • 案例效果演示

wheel的使用

配置项 作用
selectedIndex 选中的是第几个
rotate 转盘的旋转效果
adjustTime 动画时长
wheelWrapperClass 对应外框类名
wheelItemClass 对应外框中的子项类名
wheelDisabledItemClass 禁选
flick 轻拂时。
getSelectedIndex 当我们做 picker 组件的时候,调用该方法可以滚动到索引对应的位置
wheelTo 获取当前选中的索引值

注意这里以better-scroll的1.15.2版本举例说明

  • 配置了上表的基础配置后代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width,user-scalable=no" />
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
body {
	margin: 0;
}
ul {
	margin: 0;
	padding: 0;
	list-style: none;
}	
.wrap {
	width: 100vw;
	height: 200px;
	overflow: hidden;
}
.select {
	position: absolute;
	top: 80px;
	left: 0;
	box-sizing: border-box;
	width: 100vw;
	height: 40px;
	border: 1px solid #000;
}
.list {
	margin-top: 80px;
}
.list li {
	font: 20px/40px "宋体";
	text-align: center;
}
</style>
</head>
<body>
<div class="wrap">
	<ul class="list">
		<li class="list-item">1</li>
		<li class="list-item">2</li>
		<li class="list-item">3</li>
		<li class="list-item">4</li>
		<li class="list-item disabled-item">5</li>
		<li class="list-item">6</li>
		<li class="list-item">7</li>
		<li class="list-item">8</li>
	</ul>
	<div class="select"></div>
</div>
<script src="js/bscroll.js"></script>
<script>
{
	//获取外框
    let wrap = document.querySelector(".wrap");
    let wheel = new BScroll(wrap,{
        wheel: {
          selectedIndex: 0,
          //转盘的旋转效果
          rotate: 30,
          //动画时长
          adjustTime: 200,
          //对应外框类名
          wheelWrapperClass: 'wrap',
          //对应外框中的子项类名
          wheelItemClass: 'list-item',
          //禁选
          wheelDisabledItemClass: 'disabled-item'
        }
	}); 
	

    wheel.on("scrollEnd",()=>{
		console.log("完成选中");
		//获取当前选中的索引值
        console.log(wheel.getSelectedIndex());
    });
    setTimeout(()=>{
		//当我们做 picker 组件的时候,调用该方法可以滚动到索引对应的位置
        wheel.wheelTo(3);
    },3000);
}
</script>
</body>
</html>
  • 案例效果演示

snap的使用

配置项 作用
snap 这个配置是为了做 Slide 组件用的,默认为 false,如果开启则需要配置一个 Object
loop loop 为 true 是为了支持循环轮播,但只有一个元素的时候,loop 为 true 是无效的,也并不会 clone 节点
threshold threshold 表示可滚动到下一个的阈值
eventPassthrough 有时候我们使用 better-scroll 在某个方向模拟滚动的时候,希望在另一个方向保留原生的滚动(比如轮播图,我们希望横向模拟横向滚动,而纵向的滚动还是保留原生滚动,我们可以设置 eventPassthrough 为 vertical;相应的,如果我们希望保留横向的原生滚动,可以设置eventPassthrough为 horizontal)。
getSelectedIndex 获取当前选中的索引值。
getCurrentPage() 获取当前页面的信息
next 滚动到下一个页面
prev 滚动到上一个页面
goToPage 当我们做 slide 组件的时候,slide 通常会分成多个页面。调用此方法可以滚动到指定的页面。

注意这里以better-scroll的1.15.2版本举例说明

  • 配置了上表的基础配置后代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width,user-scalable=no" />
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
body {
	margin: 0;
}
ul {
	margin: 0;
	padding: 0;
	list-style: none;
}
.wrap {
	width: 100vw;
	overflow: hidden;
	position: relative;
	left: 0;
	bottom: 20px;
}

.list {
	width: 600vw;
	overflow: hidden;
	position: relative;
}
.list li {
	float:left;
	width: 100vw;
	height: 140px;
	box-sizing: border-box;
	font: 80px/138px "宋体";
	text-align:center;
	border: 1px solid #000;
	background: #f1f1f1;
}
.list2 li {
	width: 100vw;
	height: 140px;
	box-sizing: border-box;
	font: 80px/138px "宋体";
	text-align:center;
	border: 1px solid #000;
	background: #f1f1f1;
} 
.nav {
	position: absolute;
	left: 0;
	bottom: 20px;
	width: 100vw;
	height: 10px; 
	text-align: center;
}
.nav a {
	display: inline-block;
	width: 10px;
	height: 10px;
	background: #fff;

}
.nav a.active {
	background:#f60;
}
</style>
</head>
<body>
<div class="wrap">
	<ul class="list">
		<li>1</li>
		<li>2</li>
		<li>3</li>
		<li>4</li>
	</ul>
	<nav class="nav">
		<a class="active"></a>
		<a></a>
		<a></a>
		<a></a>
	</nav>
</div>
<ul class="list2">
	<li>1</li>
	<li>2</li>
	<li>3</li>
	<li>4</li>
	<li>1</li>
	<li>2</li>
	<li>3</li>
	<li>4</li>
</ul>
<script src="js/bscroll.js"></script>
<script>
{
	//获取外框
	let wrap = document.querySelector(".wrap");
	//获取滚动的小点
	let navs = document.querySelectorAll(".nav a");
	let timer = 0;
	//问题1:当滑动特别快的时候会出现一次滑动了好几张幻灯片的效果
	//问题1解决:找到缓冲momentum设置为false即一次只能滑动一张
	let snap = new BScroll(wrap,{
		scrollX: true,
		scrollY: false,
		momentum: false,

		//幻灯片的宽高不设置的话根据幻灯片外框的宽高来设置
		// stepX:100,
		// stepY:100,


		tap: true,
		snap: {
			loop: true,
			//阈值即拖拽的时候拽了多少距离的时候才滑到下一张
			threshold: 0.1
		},
		//eventPassthrough 的设置会导致其它一些选项配置无效,需要小心使用它。
		//在支持幻灯片的同时支持上下滚动
		eventPassthrough: 'vertical'
	});
	snap.on("scrollEnd",()=>{
		// console.log(snap.getCurrentPage(),'page');

		//先清除每一个小点的选中样式
		navs.forEach(item=>{
			item.classList.remove("active");
		});

		//获取当前页面的信息
		//console.log(snap.getCurrentPage());
		
		//
		navs[snap.getCurrentPage().pageX].classList.add("active");
	});
	// document.addEventListener("click",function(){
		//滚动到下一个页面
		// 	//snap.next(1000);

		//滚动到上一个页面
	// 	snap.prev();
	// });

	//自动播放的制作
	snap.on("beforeScrollStart",()=>{
		clearInterval(timer);
	});
	snap.on("touchEnd",()=>{
		timer = setInterval(()=>{
			snap.next();
		},3000);
	});
	timer = setInterval(()=>{
		snap.next();
	},3000);


	//点击按钮跳转至指定页
	navs.forEach((item,index)=>{
          item.addEventListener("tap",()=>{
              //console.log(index);
              //调用此方法可以滚动到指定的页面。
              snap.goToPage(index,0);
              navs.forEach(item=>{
                  item.classList.remove("active");
              });
              navs[index].classList.add("active");
          });
	});
}
</script>
</body>
</html>
  • 案例效果演示

上拉加载下滑刷新

配置项 作用
scrollbar 这个配置可以开启滚动条,默认为 false。当设置为 true 或者是一个 Object 的时候,都会开启滚动条,例如:
mouseWheel 作用:这个配置用于 PC 端的鼠标滚轮,默认为 false,。当设置为 true 或者是一个 Object 的时候,可以开启鼠标滚轮
pullDownRefresh 这个配置用于做下拉刷新功能,默认为 false。当设置为 true 或者是一个 Object 的时候,可以开启下拉刷新
pullUpLoad 这个配置用于做上拉加载功能,默认为 false。当设置为 true 或者是一个 Object 的时候,可以开启上拉加载
pullingDown 在一次下拉刷新的动作后,这个时机一般用来去后端请求数据。
finishPullDown 当下拉刷新数据加载完毕后,需要调用此方法告诉 better-scroll 数据已加载。
finishPullUp 当上拉加载数据加载完毕后,需要调用此方法告诉 better-scroll 数据已加载。
closePullUp 动态关闭上拉加载功能。

注意这里以better-scroll的1.15.2版本举例说明

  • 配置了上表的基础配置后代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width,user-scalable=no" />
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
/* 滚动设置和滚动条设置 */
body {
	margin: 0;
}
ul {
	margin: 0;
	padding: 0;
	list-style: none;
}
.wrap {
	width: 100vw;
	height: 100vh;
	/*
		100 vw == 1可视区宽度
		100 vh == 1可视区高度
	*/
	overflow: hidden;
}
.list {
	position: relative;
	width: 200vw;
}
.list li {
	font: 16px/40px "宋体";
	border-bottom: 1px solid #000;
}


.pullUp:after {
	content:"正在加载更多内容";
}
.pullUpEnd:after {
	content:"没有更多数据了";
}

/* 触发下拉刷新时显示  正在刷新*/
.pullDown:before {
	content:"正在刷新";
	position: absolute;
	top: -50px;
}
.pullDownEnd:before {
	content:"刷新完毕";
	position: absolute;
	top: -50px;
}
</style>
</head>
<body>
<div class="wrap">
	<ul class="list">
	</ul>
</div>
<script src="js/bscroll.js"></script>
<script>
{
    let data = [...(".".repeat(200))].map((item,index)=>`这是第${index}条数据`);
    let wrap = document.querySelector(".wrap");
    let list = document.querySelector(".list");
    
    //记录当前第几次请求第几页数据,一次请求一批数据
    let page = 0;

    //记录每一页多少条数据
    let len = 20;
    /*
        0: 0 - 19
        1: 20 - 39
    */
    let render = ()=>{
        let start = page*len;
        let end = (page+1)*len;
        let nowData = data.filter((item,index)=>index>=start&&index<end);
        return nowData.map(item=>`<li>${item}</li>`).join("");
    };
    //添加内容
    list.innerHTML += render();


    let bscroll = new BScroll(wrap,{

        //这个配置可以开启滚动条
        scrollbar: {
            fade: true,
            interactive: false  //别操作滚动条了
        },

        //这个配置用于 PC 端的鼠标滚轮
        mouseWheel: {
            speed: 20,
            invert: false, //滚轮方向
            easeTime: 400 //缓动时长
        },

        //这个配置用于做下拉刷新功能
        pullDownRefresh: {
            threshold: 50, //可以配置顶部下拉的距离
            stop: 50 //回弹停留的距离
        },

        //这个配置用于做上拉加载功能
        pullUpLoad: {
            threshold: -50 //距离底部还有多少距离的时候触发
        }
    });

    //滚动开始之前
    bscroll.on("beforeScrollStart",()=>{
        list.classList.remove("pullDownEnd");
        /*
            .pullDownEnd:before {
                content:"刷新完毕";
                position: absolute;
                top: -50px;
            }
        */
    });

    //pullingDown在一次下拉刷新的动作后,这个时机一般用来去后端请求数据。
    bscroll.on("pullingDown",()=>{
        // console.log("触发下拉刷新");
        list.classList.add("pullDown");
        /*
            触发下拉刷新时显示  正在刷新
            .pullDown:before {
                content:"正在刷新";
                position: absolute;
                top: -50px;
            }
        */
        setTimeout(()=>{
            list.classList.remove("pullDown");
            list.classList.add("pullDownEnd");
            /*
            .pullDownEnd:before {
                content:"刷新完毕";
                position: absolute;
                top: -50px;
            }
            */
            list.innerHTML = `<li>这是刷新的新数据${Date.now()}</li>` +  list.innerHTML;
            //当下拉刷新数据加载完毕后,需要执行 finishPullDown 方法
            //当下拉刷新数据加载完毕后,需要调用此方法告诉 better-scroll 数据已加载。
            bscroll.finishPullDown()
        },1000);
    });

    //在一次上拉加载的动作后,这个时机一般用来去后端请求数据。
    bscroll.on("pullingUp",()=>{
        //console.log("上滑加载");
        list.classList.add("pullUp");
        /*
            .pullUp:after {
                content:"正在加载更多内容";
            }
        */
        page++;
        setTimeout(()=>{
            list.innerHTML += render();
            list.classList.remove("pullUp");
            /*
                .pullUp:after {
                    content:"正在加载更多内容";
                }
            */
           //当上拉加载数据加载完毕后,需要调用此方法告诉 better-scroll 数据已加载
            bscroll.finishPullUp();
            console.log((page+1)*len, data.length);

            //是否已经请求完成 没有数据可以再请求了
            if((page+1)*len >= data.length){

                //动态关闭上拉加载功能
                bscroll.closePullUp();


                list.classList.add("pullUpEnd");
                /*
                    .pullUpEnd:after {
                        content:"没有更多数据了";
                    }
                */
            }
        },1000);
    });


    /*
        动态关闭和开启下拉刷新功能
    */
    // setTimeout(()=>{    
          //动态关闭下拉刷新功能
    //     bscroll.closePullDown()
    // },2000);
    // setTimeout(()=>{    
            //动态开启下拉刷新功能
    //     bscroll.openPullDown({
    //         threshold: 50,
    //         stop: 50
    //     })
    // },6000);

    
}
</script>
</body>
</html>
  • 案例效果演示

zoom

配置项 作用
zoom 这个配置用于对滚动内容的缩放
start 开始的缩放比例

注意这里以better-scroll的1.15.2版本举例说明

  • 配置了上表的基础配置后代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #box {
            width: 300px;
            height: 300px;
            border: 2px solid #000;
            display: flex;
        }
        #div {
            margin: auto;
            width: 100px;
            height: 100px;
            background: red;
        }
    </style>
</head>
<body>
<div id="box">
    <div id="div"></div>
</div>  
<script src="js/bscroll.js"></script>
<script>
{
    let box = document.querySelector("#box");
    let div = document.querySelector("#div");
    let boxZoom = new BScroll(box,{
        //这个配置用于对滚动内容的缩放
        //双指缩放
        zoom: { 
            start: 1, //开始的缩放比例
            min: .5, //最小缩放比例
            max: 2 //最大缩放比例
        }
    });
    boxZoom.on("zoomStart",()=>{
        div.style.background = "yellow";
    });
    boxZoom.on("zoomEnd",()=>{
        div.style.background = "red";
    });
}
</script>  
</body>
</html>

无限滚动

注意这里以better-scroll的1.15.2版本举例说明

  • 案例效果演示
  • 代码如下
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #wrap {
            position: relative;
            width: 300px;
            height: 300px;
            background: #eee;
            /* 不要在这里加边框 */
            overflow: hidden;
        }
        .tombstone {
            width: 100px;
            height: 100px;
            border: 2px solid #000;
            /* 墓碑机制 占位置先 */
            background: rgb(50, 26, 82);
        }
        .inner {
            width: 100px;
            height: 100px;
            border: 2px solid #000;
            background: red;
        }
    </style>
</head>
<body>
<div id="wrap">
    <div id="div"></div>
</div>      
<script src="js/bscroll.js"></script>
<script>
{
    let wrap = document.querySelector("#wrap");
    let nub = 0;
    let infinityScroll = new BScroll(wrap,{
        //该配置的使用场景是长列表滚动或者是无限滚动
        infinity:{
            fetch(count) {
                console.log(count);
                // 获取大于 count 数量的数据,该函数是异步的,它需要返回一个 Promise。
                // 成功获取数据后,你需要 resolve 数据数组(也可以 resolve 一个 Promise)。
                // 数组的每一个元素是列表数据,在 render 方法执行的时候会传递这个数据渲染。
                // 如果没有数据的时候,你可以 resolve(false),来告诉无限滚动列表已经没有更多数据了。
                nub++;
                return new Promise((resolve)=>{
                    setTimeout(()=>{
                        if(nub > 10){
                            resolve(false);
                        } else {
                            let data = [...(".".repeat(count))];
                            resolve(data);
                        }   
                        
                    },Math.random()*1000+1000);
                })
            },
            //请求到数据之后调用render方法
            render(item) {

                // 渲染每一个元素节点,item 是数据
                // 该函数需要返回渲染后的 DOM 节点。
                let div = document.createElement("div");
                div.className = "inner";
                
                //要返回真正的内容
                return div;
            },
            createTombstone() {
                // 返回一个墓碑 DOM 节点。
                // 在数据还没有请求到之前会有 墓碑 来占位置
                let div = document.createElement("div");
                div.className = "tombstone"
                return div;
            }
        }
    });     
}
</script>  
</body>
</html>

索引列表

注意这里以better-scroll的1.15.2版本举例说明

  • 案例效果演示
  • 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width,user-scalable=no" />
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
/* 索引列表 */
ul {
	margin: 0;
	padding: 0;
	list-style: none;
}
.list-wrapper{
	position: absolute;
	left: 0;
	top: 0;
	right: 0;
	bottom: 0;
	overflow: hidden;
	background: #fff;
} 
.index-list-content{
	background: #fff;
	border-radius: 2px;
}

.index-list-title{
	padding: 14px 16px;
	font-size: 14px;
	line-height: 1.6;
	color: #333;	
}

.index-list-anchor{
	padding: 16px 16px 10px 16px;
	line-height: 1;
	font-size: 14px;
	color: #999;
	background: #f7f7f7;	
}

.index-list-item {
	position: relative;
	height: 50px;
	line-height: 50px;
	padding: 0 16px;
	font-size: 14px;
	color: #333;
}
.index-list-item:last-child{
	border: none;
}
.index-list-item_active{
	background: #ddd;	
}
.index-list-fixed{
	position: absolute;
	z-index: 1;
	top: 0;
	left: 0;
	width: 100%;
	padding: 16px 16px 10px 16px;
	box-sizing: border-box;
	font-size: 14px;
	line-height: 1;
	color: #999;
	background: #f7f7f7;	
}

.index-list-nav {
	position: absolute;
	z-index: 30;
	right: 0;
	top: 50%;
	transform: translateY(-50%);
	font-family: Helvetica;	
}
.index-list-nav ul {
	padding: 0;
	margin: 0;
}       
.index-list-nav li{
	padding: 6px 16px 0 16px;
	line-height: 1;
	text-align: center;
	box-sizing: border-box;
	font-size: 12px;
	color: gray;
}          
.index-list-nav .active {
	color: blue;
}
                
</style>
</head>
<body>
<div class="list-wrapper">
    <div class="scroll-content">
        <div class="index-list-content">
            <div class="index-list-title">
                定位城市: 背景
            </div>
            <ul>
                <li>
                    <h2 class="index-list-anchor">
                        ★热门城市
                    </h2>
                    <ul>
                        <li class="index-list-item border-bottom-1px">
                            北京市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            上海市
                        </li>
                    </ul>
                </li>
                <li>
                    <h2 class="index-list-anchor">
                        A
                    </h2>
                    <ul>
                        <li class="index-list-item border-bottom-1px">
                            鞍山市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            安庆市
                        </li>
                    </ul>
                </li>
                <li>
                    <h2 class="index-list-anchor">
                        B
                    </h2>
                    <ul>
                        <li class="index-list-item border-bottom-1px">
              
                            北京市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            巴音郭楞州
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            博尔塔拉州
                        </li>
                    </ul>
                </li>
                <li>
                    <h2 class="index-list-anchor">
                        C
                    </h2>
                    <ul>
                        <li class="index-list-item border-bottom-1px">
                            成都市
                        </li>
                    </ul>
                </li>
                <li>
                    <h2 class="index-list-anchor">
                        E
                    </h2>
                    <ul>
                        <li class="index-list-item border-bottom-1px">
                            鄂尔多斯市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            鄂州市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            恩施州
                        </li>
                    </ul>
                </li>
                <li>
                    <h2 class="index-list-anchor">
                        F
                    </h2>
                    <ul>
                        <li class="index-list-item border-bottom-1px">
                            福州市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            佛山市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            防城港市
                        </li>
                    </ul>
                </li>
                <li>
                    <h2 class="index-list-anchor">
                        G
                    </h2>
                    <ul>
                        <li class="index-list-item border-bottom-1px">
                            广州市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            贵阳市
                        </li>
                    </ul>
                </li>
                <li>
                    <h2 class="index-list-anchor">
                        H
                    </h2>
                    <ul>
                        <li class="index-list-item border-bottom-1px">
                            杭州市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            和田地区
                        </li>
                    </ul>
                </li>
                <li>
                    <h2 class="index-list-anchor">
                        Z
                    </h2>
                    <ul>
                        <li class="index-list-item border-bottom-1px">
                            郑州市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            张家口市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            张家界市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            珠海市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            中山市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            自贡市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            资阳市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            枣庄市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            舟山
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            遵义市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            淄博市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            株洲市
                        </li>
                        <li class="index-list-item border-bottom-1px">
                            中卫市
                        </li>
                    </ul>
                </li>
            </ul>
        </div>
    </div>
</div>
<!-- 最右侧的字母排序表 -->
<div class="index-list-nav">
    <ul>
        <li data-index="0" class="active"></li>
        <li data-index="1">
            A
        </li>
        <li data-index="2" class="">
            B
        </li>
        <li data-index="3" class="">
            C
        </li>
        <li data-index="4" class="">
            E
        </li>
        <li data-index="5" class="">
            F
        </li>
        <li data-index="6" class="">
            G
        </li>
        <li data-index="7" class="">
            H
        </li>
        <li data-index="8" class="">
            Z
        </li>
    </ul>
</div>
<!-- 这里的内容是随着 
        哪一块最后的标题超过了顶部就
        显示哪一块标题内容
-->
<div class="index-list-fixed" style="display: none;">
    A
</div>
<script src="js/bscroll.js"></script>
<script>
{

    //获取外框
    let listWrapper = document.querySelector(".list-wrapper");
    
    //获取所有标题框  即热门城市、A、B、C等等
    //循环遍历所有标题框 查看标题框与顶部的距离
    let listAnchor = document.querySelectorAll(".index-list-anchor");
    
    //最右侧的字母排序表
    let listNav = document.querySelector(`.index-list-nav`);
    
    
    let activeListNav = document.querySelectorAll(`.index-list-nav li`);
    
    //固定的浮动条
    let indexListFixed = document.querySelector(".index-list-fixed");
    
    
    let bscroll = new BScroll(listWrapper,{
        //当 probeType 为 3 的时候,不仅在屏幕滑动的过程中,
        //而且在 momentum 滚动动画运行过程中实时派发 scroll 事件
        probeType: 3
    });
    bscroll.on("scroll",()=>{
        //默认一项都不选中
        var activeIndex = -1;

        //当标题的顶部超过可视区的顶部的时候 需要将该标题吸顶
        //如果有好几个标题的顶部都超过可视区的顶部的时候取最后一个超出的标题
        listAnchor.forEach((item,index)=>{
            let t = item.getBoundingClientRect().top;
            //如果超出可视区顶部(计算外框/顶部的距离)的话
            //跑到可视区上面了
            if(t <= 0){
                //循环正好是从第0个到最后一个
                //所以activeIndex的值取的永远是最后一个标题超出的index值
                activeIndex = index;
            }
        });

        
        activeListNav.forEach(item=>{
            item.classList.remove("active");
        });
        //根据索引值来选择到元素  当前项 
        //排除-1的情况 默认的情况
        activeListNav[activeIndex<0?0:activeIndex].classList.add("active");
        
        
        if(activeIndex >= 0){
            indexListFixed.style.display = "block";
            indexListFixed.innerHTML = listAnchor[activeIndex].innerHTML;
        } else {
            indexListFixed.style.display = "none";
        }
    });

    //最右侧的字母排序表的点击事件
    let getActive = (e)=>{
        let clientY = e.changedTouches[0].clientY;
        var activeIndex = -1;
        for(let i = 0; i < activeListNav.length; i++){
            let rect = activeListNav[i].getBoundingClientRect();
            //获取top和bottom值
            let t = rect.top;
            let b = rect.bottom;

            //鼠标触摸的位置需要在 最右侧字母顺序表 范围内
            if(clientY <= b
            && clientY >= t){
                activeIndex = i;
                break;
            }
        }

        //知道了滑动到了哪一项之后 就可以让其滚动到指定的元素上
        if(activeIndex >= 0){
            // console.log(activeListNav[activeIndex]);
            bscroll.scrollToElement(listAnchor[activeIndex], 500,0,1)
        }
    }

    //最右侧的字母排序表
    listNav.addEventListener("touchmove",getActive);
    listNav.addEventListener("touchstart",getActive);
    // listNav.addEventListener("touchstart",function(e){
    //     let clientY = e.changedTouches[0].clientY;
    //     clientY -=listNav.getBoundingClientRect().top
    //     获取的是相对于listNav的坐标
    // });
}    
</script>
</body>
</html>

better-scroll2.x的学习使用

  • 下载方式
    • npm i better-scroll
    • yarn add better-scroll
  • 指定子元素
  • 插件机制

起步

注意从这里开始都是以better-scroll2.x的版本来演示案例

  • 案例演示如下:
  • 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="node_modules/@better-scroll/core/dist/core.js"></script>
  <script src="node_modules/@better-scroll/scroll-bar/dist/scroll-bar.js"></script>
  <style>
      #box {
        position: relative;
        width: 50vw;
        height: 50vh;
        border: 1px solid #000;
        overflow: hidden;
      }
      #title {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        margin: 0;
        font: 16px/30px "宋体";
        background: rgba(0, 0, 0, .5);
        text-align: center;
        color: #fff;
      }
      #page {
        padding-top: 30px;
      }
  </style>
</head>
<body>
<div id="box">
  <h1 id="title">这是列表标题</h1>  
  <div id="page">
    <ul class="list"></ul>
  </div>
</div>
<script>
BScroll.use(ScrollBar);
{
  let list = document.querySelector(".list");
  list.innerHTML = [...(".".repeat(100))].map((item,index)=>{
    return `<li>这是第${index}个li</li>`
  }).join("");
}  
{
  let box = document.querySelector("#box");
  let pageScroll = new BScroll(box,{
    scrollY: true,
    scrollbar: true,
    // 当超过边界的时候,进行阻尼行为,阻尼因子越小,阻力越大
    outOfBoundaryDampingFactor:1/3,
    //指定wrapper对应的索引的子元素作为content,默认
    //情况下采用的是wrapper的第一个子元素作为content
    specifiedIndexAsContent: 1,
    // 派发处理 才能支持scroll事件
    probeType: 3
  });


  pageScroll.on("scroll",(position)=>{
    // 滚动的时候拿到事件
    console.log(position);
  });

  // hooks钩子的用法
  /*
    钩子是2.0版本衍生出来的概念,它的本质与事件相同
    都是eventEmitter实例,即典型的订阅发布模式
  */  
  pageScroll.hooks.on("beforeInitialScrollTo",()=>{
    console.log("init");
  })
  pageScroll.init(box);


  // pending 判断当前bs是否处于滚动动画过程中
  box.addEventListener("touchend",()=>{
    setTimeout(() => {
      console.log(pageScroll.pending);
    }, 200);
    setTimeout(() => {
      console.log(pageScroll.pending);
    }, 2000); 
  })
}  
</script>
</body>
</html>

hooks的基础使用

注意从这里开始都是以better-scroll2.x的版本来演示案例

  • 案例演示如下:
  • 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="node_modules/@better-scroll/core/dist/core.js"></script>
  <script src="node_modules/@better-scroll/scroll-bar/dist/scroll-bar.js"></script>
  <style>
      #box {
        position: relative;
        width: 50vw;
        height: 50vh;
        border: 1px solid #000;
        overflow: hidden;
      }
      #title {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        margin: 0;
        font: 16px/30px "宋体";
        background: rgba(0, 0, 0, .5);
        text-align: center;
        color: #fff;
      }
      #page {
        padding-top: 30px;
      }
  </style>
</head>
<body>
<div id="box">
  <h1 id="title">这是列表标题</h1>  
  <div id="page">
    <ul class="list"></ul>
  </div>
</div>
<script>
BScroll.use(ScrollBar);
{
  let list = document.querySelector(".list");
  list.innerHTML = [...(".".repeat(100))].map((item,index)=>{
    return `<li>这是第${index}个li</li>`
  }).join("");
}  
{
  let box = document.querySelector("#box");
  let pageScroll = new BScroll(box,{
    scrollY: true,
    scrollbar: true,
    outOfBoundaryDampingFactor:1/3,
    specifiedIndexAsContent: 1
  });

  /*
    钩子是2.0版本衍生出来的概念,它的本质与事件相同
    都是eventEmitter实例,即典型的订阅发布模式


    钩子就是一个一个事件对象
    每一个事件对象中包括了不同的事件
    针对不同的事件的不同处理可以实现更多的功能需求
  */  
  let hooks = pageScroll.scroller
  console.log(pageScroll);
}  
</script>
</body>
</html>

插件的使用

注意从这里开始都是以better-scroll2.x的版本来演示案例

  • 案例演示如下:
  • 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="node_modules/@better-scroll/core/dist/core.js"></script>
  <script src="node_modules/@better-scroll/scroll-bar/dist/scroll-bar.js"></script>
  <script src="node_modules/@better-scroll/mouse-wheel/dist/mouse-wheel.js"></script>
  <script src="node_modules/@better-scroll//observe-dom/dist/observe-dom.js"></script>
  <style>
      #box {
        position: relative;
        width: 50vw;
        height: 50vh;
        border: 1px solid #000;
        overflow: hidden;
      }
      #title {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        margin: 0;
        font: 16px/30px "宋体";
        background: rgba(0, 0, 0, .5);
        text-align: center;
        color: #fff;
      }
      #page {
        padding-top: 30px;
      }
  </style>
</head>
<body>
<div id="box">
  <h1 id="title">这是列表标题</h1>  
  <div id="page">
    <ul class="list"></ul>
  </div>
</div>
<script>
/*
2.x采用了插件化的架构设计,
对于1.x的各个feature,在
2.x都将以plugin的形式实现
*/
BScroll.use(ScrollBar)
BScroll.use(MouseWheel);
//使用全局引入的话名字就叫做ObserveDom
BScroll.use(ObserveDOM);
{
  let list = document.querySelector(".list");
  list.innerHTML = [...(".".repeat(100))].map((item,index)=>{
    return `<li>这是第${index}个li</li>`
  }).join("");
}  
{
  let box = document.querySelector("#box");
  let pageScroll = new BScroll(box,{
    scrollY: true,
    scrollbar: true,
    outOfBoundaryDampingFactor:1/3,
    specifiedIndexAsContent: 1,
    mouseWheel: {
      speed: 20, //滚轮滚动的速度
      invert: false, //表示滚轮滚动和bs滚动的方向
      easeTime: 300 //滚动动画的缓动时长
    },
    observeDOM:true
  });
  /*
    开启对content以及content子元素DOM改变的探测
    当插件被使用后,这些dom元素被使用时
    将会触发scroll的refresh方法
    observe-dom插件具有以下几个特性

    针对改变频繁的css属性 增加debounce
    如果改变发生在scroll动画过程中,则不会触发refresh
  */
  let list = document.querySelector(".list");
  let index = 0;
  setInterval(() => {
    index++;
    list.innerHTML +=  `<li>这是新增加第${index}个li</li>`;
    
    //bs在dom改变后不会主动刷新获得最新页面

    //解决方法一:手动调用更新
    //pageScroll.refresh();

    //解决方法二:开启observeDOM:true
  }, 1000);
  pageScroll.on("mousewheelStart",()=>{
      console.log("开始滚动",'滚轮滚动开始');
  })
  pageScroll.on("mousewheelMove",()=>{
      console.log("滚动");
  })
  pageScroll.on("mousewheelEnd",()=>{
      console.log("滚动结束");
  })
}  
</script>
</body>
</html>

轮播图

注意从这里开始都是以better-scroll2.x的版本来演示案例

  • 案例演示如下:
  • 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="./css/solid.css" rel="stylesheet" />
  <script src="./node_modules/@better-scroll/core/dist/core.js"></script>
  <script src="./node_modules//@better-scroll/slide/dist/slide.js"></script>
</head>
<body>
  <div class="slide-banner">
    <div class="banner-wrapper">
      <div class="slide-banner-wrapper">
        <div class="slide-banner-content">
          <div class="slide-page page1">page 1</div>
          <div class="slide-page page2">page 2</div>
          <div class="slide-page page3">page 3</div>
          <div class="slide-page page4">page 4</div>
        </div>
      </div>
      <div class="dots-wrapper">
        <span class="dot active"></span>
        <span class="dot"></span>
        <span class="dot"></span>
        <span class="dot"></span>
      </div>
    </div>
    <div class="btn-wrap">
      <button class="next">nextPage</button>
      <button class="prev">prePage</button>
    </div>
  </div>
<script>
BScroll.use(Slide);  
let warper = document.querySelector(".slide-banner-wrapper");
let content = document.querySelector(".slide-banner-content");
let prevBtn = document.querySelector(".prev");
let nextBtn = document.querySelector(".next");
let navs = document.querySelectorAll(".dots-wrapper span")
function setContentWidth() {
  let w = warper.clientWidth;
  content.style.width = content.children.length *  w + "px";
  for(let i = 0; i < content.children.length; i++ ){
    content.children[i].style.width = w + 'px';
  }
}
window.onresize = setContentWidth;
setContentWidth();
let picTab = new BScroll(warper,{
  scrollX: true,
  scrollY: false,
  momentum: false, //当快速在屏幕滑动一段距离后,会根据滑动的距离和时间计算出动量
  slide:{
    loop:true, //无限循环
    autoplay: false, //自动播放
    listenFlick: true, //当快速轻抚过slide区域时,会触发切换上一页/下一页
    threshold: .4  //切换下一个或上一个page的阈值
  }
});
prevBtn.onclick = function(params) {
  //上一张
  picTab.prev();
}
nextBtn.onclick = function(params) {
  //下一张
  picTab.next();
}
navs.forEach((nav,index)=>{
    //切换到第几张图片
    nav.onclick = function(params) {
        picTab.goToPage(index,1);
    }
});
picTab.on("scrollEnd",()=>{
  console.log(picTab.getCurrentPage(),"end");
});
picTab.on("slideWillChange",()=>{
  console.log(picTab.getCurrentPage(),"slideWillChange");
});
picTab.on("slidePageChanged",()=>{
  console.log(picTab.getCurrentPage(),"slidePageChanged");
});
</script>
</body>
</html>

wheel的使用

注意从这里开始都是以better-scroll2.x的版本来演示案例

  • 案例演示如下:
  • 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="./css/solid.css" rel="stylesheet" />
  <script src="./node_modules/@better-scroll/core/dist/core.js"></script>
  <script src="./node_modules//@better-scroll/wheel/dist/wheel.js"></script>
  <style>
    body {
      background: #cccccc;
    }
    .wraper {
      position: fixed;
      left: 0;
      bottom: 50%;
      height: 200px;
      width: 100%;
      background: #fff;
      overflow: hidden;
      perspective: 50px;
    }
    #wraper {
      position: absolute;
      left: 0;
      top: 78px;
      width: 100%;
      height: 40px;
      border: 2px solid #000;
    }
    #options {
      margin: 0;
      padding: 0;
      list-style: none;
    }
    #options li {
      font: 20px/40px "宋体";
      text-align: center;
    }
    #btn {
      position: relative;
      z-index: 10;
    }
  </style>
</head>
<body>
<div class="wraper">
  <button id="btn">按钮</button>
  <button id="stop">stop</button>
  <div id="wraper"><ul id="options"></ul></div>
</div>  
<script>
const data = [
    {
      text: 'Venomancer',
      value: 1
    }, {
      text: 'Nerubian Weaver',
      value: 2
    },
    {
      text: 'Spectre',
      value: 3
    },
    {
      text: 'Juggernaut',
      value: 4
    },
    {
      text: 'Karl',
      value: 5
    },
    {
      text: 'Zeus',
      value: 6
    },
    {
      text: 'Witch Doctor',
      value: 7
    }, {
      text: 'Lich',
      value: 8
    },
    {
      text: 'Oracle',
      value: 9
    },
    {
      text: 'Earthshaker',
      value: 10
    }
  ];  
{
  const options = document.querySelector("#options");
  options.innerHTML = data.map(item=>`<li>${item.text}</li>`).join("");
}  
</script>  
<script>
BScroll.use(Wheel);  
const wrap = document.querySelector("#wraper");
const btn = document.querySelector("#btn");
const stopBtn = document.querySelector("#stop");
const wheel = new BScroll(wrap,{
  wheel: {
    wheelWrapperClass: 'wheel-scroll',
    wheelItemClass: 'wheel-item',
    rotate: 30,
    adjustTime: 400,
    selectedIndex: 1,
    wheelDisabledItemClass: 'wheel-disabled-item'
  }
})
btn.onclick = function() {
  console.log(wheel.getSelectedIndex());
}
stopBtn.onclick= function() {
  //wheel.stop();

  // 强制让滚动的bs停止下来 并且恢复至滚动开始的位置
  wheel.restorePosition();
}
wheel.on("wheelIndexChanged",()=>{
  console.log(wheel.getSelectedIndex());
})
</script>
</body>
</html>

嵌套滚动

注意从这里开始都是以better-scroll2.x的版本来演示案例

  • 案例演示如下:
  • 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
      ul {
        margin: 0;
        padding: 0;
        list-style: none;
      }
      .wrap {
        width: 300px;
        border: 2px solid #000;
        height: 500px;
        overflow: hidden;
      }
      .wrap li {
        font: 14px/30px "宋体";
      }
      .wrap-inner {
        padding: 10px;
        height: 90px;
        border: 2px solid #000;
        overflow: hidden;
        background: #ccc;
      }
  </style>
</head>
<body>
<div class="wrap">
  <div>
    <ul class="list-1">
      <li>1-列表-1</li>
      <li>1-列表-2</li>
      <li>1-列表-3</li>
      <li>1-列表-4</li>
      <li>1-列表-5</li>
      <li>1-列表-6</li>
      <li>1-列表-7</li>
      <li>1-列表-8</li>
      <li>1-列表-9</li>
      <li>1-列表-10</li>
      <li>1-列表-11</li>
    </ul>
    <div class="wrap-inner">
      <ul class="list-2">
        <li>2-列表-1</li>
        <li>2-列表-2</li>
        <li>2-列表-3</li>
        <li>2-列表-4</li>
        <li>2-列表-5</li>
        <li>2-列表-6</li>
        <li>2-列表-7</li>
        <li>2-列表-8</li>
        <li>2-列表-9</li>
        <li>2-列表-10</li>
        <li>2-列表-11</li>
      </ul>
    </div>
    <ul class="list-3">
      <li>3-列表-1</li>
      <li>3-列表-2</li>
      <li>3-列表-3</li>
      <li>3-列表-4</li>
      <li>3-列表-5</li>
      <li>3-列表-6</li>
      <li>3-列表-7</li>
      <li>3-列表-8</li>
      <li>3-列表-9</li>
      <li>3-列表-10</li>
      <li>3-列表-11</li>
    </ul>
  </div>
</div> 
<script src="./node_modules/@better-scroll/core/dist/core.js"></script>
<script src="./node_modules/@better-scroll/nested-scroll/dist/nested-scroll.js"></script>
<script>
{
  BScroll.use(NestedScroll.default)
  const wrap = document.querySelector(".wrap");
  const wrapInner = document.querySelector(".wrap-inner");
  new BScroll(wrap,{
    nestedScroll:{
      groupId:"kkb"
    }
  });
  new BScroll(wrapInner,{
    nestedScroll:{
      groupId:"kkb"
    }
  });
}  
</script> 
</body>
</html>

无限滚动

注意从这里开始都是以better-scroll2.x的版本来演示案例

  • 案例演示如下:
  • 代码如下:
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    ul {
      margin: 0;
      padding: 0;
      list-style: none;
    }

    .wrap {
      position: relative;
      width: 300px;
      border: 2px solid #000;
      height: 500px;
      overflow: hidden;
    }

    .wrap li {
      font: 14px/30px "宋体";
    }
  </style>
</head>

<body>
  <div class="wrap">
    <ul class="list-1">
    </ul>
  </div>
  <script src="./node_modules/@better-scroll/core/dist/core.js"></script>
  <script src="./node_modules/@better-scroll/infinity/dist/infinity.js"></script>
  <script>
    {
      BScroll.use(InfinityScroll)
      const wrap = document.querySelector(".wrap");
      let nubs = 0;
      new BScroll(wrap, {
        infinity: {
          fetch(count) {
            // 获取大于 count 数量的数据,该函数是异步的,它需要返回一个 Promise。
            // case 1. resolve 数据数组Array<data>,来告诉 infinity 渲染数据,render 的第一个参数就是数据项
            // case 2. resolve(false), 来停止无限滚动
            return new Promise((resolve)=>{
                setTimeout(() => {
                  let data = [];
                  for (let i = 0; i < count; i++) {
                    nubs++;
                    data.push(`这是第${nubs}个li`);
                  }
                  resolve(data);
                }, 500);
            })
          },
          render(item,div) {
            // item 是 fetch 函数提供的每一个数据项,
            // div 是页面回收的 DOM,可能不存在
            // 如果 div 不存在,你需要创建一个新的 HTMLElement 元素
            // 必须返回一个 HTMLElement
            div = div?div:document.createElement("li");
            div.innerHTML = item;
            return div;
          },
          createTombstone() {
            // 必须返回一个墓碑 DOM 节点。
            const li = document.createElement("li");
            li.className = "tombstone";
            li.innerHTML = "请求数据中";
            return li;
          }
        }
      });
    }  
  </script>
</body>

</html>