一、问题的产生

基础框架界面如图1所示,目前app流行布局

      图1

布局关注点:

  1.Title和Footer部分为固定布局position:fixed,存在的争议是android2.x和IOS4一下说是不支持,过渡办法是position:absolute(本手机亲测android2.3.7是支持position:fixed的,android2.2系列市场占有率不到1%,IOS4一下也是忽略,如果要兼容js控制位置也可以...自行百度)

  2.Content内容为滚动,其实通过布局为position:absolute;overflow:auto;能达到支持滚动条、动态滑动等效果,存在争议的是android2.x和IOS5不支持overflow:auto,所以必须要js模拟滑动效果(由此引出下文)

二、问题的解决

解决的思路如图2所示

解决问题需要注意的点:

1.js判断操作系统类型,根据navigator.userAgent的返回基本可以判断android类型(具体方法见代码,IOS网上说也可以,但是我是没有苹果设备没来得及测试)

2.系统默认滚动条的添加需要采用动态创建style标签,往标签里写webkit的自定义滚动条样式,类似"::-webkit-scrollbar {width: 3px;}",这种样式可以达到修改浏览器默认样式的效果,主要是为了跟自定义滚动条样式统一(具体有哪些见代码)

3.Content部分滑动效果采用css的transition,android都是采用webkit内核,低版本需要加前缀-webkit-,要达到的效果有界面跟随手指滑动、自定义滚动条滚动、快速滑动后的阻尼效果、上下边界超出部分的回滚等,其中浏览器原生效果没有上下边界超出部分回滚效果,这个可以自己做

三、代码和分析

1.html部分

 .header2-bar
span.header-back 返回
span.head-title 标题
.content2-bar#wrapper
.content-scroll#scroll
ul
li 周考
li 月考
li 季考
li 期考
li 年考
li 年考1
li 年考2
li 年考3
li 年考4
li 年考5
li 年考6
li 年考7
li 年考8
li 年考9
li 年考10
li 年考11
li 年考12
li 年考13
li 年考14
li 年考15
li 年考16
li 年考17
li 年考18
li 年考19
li 年考20
li 年考21
li 年考22
li 年考23
li 年考24
li 年考25
li 年考26
li 年考27
li 年考28
li 年考29
li 年考30
li 年考31
li 年考32
li 年考33
.footer2-bar
ul.footer-nav
li 主页
li 数学
li 语文
li 物理
li 化学

由于开发框架的原因,我这里提供的是jade的源代码,就跟html一样(最后也是编译为html),还不明白的话还是自行百度

2.css部分

 .header2-bar {
position: fixed;
width: 100%;
height: 50px;
z-index: 2;
left: 0;
top: 0;
text-align: center;
line-height: 50px; .header-back {
display: block;
width: 30px;
height: 30px;
position: absolute;
left: 10px;
top: 10px;
padding: 3px;
line-height: 30px;
} }
.content2-bar {
position: absolute;
width: 100%;
top: 50px;
left: 0;
bottom: 50px;
z-index: 1;
overflow-y: auto; .content-scroll {
overflow: auto;
position: relative; li {
height: 45px;
line-height: 45px;
}
} .lowerScrollBar {
position: absolute;
right: 0;
top: 0;
width: 3px;
background-color: rgba(0, 0, 0, 0.5);
border: 1px solid rgba(255, 255, 255, 0.9);
border-radius: 3px;
}
}
.footer2-bar {
position: fixed;
width: 100%;
height: 50px;
z-index: 2;
left: 0;
bottom: 0; .footer-nav {
display: block;
width: 100%;
height: 100%; li {
width: 20%;
height: 100%;
display: block;
float: left;
line-height: 50px;
text-align: center;
}
}
}

由于开发框架的原因,我这里提供的是less的源代码,就跟css一样(最后也是编译为css),还不明白的话还是自行百度

3.js代码

 /**
* 低版本Android模拟滑动
* @param id 滑动区域id
*/
function noBarsOnTouchScreen(id) {
var elem, //滑动元素
ty, //滑动Y位置
tyStart, //初始滑动Y位置
scrollBar, //模拟滚动条
elemHeight, //滑动元素高度
elemParentHeight, //滑动元素夫容器高度
startTime, //滑动开始时间
endTime; //滑动结束时间
if('ontouchstart' in document.documentElement) {
if(elem = document.getElementById(id)) {
elem.style.overflow = 'hidden';
elemHeight = elem.offsetHeight;
elemParentHeight = elem.parentNode.offsetHeight; elem.ontouchstart = ts;
elem.ontouchmove = tm;
elem.ontouchend = te; addScrollBar();
}
} //touchstart
function ts(e) {
var tch;
if(e.touches.length == 1) {
e.preventDefault();
e.stopPropagation();
tch = e.touches[0];
ty = tch.pageY;
tyStart = ty;
startTime = new Date().getTime(); this.style.transition = '';
scrollBar.style.transition = '';
}
} //touchmove
function tm(e) {
var tch; if(e.touches.length == 1) {
e.preventDefault();
e.stopPropagation();
tch = e.touches[0]; var top = this.style.top;
if(top) {
top = parseInt(top.replace('px', ''));
} else {
top = 0;
}
top -= (ty - tch.pageY);
ty = tch.pageY; //滚动条位置
var scrollBarTop = (-top) * (elemParentHeight) / elemHeight; if(top > 0) { //保证顶部不拉出
if(top > 50) top = 50;
}
if(top < (elem.parentNode.offsetHeight - elem.offsetHeight) - 50) { //保证底部不拉出
top = elem.parentNode.offsetHeight - elem.offsetHeight -50;
}
console.log('top: ' + top);
this.style.top = top + 'px'; scrollBar.style.top = scrollBarTop + 'px';
}
} //touchend
function te(e) {
e.preventDefault();
e.stopPropagation();
endTime = new Date().getTime();
var scrollBarTop; var top = this.style.top;
if(top) {
top = parseInt(top.replace('px', ''));
} else {
top = 0;
} var speed = Math.abs(top) / (endTime - startTime);
console.log(speed);
if(speed > 1.0) {
if(tyStart < ty) {
top += speed * 100;
}
if(tyStart > ty) {
top -= speed * 100;
}
this.style.transition = 'top 0.4s cubic-bezier(.12,.71,.83,.67)';
this.style['-webkit-transition'] = 'top 0.4s cubic-bezier(.12,.71,.83,.67)';
this.style.top = top + 'px'; //滚动条位置
scrollBarTop = (-top) * (elemParentHeight) / elemHeight;
scrollBar.style.transition = 'top 0.4s cubic-bezier(.12,.71,.83,.67)';
scrollBar.style['-webkit-transition'] = 'top 0.4s cubic-bezier(.12,.71,.83,.67)';
scrollBar.style.top = scrollBarTop + 'px';
} //顶部拉过了 弹回
while(top > 0) {
top = 0; this.style.transition = 'top 0.4s cubic-bezier(.12,.71,.83,.67)';
this.style['-webkit-transition'] = 'top 0.4s cubic-bezier(.12,.71,.83,.67)';
this.style.top = top + 'px'; //滚动条位置
scrollBarTop = (-top) * (elemParentHeight) / elemHeight;
scrollBar.style.transition = 'top 0.4s cubic-bezier(.12,.71,.83,.67)';
scrollBar.style['-webkit-transition'] = 'top 0.4s cubic-bezier(.12,.71,.83,.67)';
scrollBar.style.top = scrollBarTop + 'px';
}
//底部拉过了 弹回
while(top < 0 && (elemParentHeight + Math.abs(top)) > elemHeight) {
top = elemParentHeight - elemHeight; this.style.transition = 'top 0.4s cubic-bezier(.12,.71,.83,.67)';
this.style['-webkit-transition'] = 'top 0.4s cubic-bezier(.12,.71,.83,.67)';
this.style.top = top + 'px'; //滚动条位置
scrollBarTop = (-top) * (elemParentHeight) / elemHeight;
scrollBar.style.transition = 'top 0.4s cubic-bezier(.12,.71,.83,.67)';
scrollBar.style['-webkit-transition'] = 'top 0.4s cubic-bezier(.12,.71,.83,.67)';
scrollBar.style.top = scrollBarTop + 'px';
} } //添加默认滚动条
function addScrollBar() {
scrollBar = document.createElement('div');
scrollBar.className = 'lowerScrollBar';
scrollBar.id = 'lowerScrollBar';
scrollBar.style.height = elemParentHeight * elemParentHeight / elemHeight + 'px';
elem.parentNode.appendChild(scrollBar);
}
} /**
* 添加默认滚动条
*/
function addDefultScrollBar() {
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '::-webkit-scrollbar {width: 3px;}::-webkit-scrollbar-thumb {background-color: rgba(0, 0, 0, 0.5);border: 1px solid rgba(255, 255, 255, 0.9);border-radius: 3px;}::-webkit-scrollbar-thumb:window-inactive {background-color: rgba(0, 0, 0, 0.6);}';
document.head.appendChild(style);
} /**
* 判定是否是低版本android
* 是低版本android就要模拟滑动
* 不是低版本android就要添加默认滚动条
*/
function isLowerAndroid() {
var us = navigator.userAgent.toLowerCase();
var isAndroid = us.indexOf('android') > -1;
if(isAndroid) {
var version = us.substr(us.indexOf('android') + 8, 3);
if(parseInt(version) <) {
noBarsOnTouchScreen('scroll');
} else {
addDefultScrollBar();
}
} else {
addDefultScrollBar();
}
} isLowerAndroid();

红色字体不是突出,只是粘贴的时候富文本控件自己添加的

四、结果分析

1.测试在android2.3.7(好几年前的手机了...)和android4.4.4里测试都通过,基本上还是能模拟原生浏览器的下拉效果,更复杂和更棒的滑动效果就要自己动手了

2.界面效果如图3所示

3.进一步分析存在的问题

  1)手势判断,目前判断手指滑动的方向是ontouchstart的时候记录手指的位置,ontouchmove的时候更新手指位置,在ontouchend的时候对差值计算判断手指的上下滑动方向,这里存在一个问题连续多次在屏幕上滑动就会不靠谱,理想的办法是分析最后多次ontouchmove的手指位置变化趋势,根据这个趋势来判定手指滑动的方向(不知道有些库是怎么判断的,如果知道的人可以分享一下)

  2)阻尼效果,快速滑动屏幕的时候有一个阻尼效果,会使得屏幕往手指滑动方向再滑动一定距离,这个需要判定手指滑动的速度。目前采用的是在ontouchstart记录开始时间,ontouchend记录结束时间,根据滑动具体计算平均滑动速度,如果速度值大于1,表示需要产生阻尼滑动效果,然后再根据该速度滑动一定距离,这个效果没有原生效果看起来那么棒(这里也求一个阻尼效果的js分析)

  3)css动画和js动画,之前一直采用js做动画,发现都达不到平滑过渡的效果(js太差劲了),不得已采用css模式,js厉害的人可以分析一下采用原生代码完成这个滑动效果,我想的话最好是支持设定贝塞尔值的滑动

  4)这只是一个主界面架子,app还要支持横向滚动,界面切换,局部切换...太多东西了

web app 基础界面框架搭建的更多相关文章

  1. .NET Core MVC Web最最最基础的框架搭建

    1. 使用VS创建.NET Core MVC Web项目 创建完成就是酱紫的了 2. 用NuGet把这些全部都安装了 Install-Package Microsoft.EntityFramework ...

  2. javaWeb项目(SSH框架+AJAX+百度地图API+Oracle数据库+MyEclipse+Tomcat)之一 基础Struts框架搭建篇

    即将开始着手写这个项目,所以希望通过这篇博客来记录自己学习的过程 今天开学第一天,就上了软件工程实践课,自己也开始着手做这个大作业了.首先我的项目名称叫做智能班车管理系统. 项目的概况: 该软件产品是 ...

  3. IOS开发-基于WebDriverAgent代理服务,实现iOS手机app自动化测试的框架搭建

    导引 iOS自动化测试一直使用的appium,iOS系统升级至10.0 Xcode8.0之后,改用WebDriverAgent代理服务作为server,编写了一套基于WebDriverAgent服务 ...

  4. 基于WebDriverAgent代理服务,实现iOS手机app自动化测试的框架搭建

    iOS自动化测试一直使用的appium,iOS系统升级至10.0 Xcode8.0之后, 改用WebDriverAgent代理服务作为server,编写了一套基于WebDriverAgent服务 ap ...

  5. MontageJS:构建现代 Web App 的 HTML5 框架

    MontageJS 可以帮助您构建高可扩展性和可维护性的 HTML5 应用.有了 MontageJS,开发人员可以创建可重用的用户界面组件和模块,组件和控制器之间的绑定属性,并且同步 DOM 查询和更 ...

  6. 【AMAD】splinter -- 用于测试web app的python框架

    简介 动机 作用 用法 热度分析 个人评分 简介 Splinter1是一个开源工具,使用Python编写,用于测试web apps.它可以用来对浏览器实现自动化操作,比如访问URLs,和按钮等交互. ...

  7. 基于Web Service的客户端框架搭建四:终结篇

    前言 这是这个系列的终结篇,前面3个博客介绍了一下内容: 1.使用Http Post方式调用Web Service 2.客户端框架之数据转换层 3.客户端框架之代理层 框架结构 框架是基于C#的,在V ...

  8. [知了堂学习笔记]_用JS制作《飞机大作战》游戏_第1讲(素材查找和界面框架搭建)

    一.查找素材: 二.分析游戏界面框架: 登录界面.游戏界面.暂停游戏界面.玩家死亡后弹出界面:并对应的界面包含什么元素: 三.分别搭建以上四个界面: 1.登录界面与游戏界面框架(隐藏游戏界面,四个界面 ...

  9. JAVA之Mybatis基础入门--框架搭建与简单查询

    JAVA中,操作数据库有JDBC.hibernate.Mybatis等技术,今天整理了下,来讲一讲下Mybatis.也为自己整理下文档: hibernate是一个完全的ORM框架,是完全面向对象的.但 ...

随机推荐

  1. 2016 ACM Amman Collegiate Programming Contest D Rectangles

    Rectangles time limit per test 5 seconds memory limit per test 256 megabytes input standard input ou ...

  2. mapreduce on yarn简单内存分配解释

    关于mapreduce程序运行在yarn上时内存的分配一直是一个让我蒙圈的事情,单独查任何一个资料都不能很好的理解透彻.于是,最近查了大量的资料,综合各种解释,终于理解到了一个比较清晰的程度,在这里将 ...

  3. 寒假学干货之------初步布局Layout

    在开发的最初,需要设计好我们的Activity,在res/layout下,找到**activitymian(名字都差不多的)的.xml文件,打开他就可以开始编辑. http://www.tuicool ...

  4. 第七十四节,css边框与背景

    css边框与背景 学习要点: 1.声明边框 2.边框样式 3.圆角边框  本章主要探讨HTML5中CSS边框和背景,通过边框和背景的样式设置,给元素增加更丰富的外观. 声明边框 边框的声明有三个属性设 ...

  5. 整体认识flume:Flume介绍、分布式安装、常见问题及解决方案

    问题导读 1.什么是flume? 2.flume包含哪些组件? 3.Flume在读取utf-8格式的文件时会出现解析不了时间戳,该如何解决? Flume是一个分布式.可靠.和高可用的海量日志采集.聚合 ...

  6. javascript 限制字符串字数换行 带BUG

    function chang(str ,len) { function lenStat(str) { function isChinese(str) { //判断是不是中文 var reCh = /[ ...

  7. JVM基础(5)-垃圾回收机制

    一.对象引用的类型 Java 中的垃圾回收一般是在 Java 堆中进行,因为堆中几乎存放了 Java 中所有的对象实例.谈到 Java 堆中的垃圾回收,自然要谈到引用.在 JDK1.2 之前,Java ...

  8. HDU 1969 Pie(二分搜索)

    题目链接 Problem Description My birthday is coming up and traditionally I'm serving pie. Not just one pi ...

  9. 转载–移动互联网终端的touch事件,touchstart, touchend, touchmove

    转载请注明: 转载自WEB前端开发(www.css119.com)-关注常见的WEB前端开发问题.最新的WEB前端开发技术(webApp开发.移动网站开发).最好的WEB前端开发工具和最全的WEB前端 ...

  10. css-文本垂直居中(转)

    css-文本垂直居中(转) 在说到这个问题的时候,也许有人会问CSS中不是有vertical-align属性来设置垂直居中的吗?即使是某些浏览器不支持我只需做少许的CSS Hack技术就可以啊!所以在 ...