背景:

弹层里边有可滚动区域时,在移动端的坑我就不多说了。

找了很多解决滚动穿透的方案,最终都不能完美解决。

一气之下自己js撸了一个。

效果图:

原理:

1、解决滚动穿透:通过给弹层绑定touchmove和mousewheel事件,取消默认行为实现。

2、取消默认行为后不能滚动:给需要滚动展示的区域绑定touchstart、touchmove和mousewheel事件,监听触发区域的Y值,对应修改可滚动区域的translateY值,实现滚动效果。

缺点/不足:
滑动起来略显卡顿,用户体验不好,有大佬给提示下怎么优化吗?

代码:

 <div class="layer">
<div class="layer-box">
<h3>title
<span class="close">X</span>
</h3>
<div class="lose-list">
<ul class="layer-scroll">
<li class="lose-item">
<h3>有效降价车款1</h3>
<ul class="lose-date">
<li>10月7日5分</li>
<li>10月7日6分</li>
<li>10月7日7分</li>
<li>10月7日8分</li>
<li>10月7日9分</li>
<li>10月7日10分</li>
<li>10月7日11分</li>
<li>10月7日12分</li>
<li>10月7日13分</li>
<li>10月7日14分</li>
<li>10月7日15444分</li>
</ul>
</li>
<li class="lose-item">
<h3>有效降价车款2</h3>
<ul class="lose-date">
<li>10月7日5分</li>
<li>10月7日6分</li>
<li>10月7日7分</li>
<li>10月7日8分</li>
<li>10月7日9分</li>
<li>10月7日10分</li>
<li>10月7日11分</li>
<li>10月7日12分</li>
<li>10月7日13分</li>
<li>10月7日14分</li>
<li>10月7日15333分</li>
</ul>
</li>
<li class="lose-item">
<h3>有效降价车款3 </h3>
<ul class="lose-date">
<li>10月7日5分</li>
<li>10月7日6分</li>
<li>10月7日7分</li>
<li>10月7日8分</li>
<li>10月7日9分</li>
<li>10月7日10分</li>
<li>10月7日11分</li>
<li>10月7日12分</li>
<li>10月7日13分</li>
<li>10月7日14分</li>
<li>10月7日152222分</li>
</ul>
</li>
</ul>
<div class="right-bar">
<div class="bar-pro"></div>
</div>
</div>
</div>
</div>
 myScroll({
openBtn: 'button',
layer: '.layer',
client: '.lose-list',
scroll: '.layer-scroll',
barBG: '.right-bar',
bar: '.bar-pro'
});
function myScroll(params) {
var utils = {
clientH: $(params.client).height(), //h1
scrollH: $(params.scroll).height(), //h2
barBgH: $(params.barBG).height() //h4
}
var lastY = 0,
transY = 0,
barTransY = 0,
barH = 0; //h3
function noScroll(dom) {
$(dom).on('mousewheel', function (e) {
e.preventDefault();
});
$(dom).on('touchmove', function (e) {
e.preventDefault();
});
}
function touchToBottom(target, bar) {
$(target).on('touchstart', function (e) {
e.preventDefault();
let y = e.originalEvent.touches[0].pageY;
lastY = y;
});
$(target).on('touchmove', function (e) {
e.preventDefault();
let y = e.originalEvent.touches[0].pageY,
moveY = y - lastY;
transY += moveY;
if (moveY > 0 && transY > 0) {
/* 鼠标向下移动,对应元素向上回看 */
transY = 0; //到顶
} else {
/* 鼠标向上移动,对应元素向下翻看 */
if (Math.abs(transY) >= e.currentTarget.clientHeight - utils.clientH) { //触底
transY = -(e.currentTarget.clientHeight - utils.clientH) + 1;
}
}
$(this).css('transform', `translate(0px, ${transY}px)`);
/* 移动时,滚轮的变化监听 */
var barMove = Math.abs(moveY) * utils.barBgH / utils.scrollH;
if (moveY > 0) {
barMove = -barMove;
}
barTransY += barMove;
if (moveY > 0) {
if (barTransY <= 0) {
barTransY = 0; //到顶
}
} else {
if (barTransY >= utils.barBgH - barH) {
barTransY = utils.barBgH - barH; //到底
}
}
$(bar).css('transform', `translate(0px, ${barTransY}px)`);
lastY = y;
});
/* 滚轮事件 */
$(target).on("mousewheel", function (e, delta) {
e.preventDefault();
let y = e.originalEvent.deltaY;
if (y > 0) {
/* 向下翻滚轮 wheelDeltaY的值与之相反*/
transY -= 100;
barTransY += 100 * utils.barBgH / utils.scrollH;
if (Math.abs(transY - 100) >= e.currentTarget.clientHeight - utils.clientH) { //触底
transY = -(e.currentTarget.clientHeight - utils.clientH) + 1;
}
if (barTransY > utils.barBgH - barH) {
barTransY = utils.barBgH - barH
}
} else {
/* 向上翻滚轮*/
transY += 100;
barTransY -= 100 * utils.barBgH / utils.scrollH;
if (Math.abs(transY) - 100 <= 0) {
transY = 0; //到顶
}
if (barTransY <= 0) {
barTransY = 0; //到顶
}
}
$(this).css('transform', `translate(0px, ${transY}px)`);
$(bar).css('transform', `translate(0px, ${barTransY}px)`);
});
}
noScroll(params.layer);
$(params.layer + ' .close').on('click', function () {
$(params.layer).fadeOut();
// $(params.scroll).css('transform', 'translate(0px, 0px)');
// $(params.bar).css('transform', 'translate(0px, 0px)');
});
$(params.openBtn).on('click', function () {
$(params.scroll).css('transform', 'translate(0px, 0px)');
$(params.bar).css('transform', 'translate(0px, 0px)');
lastY = 0;
transY = 0;
barTransY = 0;
$(params.layer).fadeIn();
utils = {
clientH: $(params.client).height(), //h1
scrollH: $(params.scroll).height(), //h2
barBgH: $(params.barBG).height() //h4
}
barH = parseInt(utils.clientH * utils.barBgH / utils.scrollH); //h3
$(params.bar).height(barH + 'px');
if (utils.clientH < utils.scrollH) {
touchToBottom(params.scroll, params.bar);
}
});
}

完整demo见github:

移动端超出滚动效果

声明:

  请尊重博客园原创精神,转载或使用图片请注明:

  博主:xing.org1^

  出处:http://www.cnblogs.com/padding1015/

js - 移动端的超出滚动功能,附带滚动条,可解决弹层中滚动穿透问题。的更多相关文章

  1. 解决: 移动端经mouseover显示出的弹层中链接点击问题

    通常我们会遇到这样的需求,导航菜单在鼠标划过的时候显示自定义弹层,在弹层中有一些链接需要点击后跳转或者其他一些事件.比如: $(".menu li").on("mouse ...

  2. css 之内容溢出滚动,隐藏滚动条(解决火狐浏览隐藏不了滚动条问题)

    解决火狐浏览隐藏不了滚动条问题 1.里层容器的width多17px,外层容器溢出隐藏,能兼容各个浏览器 .outContainer { width:350px; height:300px; overf ...

  3. 弹层蒙版(mask),ios滚动穿透,我们项目的解决方案

    问题描述 项目开发遇到一个ios独有的问题,在wkwebview中稳定复现 问题: 弹出一个蒙版,当在蒙版上面滑动的时候蒙版后面的内容滚动了 这当然是ios的bug,但是经过我们测试iphone7也会 ...

  4. C# 在RichTextBox中滚动鼠标时滚动的是父窗口的滚动条

    1. RichTextBox u2 = new RichTextBox(); 2. 先记住日RichTextBox没有显示滚动条时的总宽度和显示宽度 u2.Width - u2.ClientSize. ...

  5. 基于animate.css动画库的全屏滚动小插件,适用于vue.js(移动端、pc)项目

    功能简介 基于animate.css动画库的全屏滚动,适用于vue.js(移动端.pc)项目. 安装 npm install vue-animate-fullpage --save 使用 main.j ...

  6. 原生js移动端列表无缝间歇向上滚动

    在项目开发中尤其是在项目的活动页面的开发中,经常需要将用户的购买信息或中奖信息等以列表的形式展示在页面当中,并可以使其自动间歇向上滚动来达到在有限的区域内展示所有信息的目的.通常的做法是通过将列表父元 ...

  7. JS pc端和移动端共同实现复制到剪贴板功能实现

    JS pc端和移动端实现复制到剪贴板功能实现 在网页上复制文本到剪切板,一般是使用JS+Flash结合的方法,网上有很多相关文章介绍.随着 HTML5 技术的发展,Flash 已经在很多场合不适用了, ...

  8. vue.js移动端app实战4:上拉加载以及下拉刷新

    上拉加载以及下拉刷新都是移动端很常见的功能,在搜索或者一些分类列表页面常常会用到. 跟横向滚动一样,我们还是采用better-scroll这个库来实现.由于better已经更新了新的版本,之前是0.几 ...

  9. 基于Vue.js PC桌面端弹出框组件|vue自定义弹层组件|vue模态框

    vue.js构建的轻量级PC网页端交互式弹层组件VLayer. 前段时间有分享过一个vue移动端弹窗组件,今天给大家分享一个最近开发的vue pc端弹出层组件. VLayer 一款集Alert.Dia ...

随机推荐

  1. iOS 跳转到系统指定设置界面

    在需要调转的按钮动作中添加如下的代码,就会跳转到设置中自己的app的设置界面,这里会有通知和位置权限的设置 NSURL * url = [NSURLURLWithString:UIApplicatio ...

  2. Cocos2d-x 3.x游戏开发之旅 笔记

    #include "HelloWorldScene.h"#include "SimpleAudioEngine.h"#include "MyHello ...

  3. 27.移除元素(c++方法实现)

    问题描述: 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间 ...

  4. 隐藏控件--HiddenField控件

    HiddenField控件百度查的结果(帮助大家对比理解): HiddenField控件顾名思义就是隐藏输入框的服务器控件,它能让你保存那些不需要显示在页面上的且对安全性要求不高的数据.也许这个时候应 ...

  5. 打通MySQL架构和业务的任督二脉

    目前,在很多OLTP场景中,MySQL数据库都有着广泛的应用,也有很多不同的使用方式.从数据库的业务需求.架构设计.运营维护.再到扩容迁移,不同的MySQL架构有不同的特点,适应一定的业务场景,或者解 ...

  6. B+树索引和哈希索引的区别[转]

    导读 在MySQL里常用的索引数据结构有B+树索引和哈希索引两种,我们来看下这两种索引数据结构的区别及其不同的应用建议. 二者区别 备注:先说下,在MySQL文档里,实际上是把B+树索引写成了BTRE ...

  7. STL--迭代器(iterator)使用详解

    迭代器的分类 在STL中,原生指针也是一种迭代器,除了原生指针以外,迭代器被分为五类: Input Iterator 此迭代器不允许修改所指的对象,即是只读的.支持==.!=.++.*.->等操 ...

  8. 简单的redis 的list应用

    error_reporting(E_ALL); if(empty($a)){ echo 111; }else{ echo 3333; } die; phpinfo();die; $redis = ne ...

  9. 编写SHELL脚本--判断用户的参数

    测试语句格式: [ 条件表达式 ] 常见的几种形式: [ -d /etc ]  判断/etc是不是一个目录类型, [ -e /etc/php.ini ] 判断/etc/php.ini 文件是否存在 [ ...

  10. IDEA使用笔记(六)——设置项目的JDK配置

    1:由于dev分支和master分支的代码差异比较多,所以,就从master上分出一个新的分支dev_,于是我就克隆新的代码,打开对应的项目文件,然后启动试试,发现报出如下的错误,很明显是因为没有制定 ...