模拟滚动插件,支持滚轮和手势, 手势识别基于any-touch.
any-scroll的滚动实际是通过2个"父子div"的相对位置变化模拟的, 默认使用translate3d, 外层div叫"wrap", 里面用来装载内容的div叫"content".
<div> <!-- warp -->
<div> <!-- content -->
content
</div>
</div>
如果wrap下有多个元素, 那么any-scroll会把他们都构造成content实例, 但是只有一个"激活"状态的content实例, 只有他可以响应滚动, 当然你也可以切换任意content实例为激活.
<!-- warp -->
<div>
<!-- content -->
<div>content-1<div>
<!-- content -->
<div style="position: absolute;z-index:1;top:0;left:0;">
content-2
<div>
<!-- content -->
<div no-scroll>content-3<div>
</div>
注意:
- 多个content情况下, 请给第二个子元素做一个"初始定位", 比如
style="position: absolute;z-index:1;top:0;left:0;"
, any-scroll内部没有默认定位, 这样你可以自定义"位置"和"层级". - 如果不想某个子元素(content)"可滚动", 使用"no-scroll"进行标记.
npm i any-scroll -S
首先在页面构造如下html结构, 同时给wrap一个固定尺寸.
<div id="scroll-view" style="height:600px;width:360px;"><!-- wrap -->
<div><!-- content -->
<!-- 你的内容写在这里 -->
<div>
</div>
初始化:
import AnyScroll from 'any-scroll';
const el = document.getElementById('scroll-view');
const as = new AnyScroll(el);
// 滚动到x=-100,y=-100的位置.
as.scrollTo([-100,-100]);
// 只控制Y轴,1s内滑动到目标位置
as.scrollTo({y:-100},1000);
名称 | 默认值 | 说明 |
---|---|---|
allow | [true,true] |
是否允许X或Y轴滚动,数组第一位控制X轴 |
damping | 0.1 |
dampScroll的消损系数,范围0~1 |
overflowDistance | 100 |
允许超过边界的最大距离,单位"px" |
render | 查看 | 控制content元素位置变化的函数 |
默认通过translate3d控制content的位移, 如有需要也可改为控制margin或 top(left) 属性.
// 默认
function render(el, [x, y]) {
el.style.setProperty('transform',`translate3d(${x}px, ${y}px,0)`);
}
// 或者改为
function render(el, [x, y]) {
el.style.setProperty('marginLeft', x+'px');
el.style.setProperty('marginTop', y+'px');
}
const as = new AnyScroll({render});
监听事件, 默认继承了any-touch的所有手势事件.
事件名 | 说明 |
---|---|
scroll | 每次滚动 |
scroll-end | 滚动停止 |
tap | 单击 |
press | 按压 |
pan | 拖拽 |
swipe | 快滑 |
rotate | 旋转 |
pinch | 缩放 |
as.on('scroll-end',()=>{
console.log('滚动停止了');
})
滚动到指定位置, 支持时间动画
参数名 | 参考值 | 是否可选 | 说明 |
---|---|---|---|
distXY | [-100,-200] 或{x:-100,y:-200} |
必选 | 目标位置 |
duration | 1000 | 可选 | 滚动时间,单位毫秒 |
easing | 参考 | 可选 | 缓动动画函数, 一般不需要修改 |
// 3秒钟移动到x=-100,y=-500的位置.
as.scrollTo([-100,-500],3000);
// 等价写法
as.scrollTo({x:100,y:-500},3000);
瞬间移动到目标位置
参数名 | 参考值 | 是否可选 | 说明 |
---|---|---|---|
distXY | [-100,-200] 或{x:-100,y:-200} |
必选 | 目标位置 |
as.moveTo([-100,-200]);
移动元素到wrap左上角.
参数名 | 参考值 | 是否可选 | 说明 |
---|---|---|---|
el | DOM元素 | 必选 | 目标元素 |
offset | [0,0] 或{x:0,y:0} |
可选 | 对目标位置修正, 多滚动的距离 |
duration | 1000 | 可选 | 滚动时间,单位毫秒 |
easing | 参考 | 可选 | 缓动动画函数, 一般不需要修改 |
// 滚动到content中的子元素(child-1), 让其左上角和wrap的左上角重合.
const childEl = doucument.getElementById('child-1');
as.scrollToElement(childEl);
// 滚动到child-1下方100px的位置
as.scrollToElement(childEl,{y:100});
// 等价写法
as.scrollToElement(childEl,[,100]);
作用同scrollTo,只是滚动效果不同, 其不能指定时间. 仅供插件开发者使用, 模拟快速划动scrollView产生的滚动.
参数名 | 参考值 | 是否可选 | 说明 |
---|---|---|---|
distXY | [-100,-200] 或{x:-100,y:-200} |
必选 | 目标位置 |
damping | 默认0.1, 范围0~1 | 可选 | 不断靠近目标位置,每次靠近剩余距离的0.1倍. |
as.dampScroll([-100,-200]);
如果滚动范围出现异常, 可手动更新.
as.update();
获取content实例, 其上有尺寸等数据.
参数名 | 参考值 | 是否可选 | 说明 |
---|---|---|---|
elOrIndex | number或HTML元素 | 可选 | 查看 ↓ |
- 如是number, 那么会按照wrap下的子元素索引取对应的content实例.
- 如是元素, 那么会递归向上找父元素, 直到找到对应的实例.
- 如果不传默认找当前激活状态的content实例.
as.getContentRef(1);
as.getContentRef(childEl);
as.getContentRef();
content实例或null
.
如果有多个content实例, 激活指定content实例, 只有激活的content才会响应滚动.
参数名 | 是否可选 |
---|---|
contentRef | 必选 |
// 激活第二个content实例.
const contentRef = as.getContentRef(1);
as.active(contentRef);
wrap元素
as.el; // <div class="any-scroll"></div>
any-scroll内部使用了any-touch手势库, 通过as.at
可以访问any-touch的实例,从而修改手势行为等, 详情参考any-touch
// 仅对表单元素阻止触发"默认事件"
// 这是any-touch参数的默认值, 在此仅做展示
as.at.set({
preventDefault(e){
if (event.target && 'tagName' in event.target) {
const { tagName } = event.target;
return !/^(?:INPUT|TEXTAREA|BUTTON|SELECT)$/.test(tagName);
}
return false;
}
})
注意: 普通开发者谨慎使用, 修改不当会影响滚动效果, 如开发中遇到缺少功能, 大家尽量先提Issue
wrap元素尺寸.
console.log(as.size);
as.on('scroll', context=>{
// 当前位置信息
// context === as
console.log(context.xy);
});
事件名称 | 说明 |
---|---|
scroll | 滚动 |
scrollEnd | 滚动结束 |
tap | 单击 |
press | 按压 |
pressup | 按压释放 |
pan | 拖拽 |
swipe | 滑动 |
pinch | 缩放 |
rotate | 旋转 |
除了"scroll"和"scroll-end", 其他事件都是any-touch实现的, 其事件对象上包含当前触点/距离/速度等信息, 更多请参考any-touch
as.on('tap', e=>{
// 当前触点x坐标
console.log(e.x)
})
any-scroll基于any-touch开发, 所以也支持他的所有手势, 但是为了体积默认只加载了swipe/pan, 开启更多方法:
import AScroll from 'any-scroll';
import tap from '@any-touch/tap';
import swipe from '@any-touch/swipe';
import pinch from '@any-touch/pinch';
import rotate from '@any-touch/rotate';
const as = new AScroll();
// 加载单击手势
as.at.use(tap);
// 加载快划
as.at.use(swipe);
// 加载缩放
as.at.use(pinch);
// 加载旋转
as.at.use(rotate);
as.on('tap',e=>{
});
如果wrap下的子元素, 有些你并不想让他"滚动", 可以给其加"no-scroll"标记.
<div>
<div></div> <!-- 能滚动 -->
<div no-scroll></div> <!-- 不能滚动 -->
</div>
当content中的子元素发生变化(增/减去/尺寸), any-scroll需要重新计算"可滑动范围".
默认any-scroll内部使用ResizeObserver(caniuse)监视wrap/content尺寸变化, 实现自动更新可滑动范围.
但其兼容性较差, 所以在不支持ResizeObserver的浏览器会使用MutationObserver(caniuse)降级兼容, 其只能监视content的子元素的增/减, 从而更新滑动范围.
如果不在意体积, 可以使用"resize-observer-polyfill", 其可让ResizeObserver兼容到最低IE9.
import ResizeObserver from 'resize-observer-polyfill';
// ⭐注入到全局
window.ResizeObserver = ResizeObserver;
import AnyScroll from 'any-scroll';
const as = new AnyScroll(el);
使用实例上的"update"方法更新"可滑动范围".