1.      mui简介

1.1  缘起

1、基于jq的jqmobile,性能低的无法忍受,且UI难看

2、bootstrap这种响应式设计,性能在低端机不足,而且UI风格一看就是网页,不是App的感觉。

3、framework7当时只能在iPhone上运行也无法被接受。

4、基于angular的ionic,把pc端很重的东西引入到移动App中,且angular学习门槛较高

看来看去ratchet框架还比较接近我们想要的高性能App框架,但发展理念和我们不同,我们是要求极致化的考虑App的性能。因此,我们撸起袖子,基于ratchet大幅改造实现了第一版的mui。

发展了一年半,目前mui已较完善,基于mui的app数量可统计的有20多万了,在360、大众点评、网易、京东等公司都有App使用了我们的框架。mui在github上的star数看起来不多,是2500+,希望今天过后这个数字能大幅上涨☺

附上mui的地址:https://github.com/dcloudio/mui

1.2  Mui的特点

小巧

mui不依赖任何第三方js库,核心js只有几十K;mui的核心是一个ui框架,并不是一个JS库,因此mui在实现上有所为、有所不为;mui框架中的js代码,均是为了ui组件服务,没有常用DOM操作等封装,这是mui和jQuery的区别。另外jq等框架是因为ie6-11的兼容性问题而壮大起来的,手机上都是webkit,没有引入jq的必要性,原生js很好用;

原生UI

mui的ui设计理念是:以iOS为基础,补充Android平台特有的控件;因此mui封装的控件,ui上更符合app的体验。

高性能

这是mui的重要特点,后续会单独讲述。

丰富模板

mui在逐步解决性能问题的基础上,开始封装了一系列的ui模板,比如首次启动欢迎页面,这个功能通过mui做的话可能几行代码就出来了;

如下为手机通讯录模板,常用于是通讯录、城市选择等场景,支持右侧滑动字母快速选择。

2.     mui框架如何解决性能问题

对于前端性能优化,大多数方法论是基于web的,比如压缩js、css,减少带宽请求;合并文件,减少网络请求次数;我们不谈这些常规的基于web的优化技巧,单独说说针对app,mui是如何实现性能优化的。

2.1  卡头卡尾及快速回弹滚动

在native app中,内容区域和顶部标题栏是不同的组件,内容区域的滚动条不会透穿标题栏;但使用HTML5开发mobileapp时,默认的body滚动条会透穿标题栏,这样的UI不符合app体验;通常的解决方案是使用DIV滚动(区域滚动),但DIV滚动是个大坑,我们简单回顾一下其历史:

•最早版本:iOS/Android均不支持非body元素的滚动

•iOS 5.0版本:支持区域滚动,滚动条可见

•Android 4.0:支持区域滚动,滚动条可见

•Android 4.1.x:支持区域滚动,滚动条不可见

•Android 4.4:支持区域滚动,滚动条可见

虽然区域滚动在不同版本上有各种问题,但body的原生滚动却一直很流畅; 因此我们的解决思路是:

•    将标题栏和内容区分别放到2个webview中

•    内容区使用body原生滚动;

Hello mui的首页其实就是index.html加list.html合并而成的,如下图:

为了方便工程师开发,我们封装了mui.init(subpages:{})方法,可以快捷创建子webview。

这里要引入一个概念,就是mui可以调用原生加速。在App开发中,js代码是和hybrid引擎一起打包成apk、ipa发布的,不是运行在浏览器里,此时引擎的原生操作能力要被充分发挥出来。

mui就是利用对原生的webview的操作能力,实现了在App中更流畅的体验。当然mui在普通浏览器里也可以运行上面的代码,这个是mui如何多端发布,后续会专门讲。

2.2  切页白屏和转场动画

传统的web开发,点击href跳转,会立即显示一个空白页面,然后看到页面的渲染绘制过程,这就是常说的“白屏等待”现象,这个是不符合App体验的;为了解决这个问题,部分框架推出了SPA(Single-pageapplication)方案,在一定程度上缓解了这个问题。

但SPA模式也有其短板:

1、DIV的动画模拟页面切换,在页面复杂时,会出现卡顿现象;

2、通过JS频繁操作DOM,VIEW切换时动态添加、删除事件监听,在低端机上会经常碰到性能问题,甚至出现浏览器崩溃。

MUI针对切页白屏的解决方案:

1、预加载和预渲染新界面,在背景创建webview加载新页面,点击跳转时,直接显示之前创建好的webview,因为已提前加载渲染,因此显示时不会白屏;

2、显示动画使用原生view动画,避免DIV动画的卡顿情况;

3、如果觉得还不够好,mui还提供预截图API,提前对预加载的webview进行截图(预截图),页面切换时直接使用截图代替webview的移动,毕竟图片移动动画的资源消耗要远低于view的移动动画资源消耗。

2.3  下拉刷新

DIV模拟的下拉刷新为什么会卡顿?在这里先带大家复习一下web页面的渲染过程,如下图:

主要流程:

1、JS代码执行:比如设置元素的位置属性;

2、样式计算:根据CSS选择器,对每个DOM元素匹配对应的CSS样式

3、布局:计算每个DOM元素最终在屏幕上显示的大小和位置。web页面中元素的布局是相对的,因此一个元素的布局发生变化,会联动地引发其他元素的布局发生变化,特别是其子元素和孙子元素

4、绘制:本质上就是填充像素的过程。包括绘制文字、颜色、图像、边框和阴影等,也就是一个DOM元素所有的可视效果。一般来说,这个绘制过程是在多个层上完成的

5、渲染层合并:由上一步可知,对页面中DOM元素的绘制是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序合并成一个图层,然后显示在屏幕上

知道了如上渲染流程,我们就不难理解为何DIV模拟实现的下拉刷新容易发生卡顿现象;随着手指的移动,JS不停更改拖动区域的top属性,然后不停引发后续的布局、重绘、渲染层合并;

mui的解决思路:

1、把一个页面拆分成两个webview,拖动的时候只拖动内容区的webview,拖动过程中webview位置变化,但webview内DOM元素位置不变,因此有效避免页面的布局、重绘操作;

2、拖动及回弹效果均采用原生动画实现,这就保证了原生的流畅体验。

2.4  硬件加速那些坑

很多同学都知道,若想动画流畅,需要启动硬件加速!但硬件加速也不能乱用。

mui最初是基于ratchet改造的,第一版本我们发现在Android手机上很容易出现闪屏或滚动卡顿的情况,后来排查代码,发现ratchet源码中有如下代码:

这样相当于将.content下所有元素全部设置了GPU加速,即使是一个没有任何动画的静态元素;我们删除该css定义后,Andriod性能大幅提升。

接着发现在列表数据较多时,iOS平台的侧滑菜单很容易crash,Android终端反而没问题;测试之后在需要执行transform动画的元素父元素之上增加如下定义,就解决了iOS的crash问题:

增加的这两行css定义解决了iOS的crash问题,却引发部分Android终端的transform不渲染,因此该样式还需修改成仅iOS平台生效。

2.5  click延迟及事件透传

300毫秒的由来

2007年初,苹果公司在发布首款iPhone前夕,遇到一个问题:当时的网站都是为大屏幕设备所设计的,不适合手机屏幕的阅读;为了解决这个问题,苹果的工程师们做了一些约定,这当中最出名的,当属双击缩放(double tap to zoom),具体方案:iOS Safari监听用户点击操作,在双击后准确地定位到页面主体文章,并将其缩放至适合比例展现。

那么问题来了,当用户点击屏幕上的一个链接时,浏览器并不能判断用户确实是要打开当前链接,还是要双击放大;因此,iOS Safari就等待300毫秒,以判断用户是否再次点击了屏幕;若有再次点击则触发双击放大;否则,触发单击逻辑,手机浏览器的点击300毫秒延时从此而生。

浏览器厂商的解决方案

优化这个延迟问题,浏览器也在积极采取措施,比如chrome通过meta禁用缩放:

<metaname="viewport" content="user-scalable=no">

<metaname="viewport"content="initial-scale=1,maximum-scale=1">

这个方案的最大问题是:完全禁用了页面元素缩放,当你想缩放显示图片时,就无法操作;

然后Chrome团队接着宣布:他们将在包含width=device-width或者置为比viewport 值更小的页面上禁用双击缩放。当然,没有双击缩放就没有300 毫秒点击延迟;这个方案虽妙,但毕竟只有Chrome支持,且有版本限制;iOSsafari除了双击缩放,还有双击滚动功能,双击问题存在,300毫秒就存在。

mui框架的解决方案

监听手机浏览器的touch事件,通过touch持续时间及移动距离来识别单击(tap)事件,当这两个值都小于特定阀值时,则触发单击(tap)事件。

•touch持续时间:touchend/touchcancel触发时间-touchstart时间

•移动距离:tohchmove事件中屏幕位置和touchstart事件中屏幕位置之间的直线距离

事件透传

问题描述:单击(tap)遮罩蒙版时,事件透传到蒙版下层的DOM元素上;比如Action sheet下方有一个<a href=“xxx”></a>链接,当点击Actionsheet控件时,会触发下层a标签的href跳转;

原因:还是300毫秒惹的祸,tap立即触发,很快关闭了遮罩层;但浏览器在300毫秒后才触发click事件,此时根据屏幕位置计算,event.target就刚好是下层的a标签,因此触发了a的默认行为href跳转。

mui解决方案:

关闭遮罩时,仅修改遮罩的透明度,并不真的关闭遮罩;等待350毫秒后,再真实关闭遮罩,这样300毫秒后,click事件触发时目标元素依然是遮罩层,从而避免click事件透传到下层的a标签;

2.6  更多底层API调用

除了webview、截图这些API操作,mui事实上可以调用Android和iOS的40多万原生API,在能力上基本与原生相同。包括拦截短信认证码、调用原生推送、扫描二维码都不在话下。

3.     多端发布

背景:大家刚才看到了mui在打包App时可以调用原生能力提升App体验,但有人会问,那岂不是无法在普通浏览器里运行了?所以mui引入了多端发布理念,通过另一种方式实现跨平台。

概念:一套基于mui的HTML5工程,通过框架的自适应和前端构建工具条件编译双管齐下,实现同时发行到iOSAppStore、安卓各大应用商店、普通手机浏览器、微信App、百度直达号和360流应用,并且并且,在每个平台上都能调用该平台的专有API达到原生体验。

Mui框架本身是支持多端发布的,Hello mui是一个WAP、流应用、Android app、iOS app一套代码多端均可使用的示例,可参考Hello mui的代码,也可以直接访问http://www.dcloud.io/hellomui体验。

实现方案示例—打开新窗口:

使用过mui的同学知道,开发App时,使用mui.openWindow()方法会创建或显示一个新的webview;但在WAP或微信中,没有webview窗口,如何实现页面切换呢?此时mui会自动降级变成href跳转;

实现方案示例—子窗口:

为了流畅的滑动体验,mui不推荐使用DIV区域滚动,若有长列表时,建议使用mui.init(subpages:{})创建子webview,然后在子webview中使用原生滚动;同样的问题,为了兼容WAP和微信,mui在这两个平台,会计算位置并创建iframe,将子页面内容显示到iframe中。

之所以引入构建工具做条件编译,而不是全部在框架里动态判断,是因为把判断放在用户操作之前,能大幅减少用户等待。

总结下与纯SPA框架的对比。

mui不排斥SPA,在mui里我们也适度引入了SPA,但对比其他纯SPA的前端框架,mui的设计思路是与他们不同的。纯SPA也能开发一次到处使用,但无法在App环境下达到原生级的体验。Mui的多端发布,同样也是跨平台,但在执行性能、充分调用引擎能力上都有更强的优势。

4. DCloud还为HTML5开发者提供那些产品服务

4.1 HBuilder

Hbuilder是DCloud提供的极客型HTML5开发IDE,它应该是目前写前端代码最快的编辑器,它的AST语法分析和提示系统也是世界级的。

工具是免费的,没有增值收费项目。

4.2 流应用

流应用是我们做的一个很酷的、有突破性的东西。

一般的App在应用市场下载时是下载按钮,点击后需要一分钟左右、点击数次,app才能启动。但流应用是可以直接秒开的。

流应用,其实是把使用mui开发的、原本打包为apk发行的那些文件,压缩和改造了包格式,使得安装包可以边用边下,一个流应用一般4秒左右就可以安装启动。

见下图,在360手机助手里搜索大众点评外卖,可以看到下载按钮变成秒开按钮:

mui体验理解的更多相关文章

  1. MUI体验框架

    1.      mui简介 1.1  缘起 1.基于jq的jqmobile,性能低的无法忍受,且UI难看 2.bootstrap这种响应式设计,性能在低端机不足,而且UI风格一看就是网页,不是App的 ...

  2. MUI简介-最接近原生App体验的前端框架

    MUI简介-最接近原生App体验的前端框架 一.总结 一句话总结:最接近原生App体验的前端框架 二.多端发布 – 开发一套代码,发布六个平台 真正彻底的跨平台开发,不是简单的跨iOS和Android ...

  3. vue.js2.0 自定义组件初体验

    理解 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能.在有些情况 ...

  4. 巨蟒python全栈开发flask8 MongoDB回顾 前后端分离之H5&pycharm&夜神

    1.MongoDB回顾 .启动 mongod - 改变data/db位置: --dbpath D:\data\db mongod --install 安装windows系统服务 mongod --re ...

  5. uni-app官方教程学习手记

    本人微信公众号:前端修炼之路,欢迎关注 背景介绍 大概在今年的十月份左右,我了解到Dcloud推出了uni-app.当时下载了一个Hbuilder X,下载了官方提供的hello示例教程.经过一番努力 ...

  6. 在github上写个人简历——最简单却又不容易的内容罗列

    前篇博客分享了一下自己初入github的过程,傻瓜式一步步搭建好主页后,终于该做正事儿了——写简历.在脑袋中构思了很多版本,最后终于决定,先写一个最传统的版本,于是我在箱子中翻出我word版本的简历, ...

  7. WordCount by C# 结对编程

    合作者:201631062210,201631062110 Gitee项目地址:https://gitee.com/zhouyue98/learngit 本次作业的链接地址:https://edu.c ...

  8. MUI - 将tap模拟成原生click体验

    mui提供了tap事件替换了html5的click事件,解决了300ms延时的问题.不过相比原生app的click体验还是有些许差距的.关于300ms延时的问题,这篇帖子分析的比较完善,其中提到了穿透 ...

  9. YII学习,初体验 ,对YII的一些理解.

    先说点没用的: 不会选择,选择后不坚持,不断的选择.这是人生中的一个死循环,前两一直迷茫.觉得自己前进方向很不明朗.想去学的东西有很多.想学好YII,想学PYTHON 想学学hadoop什么的,又想研 ...

随机推荐

  1. Python查看关键字和帮助信息

    1.查看所有的关键字 >>> help('keywords') Here is a list of the Python keywords. Enter any keyword to ...

  2. 【题解】Luogu P2257 YY的GCD

    原题传送门 这题需要运用莫比乌斯反演(懵逼钨丝繁衍) 显然题目的答案就是\[ Ans=\sum_{i=1}^N\sum_{j=1}^M[gcd(i,j)=prime]\] 我们先设设F(n)表示满足\ ...

  3. shell编程(四)之循环控制语句(for,while,until,break,continue,case)

    for循环 语法:for NAME in LIST; do 循环体 done 列表生成方式:1.整数列表 {start...end} $(seq,[start [step]] end)2.glob / ...

  4. 最后一次谈 VirtualBox的安装方法

    用 VirtualBox....run 或 .rpm安装都可以, 最重要的是要 用 /usr/sbin/vboxconfig -> vboxdrv.sh --> 去创建 VirutalBo ...

  5. docker-compose安装与部署项目

    安装: 1.curl安装慢的问题 解决:改用pip安装,需要先安装pip相关,参照: https://www.cnblogs.com/YatHo/p/7815400.html 2.pip安装依赖库re ...

  6. js字符串方法、数组方法整理

    push 向数组末尾添加一项 返回值为数组的长度: pop 删除数组最后一项: unshift 向数组开头增加一项: shift 删除数组第一项: splice 删除数组中的值:1 splice(n, ...

  7. 题解——洛谷P2613 【模板】有理数取余(扩展欧几里得算法+逆元)

    题面 题目描述 给出一个有理数 c=\frac{a}{b}  ​ ,求  c mod19260817  的值. 输入输出格式 输入格式: 一共两行. 第一行,一个整数 \( a \) .第二行,一个整 ...

  8. Dockerize a .NET Core application

    Dockerize a .NET Core application Introduction This example demonstrates how to dockerize an ASP.NET ...

  9. Kubernetes相关概念

    This page explains how Kubernetes objects are represented in the Kubernetes API, and how you can exp ...

  10. NPOI导入excel文件为DataTable,使用SqlBulkCopy添加到数据库表

    public DataTable ExcelToDataTable(Stream stream, string fileName) { DataTable data = new DataTable() ...