126

最接近原生APP体验的高性能前端框架——MUI - 听醒木一声收

 6 years ago
source link: http://www.cnblogs.com/lihaohai/p/7634094.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

  前  言

MUI有三大特点:

追求性能体验,是我们开始启动MUI项目的首要目标,轻量必然是重要特征;

MUI不依赖任何第三方JS库,压缩后的JS和CSS文件仅有100+K和60+K

鉴于之前的很多前端框架(特别是响应式布局的框架),UI控件看起来太像网页,没有原生感觉,因此追求原生UI感觉也是我们的重要目标

MUI以iOS平台UI为基础,补充部分Android平台特有的UI控件

下拉刷新,侧滑导航,滑动触发操作菜单

  1、新手指南

1.1  快速体验

1. 下载Hello mui App

点击下载 已打包好的Hello mui 手机app,直接在手机上体验mui的控件UI及能力展示;

2. 创建Hello mui工程

可从https://www.dcloud.io下载Hbuilder,选择新建“移动APP”,并选择“Hello MUI”工程模板,创建工程;然后通过数据线将手机连接上电脑,点击运行,就可以在手机上体验MUI的各项能力。

1.2快速构建页面

1. 新建含mui的HTML文件

在Hbuilder中,新建HTML文件,选择”含mui的HTML“模板,可以快速生成mui页面模板,该模板默认处理了mui的js、css资源引用。

2.输入mheader

顶部标题栏是每个页面都必需的内容,在Hbuilder中输入mheader,可以快速生成顶部导航栏。

3.输入mbody

除顶部导航、底部选项卡两个控件之外,其它控件都建议放在.mui-content控件内,在Hbuilder中输入mbody,可快速生成包含.mui-content的代码块。

4.完整代码块请参考

  2、 UI组件

  以iOS 7为基础,补充部分Android特有控件

  下面介绍常用的组件

2.1折叠面板

  折叠面板从二级列表中演化而来,dom结构和二级列表类似,如下:

  <ul class="mui-table-view"> 
        <li class="mui-table-view-cell mui-collapse">
            <a class="mui-navigate-right" href="#">面板1</a>
            <div class="mui-collapse-content">
                <p>面板1子内容</p>
            </div>
        </li>
    </ul>

   可以在折叠面板中放置任何内容;折叠面板默认收缩,若希望某个面板默认展开,只需要在包含.mui-collapse类的li节点上,增加.mui-active类即可;mui官网中的方法说明,使用的就是折叠面板控件。

2.2图片轮播

  图片轮播继承自slide插件,因此其DOM结构、事件均和slide插件相同;

  DOM结构

  默认不支持循环播放,DOM结构如下:

  <div class="mui-slider">
    <div class="mui-slider-group">
      <div class="mui-slider-item"><a href="#"><img src="1.jpg" /></a></div>
      <div class="mui-slider-item"><a href="#"><img src="2.jpg" /></a></div>
      <div class="mui-slider-item"><a href="#"><img src="3.jpg" /></a></div>
      <div class="mui-slider-item"><a href="#"><img src="4.jpg" /></a></div>
    </div>
  </div>

  假设当前图片轮播中有1、2、3、4四张图片,从第1张图片起,依次向左滑动切换图片,当切换到第4张图片时,继续向左滑动,接下来会有两种效果:

  • 支持循环:左滑,直接切换到第1张图片;
  • 不支持循环:左滑,无反应,继续显示第4张图片,用户若要显示第1张图片,必须连续向右滑动切换到第1张图片;

  当显示第1张图片时,继续右滑是否显示第4张图片,是同样问题;这个问题的实现需要通过.mui-slider-loop类及DOM节点来控制;

  若要支持循环,则需要在.mui-slider-group节点上增加.mui-slider-loop类,同时需要重复增加2张图片,图片顺序变为:4、1、2、3、4、1,代码示例如下:

<div class="mui-slider">
  <div class="mui-slider-group mui-slider-loop">
    <!--支持循环,需要重复图片节点-->
    <div class="mui-slider-item mui-slider-item-duplicate"><a href="#"><img src="4.jpg" /></a></div>
    <div class="mui-slider-item"><a href="#"><img src="1.jpg" /></a></div>
    <div class="mui-slider-item"><a href="#"><img src="2.jpg" /></a></div>
    <div class="mui-slider-item"><a href="#"><img src="3.jpg" /></a></div>
    <div class="mui-slider-item"><a href="#"><img src="4.jpg" /></a></div>
    <!--支持循环,需要重复图片节点-->
    <div class="mui-slider-item mui-slider-item-duplicate"><a href="#"><img src="1.jpg" /></a></div>
  </div>
</div>

  JS Method

  mui框架内置了图片轮播插件,通过该插件封装的JS API,用户可以设定是否自动轮播及轮播周期,如下为代码示例:

  //获得slider插件对象
  var gallery = mui('.mui-slider');
  gallery.slider({
    interval:5000//自动轮播周期,若为0则不自动播放,默认为0;
  });

  因此若希望图片轮播不要自动播放,而是用户手动滑动才切换,只需要通过如上方法,将interval参数设为0即可。

  若要跳转到第x张图片,则可以使用图片轮播插件的gotoItem方法,例如:

  //获得slider插件对象
  var gallery = mui('.mui-slider');
  gallery.slider().gotoItem(index);//跳转到第index张图片,index从0开始;

  注意:mui框架会默认初始化当前页面的图片轮播组件;若轮播组件内容为js动态生成时(比如通过ajax动态获取的营销信息),则需要在动态生成完整DOM (包含mui-slider下所有DOM结构) 后,手动调用图片轮播的初始化方法;代码如下:

  //获得slider插件对象
  var gallery = mui('.mui-slider');
  gallery.slider({
    interval:5000//自动轮播周期,若为0则不自动播放,默认为0;
  });

2.3栅格

栅格系统简介:

MUI 提供了非常简单实用的12列响应式栅格系统。使用时只需在外围容器上添加.mui-row,在列上添加 .mui-col-[sm|xs]-[1-12],即可栅格参数:

尺寸超小屏幕(<400px)(Extrasmall)小屏幕(≥400px) Small
类前缀 .mui-col-xs-[1-12] .mui-col-sm-[1-12]
列(column)数 12
可嵌套

左侧:通过定义.mui-col-sm-6类在大屏(≥400px)设备上会展现为并排的两列,而.mui-col-xs-12在小屏(<400px)设备上会覆盖之前定义的类展现为水平排列

<div class="mui-content">
    <div class="mui-row">
        <div class="mui-col-sm-6 mui-col-xs-12">
            <li class="mui-table-view-cell">
                <a class="mui-navigate-right">
                    Item 1    
                </a>
            </li>
        </div>
        <div class="mui-col-sm-6 mui-col-xs-12">
            <li class="mui-table-view-cell">
                <a class="mui-navigate-right">
                    Item 1
                </a>
            </li>
        </div>
    </div>
</div>

实例:多余的列将会另起一行排列

左侧:如果在一个.mui-row内包含的列(column)大于12个,包含多余列(column)的元素将作为一个整体单元被另起一行排列。

右侧:如果不足12个列将不会撑满整个.mui-row容器

<div class="mui-content">
    <div class="mui-row">
        <div class="mui-col-sm-8">
            <li class="mui-table-view-cell">
                <a class="mui-navigate-right">
                    Item 1    
                </a>
            </li>
        </div>
        <div class="mui-col-sm-6">
            <li class="mui-table-view-cell">
                <a class="mui-navigate-right">
                    Item 1
                </a>
            </li>
        </div>
    </div>
</div>

实例:通过为设置padding 属性,从而创建列与列之间的间隔

两列之间白色区域为左侧列的padding

<div class="mui-content">
    <div class="mui-row">
        <div class="mui-col-sm-6" style="padding-right: 20px;">
            <li class="mui-table-view-cell">
                <a class="mui-navigate-right">
                    Item 1    
                </a>
            </li>
        </div>
        <div class="mui-col-sm-6">
            <li class="mui-table-view-cell">
                <a class="mui-navigate-right">
                    Item 1
                </a>
            </li>
        </div>
    </div>
</div>

3 下拉刷新功能

  为实现下拉刷新功能,大多数 H5 框架都是通过 DIV 模拟下拉回弹动画,在低端 android 手机上,DIV 动画经常出现卡顿现象(特别是图文列表的情况); mui 通过使用原生 webview 下拉刷新解决这个 DIV 动画的卡顿问题,并且拖动效果更加流畅;

  这里提供两种模式的下拉刷新,以适用不同场景:

3.1单webview模式

  效果展示:

  动画原理:

  下拉刷新时,触发的是原生下拉刷新控件,而整个webview位置不会发生变化,所以不会在拖动过程中发生DOM重绘,当控件拖动到一定位置触发动态加载数据以及刷新操作。此模式下拉刷新,相比双webview 模式,不创建额外 webview,性能更优。

  使用方法:

  mui 初始化时设置pullRefresh各项参数,与双 webview 模式的子页面设置是一样的。

  1、DOM结构无特殊要求,只需要指定一个下拉刷新容器标识即可
  
mui.init({
  pullRefresh : {
    container:"#refreshContainer",//下拉刷新容器标识,querySelector能定位的css选择器均可,比如:id、.class等
    down : {
      style:'circle',//必选,下拉刷新样式,目前支持原生5+ ‘circle’ 样式
      color:'#2BD009', //可选,默认“#2BD009” 下拉刷新控件颜色
      height:'50px',//可选,默认50px.下拉刷新控件的高度,
      range:'100px', //可选 默认100px,控件可下拉拖拽的范围
      offset:'0px', //可选 默认0px,下拉刷新控件的起始位置
      auto: true,//可选,默认false.首次加载自动上拉刷新一次
      callback :pullfresh-function //必选,刷新函数,根据具体业务来编写,比如通过ajax从服务器获取新数据;
    }
  }
});

  模式说明:

  1、相比双webview,不创建额外子webview性能消耗更少

  2、下拉拖动过程中不会发生重绘,性能消耗更少

  目前仅仅支持circle样式及其样式的自定义

3.1双webview模式

  效果展示:

  动画原理:

  使用双 webview 模式的下拉刷新,创建一个子 webview 添加列表;拖动时,拖动的是一个完整的 webview,避免了类似 DIV 拖动流畅度不好的问题,回弹动画使用原生动画;在 iOS 平台,H5 的动画已经比较流畅,故依然使用 H5 方案。两个平台实现虽有差异,但 mui 经过封装,可使用一套代码实现下拉刷新。

  使用方法:

  主页面内容比较简单,只需要创建子页面即可:

mui.init({
    subpages:[{
      url:pullrefresh-subpage-url,//下拉刷新内容页面地址
      id:pullrefresh-subpage-id,//内容页面标志
      styles:{
        top:subpage-top-position,//内容页面顶部位置,需根据实际页面布局计算,若使用标准mui导航,顶部默认为48px;
        .....//其它参数定义
      }
    }]
});

  iOS平台的下拉刷新,使用的是 mui 封装的区域滚动组件, 为保证两个平台的 DOM 结构一致,内容页面需统一按照如下 DOM 结构构建:

<!--下拉刷新容器-->
<div id="refreshContainer" class="mui-content mui-scroll-wrapper">
  <div class="mui-scroll">
    <!--数据列表-->
    <ul class="mui-table-view mui-table-view-chevron">
      
    </ul>
  </div>
</div>

  其次,通过 mui.init 方法中 pullRefresh 参数配置下拉刷新各项参数,如下:

mui.init({
  pullRefresh : {
    container:"#refreshContainer",//下拉刷新容器标识,querySelector能定位的css选择器均可,比如:id、.class等
    down : {
      height:50,//可选,默认50.触发下拉刷新拖动距离,
      auto: true,//可选,默认false.首次加载自动下拉刷新一次
      contentdown : "下拉可以刷新",//可选,在下拉可刷新状态时,下拉刷新控件上显示的标题内容
      contentover : "释放立即刷新",//可选,在释放可刷新状态时,下拉刷新控件上显示的标题内容
      contentrefresh : "正在刷新...",//可选,正在刷新状态时,下拉刷新控件上显示的标题内容
      callback :pullfresh-function //必选,刷新函数,根据具体业务来编写,比如通过ajax从服务器获取新数据;
    }
  }
});

  模式说明:

  优点:可自定义下拉刷新样式。

  缺点:性能消耗大,DOM结构需要重新配置。

  结尾

 MUI的定位。

MUI的定位是:最接近原生体验的移动App的UI框架

基于mui的定位,产生了mui的几个特点,轻、小、只涉及UI、只为移动App而生、界面风格原生化。
所以请大家注意,mui有所为有所不为:

  1. mui不是jq,不封装dom操作
    与ui无关的mui不做,你愿意用jq或zepto就自己用,并不冲突。
    但我们并不建议在移动App里引入jq或zepto这些框架,原因如下:

    • 为了性能,层层封装的框架,尤其是遍历循环dom时,影响效率,尤其在低端Android手机上,我们费死劲了才把性能以毫秒为单位一点点提升,搞这个的dom框架进来就让很多努力又付诸东流。
    • 原生JS挺简单,为何需要jq?
      jq的成功当时是因为ie6、7、8、9、10、chrome、ff这些浏览器不兼容,让开发者崩溃,而且pc上浏览器性能好,跨平台兼容也不影响性能。但jq根本就不是为手机设计的。
      手机上只有webkit浏览器(忽略wp,反正mui不支持wp),根本就不需要jq这种封装框架来操作dom。
      而且HBuilder提供了代码块来简化开发,敲dg、dq,直接生成document.getElementById("")、document.querySelectorAll(""),非常快捷方便,而且执行性能非常高,而且没有浏览器兼容问题。
      发现很多开发者只会jq,反正想继续在App里使用jq没有问题。但也建议大家多学学js本身。
      mui与vue、react、angular也不是一个层面的东西,可以在一个工程里混合使用。但在大多数ui控件上,应该直接使用mui的写法,因为mui的绘制是最朴素的HTML绘制,不是经过js操作的绘制,这种方案的效率比经过js绘制的效率要高很多。只有必须经过js操作才能渲染的控件,比如ajax联网后填充的list,此时使用vuew或react都可以。
  2. mui、HTML5+、5+Runtime的关系说明
    mui是一个前端框架,HTML5+是一套HTML5能力扩展规范,HTML5+ Runtime是实现HTML5+规范的强化浏览器引擎。
    有点类似于bootstrap、w3c和chrome os的关系。
    HTML5+规范隶属于http://www.html5plus.org,定义了HTML5规范中没有但开发者做App需要的扩展规范。
    DCloud的5+ Runtime完整的实现了HTML5+规范。同时5+ Runtime还实现了Native.js,一种通过js调用几十万原生API的技术。
    为了提升体验,mui势必会调用一些5+Rutime的增强能力,主要是plus.webview、plus.nativeobj和plus.nativeUI。
    但mui不是要替代HTML5Plus,以后也无计划替代把所有5+的api都包一层。
    mui是把一些常用的窗体操作封装了,但这种封装适应面也是有限的,遇到复杂窗体管理,还是要仔细了解plus的api。
    所以,

    • 有人抱怨mui的文档不全,其实是缺本文,本文终于说清楚mui做什么不做什么了。详细的mui文档要去下方提示的mui官网查看。
    • 有人抱怨mui api不全,其实是没去看plus的api。知原理、知如何封装,方能融汇贯通。
    • 有人抱怨Hello mui示例代码里写的mui的方法,为何文档里没有,是因为有些方法是内部工程师简化开发中的封装,未考虑通用设计,还不足以开放为标准api,所以文档里没介绍。
  3. mui有插件体系
    为了简化开发者的多端发布开发,mui在核心库之外,补充了一些插件,这些插件不一定是ui相关,也有业务相关。
    在Hello mui示例里下方的示例模板,基本都属于插件。这些插件的使用需要加载mui标准库之外的js等资源。

mui是一个开源项目,请前往托管在github的mui官网查看详细介绍

这里是mui发布时的演讲视频:http://v.youku.com/v_show/id_XNzYyOTEyMjcy.html


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK