微信H5框架说明文档

1. 本框架是针对 微信移动端 及 业务需求 定制开发
2. 需要事先了解、最好是使用过 jQuery 和 Bootstrap
3. 对 HTML、CSS、Javascript 的综合开发能力有一定的要求
4. 底层使用 ECMAScript 5,主流移动浏览器都基本支持

浏览器兼容:

  推荐 iOS 6+, Android 4.4+, Wechat 6.0.2+

使用方式:

下载:xfh5-1.3.0.rar

  <link rel="stylesheet" href=".../xfh5-1.3.0/index.css">
  <script src=".../xfh5-1.3.0/index.js"></script>

修订历史:

2017年09月20日
  • 更新:"界面"部分的案例显示效果
  • 修正:"组件"部分的BUG
  • 更改:"计价组件"为"数量选择组件"
  • 新增:"杂项" window.toast()
2017年04月12日
  • 界面
    • 新增:图标、阶段、加载状态
    • 更新:按钮、面板
  • 组件
    • 更新:模态框
  • 模块
    • 新增:核心-设备检测、杂项-提示框、杂项-承诺对象、杂项-会话处理、杂项-前端测试机
    • 更新:表单-数据联动、地图




第三方库 Lib

1 fastclick.js

处理移动端点击事件 300ms 延时问题

2 bouncefix.js

滚动时将屏幕固定

3 layzr.js

延时加载图片、自适应加载图片
文档:https://github.com/callmecavs/layzr.js

4 doT.js

前端模板引擎
文档:http://olado.github.io/doT/





界面 UI

1 图标 Icon


plus
minus
search
star
star-o
user
check
times
power-off
setting
trash
home
clock
lock
volume
print
camera
image
map-marker
edit
times-circle-r
check-circle-r
times-circle
check-circle
arrow-right
gift
eye
cart
phone
globe
users
cloud
truck
caret-down
caret-up
lamp
cloud-download
cloud-upload
file-text
angle-up
angle-down
tablet
circle
location-arrow
shield
rocket
ellipsis-h
ios
android
wechat
dot-circle-o
hourglass
map-signs
map
cert
book
order
files
stack
coin-yen
compass
calendar
clipboard
info
circle-right

  <span class="icon-plus"></span>
  <span class="icon-minus"></span>
  <span class="icon-search"></span>
  <span class="icon-star"></span>
  ...

2 按钮 Button

<a> <span>

  <a class="btn" href="javascript:;">&lt;a&gt;</a>
  <span class="btn">&lt;span&gt;</span>
  <button class="btn" type="button">&lt;button&gt;</button>

  <button class="btn btn-sm">.btn-sm</button>
  <button class="btn btn-md">.btn-md</button>
  <button class="btn btn-lg">.btn-lg</button>

  <button class="btn">normal</button>
  <button class="btn btn-default">.btn-default</button>
  <button class="btn btn-success">.btn-success</button>
  <button class="btn btn-danger">.btn-danger</button>

  <button class="btn btn-flat">.btn-flat</button>
  <button class="btn btn-pill">.btn-pill</button>

  <div style="position:relative;height:80px;background-color:#f7f7f7;border:1px solid #c9c9c9">
    <button class="btn btn-default btn-corner">.btn-corner</button>
  </div>

  <button class="btn btn-block">.btn-block</button>


3 表单 Form

  <form>
    <fieldset>
      <label>
        <abbr title="abbr">*</abbr>label
      </label>
      <input type="text" class="form-control" placeholder=".form-control">
      <textarea rows="5" placeholder="textarea"></textarea>
    </fieldset>
  </form>


4 表格 Table

head-1 head-2 head-3 head-4 head-5
cell-1-1 cell-1-2 cell-1-3 cell-1-4 cell-1-5
cell-2-1 cell-2-2 cell-2-3 cell-2-4 cell-2-5
cell-3-1 cell-3-2 cell-3-3 cell-3-4 cell-3-5
  <div class="table-wrap">
    <table class="table">
      <thead>
        <tr> <th>head-1</th> <th>head-2</th> <th>head-3</th> <th>head-4</th> <th>head-5</th> </tr>
      </thead>
      <tbody>
        <tr> <td>cell-1-1</td> <td>cell-1-2</td> <td>cell-1-3</td> <td>cell-1-4</td> <td>cell-1-5</td> </tr>
        <tr> <td>cell-2-1</td> <td>cell-2-2</td> <td>cell-2-3</td> <td>cell-2-4</td> <td>cell-2-5</td> </tr>
        <tr> <td>cell-3-1</td> <td>cell-3-2</td> <td>cell-3-3</td> <td>cell-3-4</td> <td>cell-3-5</td> </tr>
      </tbody>
    </table>
  </div>


5 面板 Panel

panel-title

panel-body
...

panel-title

panel-body
...
  <div class="panel">
    <h4 class="panel-title">panel-title</h4>
    <div class="panel-body">
      panel-body <br>...
    </div>
  </div>
  <h4 class="panel-title">panel-title</h4>
  <div class="panel">
    <div class="panel-body">
      panel-body <br>...
    </div>
  </div>


6 列表 List

  • item-1
  • item-2
  • item-3
  •   <menu class="list">
        <li class="list-item">item-1</li>
        <li class="list-item">item-2</li>
        <li class="list-item">item-3</li>
      </menu>
    


    7 标记 Badge

    badge badge-sm badge-xs badge-muted badge-success badge-danger
      <span class="badge">badge</span>
      <span class="badge badge-sm">badge-sm</span>
      <span class="badge badge-xs">badge-xs</span>
    
      <span class="badge badge-muted">badge-muted</span>
      <span class="badge badge-success">badge-success</span>
      <span class="badge badge-danger">badge-danger</span>
    


    7 进度条 Progress

      <div class="progress">
        <div class="progress-bar" title="20%" style="width:20%"></div>
      </div>
    


    8 开关 Switch

      <label class="switch">
        <input type="checkbox" name="sfxtkzd" value="1">
        <span class="switch-handler"></span>
        <span class="switch-bg"></span>
      </label>
    


    9 阶段 Stage

    1. done
    2. done
    3. actived
    4. inactive
    1. 1
    2. 2
    3. 3
      <ol class="stagebar">
        <li class="done">done</li>
        <li class="done">done</li>
        <li class="active">actived</li>
        <li>inactive</li>
      </ol>
      <ol class="stage">
        <li class="first active">1</li>
        <li class="active">2</li>
        <li class="last">3</li>
      </ol>
    


    10 加载状态 Loading


      <div class="loading" style="height:80px;">
        页面内容
      </div>
    


    11 杂项 Misc





    组件 Component

    1 页面组件 Page

    Demo—page

    查看代码 | 查看效果
      <section class="page active" id="page-demo-com-page-1">
        <nav class="navbar">
          <h2>Demo: 页面组件</h2>
        </nav>
        <article class="scrollable">
          <div class="panel-body">
            <a href='#page-demo-com-page-2'>Go to Page 2 without data</a><br>
            <a href='#page-demo-com-page-2&data="test-data"'>Go to Page 2 with data</a>
          </div>
        </article>
      </section>
      <section class="page" id="page-demo-com-page-2">
        <nav class="navbar">
          <a class="navbar-btn navbar-back" href="javascript:window.history.back();"></a>
          <h2>Page 2</h2>
        </nav>
        <article class="scrollable">
          <div class="panel-body" id="content-demo-com-page-2"></div>
        </article>
      </section>
      <script>
        $("#page-demo-com-page-1").on("close", function (event) {
          if (!event.pageData) {
            window.alert("Please transfer data");
            return event.preventDefault();
          }
        });
        $("#page-demo-com-page-2").on("open", function (event) {
          $("#content-demo-com-page-2")[0].innerHTML
            = "pageData: " + event.pageData + "<br>"
            + "referrer: " + event.referrer + "<br>";
        });
      </script>
    

    1.1 HTML

    1.1.1 基本结构

    1. 需作为子元素放在 <body>
    2. id 必须以 page- 为前缀

      <body>
    
        <!-- 页面 1 -->
        <section class="page" id="page-id-1">
          <article class="scrollable">
            ...
          </article>
        </section>
    
        <!-- 页面 2 -->
        <section class="page" id="page-id-2">
          <article class="scrollable">
            ...
          </article>
        </section>
    
      </body>
    

    1.1.2 页面标题

    有两种方式,只能选择其中一种

      <!-- 直接修改 document.title (推荐) -->
      <section class="page" id="page-id-1" data-title="页面1">
        <article class="scrollable">
          ...
        </article>
      </section>
    
      <!-- 使用导航栏 -->
      <section class="page" id="page-id-1">
        <nav class="navbar">
          <a class="navbar-btn navbar-back" href="javascript:window.history.back();"></a>
          <h2>页面1</h2>
        </nav>
        <article class="scrollable">
          ...
        </article>
      </section>
    

    1.1.2 页面跳转

    使用 <a> 标签

      <!-- 跳转到页面2 -->
      <a href="#page-id-2">页面2</a>
    
      <!-- 跳转到页面2, 并传送数据
        1. 数据通过 目标页面 的 `open` 事件中的 `event.pageData` 获取
        2. 数据格式为 JSON 字符串
        3. href 属性需使用单引号
        4. 默认会清除 Url 中的数据, 使用 hold-data 可保留
      -->
      <a href='#page-id-2&data={"key":"value"}'>页面2</a>
      <!-- 保留 url中的数据 -->
      <a href='#page-id-2&hold-data={"key":"value"}'>页面2</a>
    
      <!-- 返回 -->
      <a href="javascript:window.history.back();">返回</a>
    

    1.2 Javascript

    历史记录只能由点击或程序产生,如果在地址栏输入将导致历史错乱
    pageID 可以是 selector | DOM | $(DOM)

    1.2.1 页面跳转

      1. $.ui.page.open(pageID, pageData);    // 显示页面同时记录 url 历史
      2. $.ui.page.replace(pageID, pageData); // 显示页面并覆盖当前 url 历史
    

    1.2.1 页面事件

      $(pageID).on("open", function (event) {
        event.pageData;          // 页面数据
        event.referrer;          // 上文页面ID
        event.preventDefault();  // 阻止跳转至本页面
      });
      $(pageID).on("close", function (event) {
        event.pageData;          // 页面数据
        event.referrer;          // 下文页面ID
        event.preventDefault();  // 阻止跳转至本页面
      });
    



    2 表单组件 Form

    Demo—form

    查看代码 | 查看效果
      <form name="form-demo-com-form" novalidate>
        <menu class="list list-form">
          <li class="list-item input empty">
            <span class="placeholder">请输入</span>
            <label class="label">文本框</label>
            <input class="form-control" type="text" name="inputName" placeholder="请输入" required data-label="文本">
          </li>
          <a class="list-item select empty" href="#page-demo-com-form-options">
            <span class="placeholder">请选择</span>
            <label class="label">选择框</label>
            <select class="form-control" name="selectName" placeholder="请选择" required data-label="选择框">
              <option value selected></option>
              <option></option>
            </select>
          </a>
          <li class="list-item radio active">
            <label class="label">单选框</label>
            <input class="hide" type="radio" name="radioName" value="value" checked>
          </li>
          <li class="list-item radio">
            <label class="label">单选框</label>
            <input class="hide" type="radio" name="radioName" value="value2">
          </li>
          <li class="list-item checkbox active">
            <label class="label">复选框</label>
            <input class="hide" type="checkbox" name="checkboxName" value="value" checked>
          </li>
        </menu>
      </form>
    

    2.1 HTML

    2.1.1 基本结构

      <form name="formName" novalidate>
        <menu class="list list-form">
          <!-- 表单字段 -->
          <li class="list-item">...</li>
          ...
        </menu>
      </form>
    

    2.1.2 表单字段

    1.设置 .list-item 的类型和状态:
        1.类型:.input, .select, .option, .radio, .checkbox
        2.状态:.empty(空), .hide(隐藏), .active(激活)
        3.样式: .radio-front, .checkbox-front
    2.阻止在 .list-item 内点击触发组件功能:
        1.添加 data-stop-form 属性

      <!-- 文本框 -->
      <li class="list-item input empty">
        <span class="placeholder">请输入字段1</span>
        <label class="label">字段1</label>
        <input class="form-control" type="text" name="inputName" required data-label="字段1">
      </li>
    
      <!-- 选择框 -->
      <li class="list-item select empty">
        <span class="placeholder">请选择字段2</span>
        <label class="label">字段2</label>
        <select class="form-control" name="selectName" required data-label="字段2">
          <option value selected></option>
          <option></option>
        </select>
      </li>
    
      <!-- 单选框 -->
      <li class="list-item radio active">
        <h4>字段3</h4>
        <p><small>说明</small></p>
        <input class="hide" type="radio" name="radioName" value="value" checked>
      </li>
    
      <!-- 复选框 -->
      <li class="list-item checkbox active">
        <h4>字段4</h4>
        <p><small>说明</small></p>
        <input class="hide" type="checkbox" name="checkboxName" value="value" checked>
      </li>
    

    2.1.3 选择框的选项列表

    data-form: 对应表单的 name 属性
    data-select: 对应选择框的 name 属性
    data-value: 对应选择框的值
    data-text: 对应选择框的文本

      <menu class="list list-form">
        <li class="list-item option" data-form="formName" data-select="selectName" data-value="value" data-text="label">
          选项1
        </li>
      </menu>
    

    2.1 Javascript

      1.$.ui.form.fill(form, data);               // 填充表单
      2.$.ui.form.reset(form);                    // 重置表单
      3.$.ui.form.showItems(form, fieldName...);  // 显示字段
      4.$.ui.form.hideItems(form, fieldName...);  // 隐藏字段
    



    3 模态框组件 Modal

    Demo—modal

    查看代码 | 查看效果
      <!-- 页面 -->
      <section class="page active" id="page-demo-com-modal">
        <article>
          <button class="btn btn-default btn-lg btn-block"
                  data-modal="#modal-demo-com-modal-modal">模态框</button>
          <button class="btn btn-default btn-lg btn-block"
                  data-modal="#modal-demo-com-modal-actionsheet">上拉框</button>
        </article>
      </section>
      <!-- 模态框 -->
      <div class="modal fade" id="modal-demo-com-modal-modal"
           data-dismiss="#modal-demo-com-modal-modal">
        <div class="modal-dialog">
          <div class="modal-content">
            <div class="modal-header">
              <h4>Modal header</h4>
              <span class="close" data-dismiss="#modal-demo-com-modal-modal">&times;</span>
            </div>
            <div class="modal-body">Modal body</div>
            <div class="modal-footer">
              <button class="btn btn-default" type="button">OK</button>
              <button class="btn" type="button"
                      data-dismiss="#modal-demo-com-modal-modal">Cancel</button>
            </div>
          </div>
        </div>
      </div>
      <!-- 上拉框 -->
      <div class="modal fade actionsheet" id="modal-demo-com-modal-actionsheet"
           data-dismiss="#modal-demo-com-modal-actionsheet">
        <div class="modal-dialog">
          <div class="modal-content">
            <menu class="list">
              <li class="list-item" data-dismiss="#modal-demo-com-modal-actionsheet">item-1</li>
              <li class="list-item" data-dismiss="#modal-demo-com-modal-actionsheet">item-2</li>
              <li class="list-item" data-dismiss="#modal-demo-com-modal-actionsheet">item-3</li>
            </menu>
          </div>
        </div>
      </div>
    

    3.1 HTML

      <button data-modal="#modal-id">弹出</button>
      <div class="modal fade" id="modal-id">
        <div class="modal-dialog">
          <div class="modal-content">
            <div class="modal-header">
            </div>
            <div class="modal-body">
            </div>
            <div class="modal-footer">
              <button data-dismiss="#modal-id">关闭</button>
            </div>
          </div>
        </div>
      </div>
    

    3.2 Javascript

      1.$.ui.modal.open(modal_id);   // 打开模态框
      2.$.ui.modal.close(modal_id);  // 关闭模态框
      3.$(modal_id).on("open", function (event) {   // 模态框打开事件
          event.relatedTarget;  // 触发打开的按钮
        });
      4.$(modal_id).on("close", function (event) {  // 模态框关闭事件
          event.relatedTarget;  // 触发关闭的按钮
        });
    



    4.1 HTML

      <div class="carousel">
        <ol class="carousel-inner">
          <li class="item active">...</li>
          <li class="item">...</li>
          ...
        </ol>
        <ol class="carousel-indicators">
          <li class="active" data-index="0"></li>
          <li data-index="1"></li>
          ...
        </ol>
      </div>
    
      <!-- 垂直模式 -->
      <div class="carousel vertical">
        ...
      </div>
    
      <!-- 触发滑动事件的目标元素 -->
      <div class="carousel" data-target="body">
        <!-- 阻止滑动事件 -->
        <li class="item" data-stop-carousel>...</li>
        ...
      </div>
    

    4.2 Javascript

      1.$(carousel_id).trigger("reset");  // 重置为首页
      2.$(carousel_id).on("last");        // 末页事件
    



    5 标签页组件 Tabs

    Demo—tabs

    查看代码 | 查看效果
      <ul class="tab-nav">
        <li class="active" data-tab="#tab-1">1</li>
        <li data-tab="#tab-2">2</li>
      </ul>
      <div class="tab-content" style="margin-bottom:10px">
        <div class="tab-pane active" id="tab-1">&#12288;The first tab.</div>
        <div class="tab-pane" id="tab-2">&#12288;The second tab..</div>
      </div>
    

    5.1 HTML

      <ul class="tab-nav">
        <li class="active" data-tab="#tab-1">...</li>
        <li data-tab="#tab-2">...</li>
        ...
      </ul>
      <div class="tab-content">
        <div class="tab-pane active" id="tab-1">...</div>
        <div class="tab-pane" id="tab-2">...</div>
        ...
      </div>
    



    6 数量选择组件 Number

    Demo—number

    查看代码 | 查看效果
      <menu class="list">
        <li class="list-item">
          <label class="label">数量</label>
          <div class="number-box pull-right" style="margin-top:5px">
            <button type="button" dir="-">-</button>
            <input type="text" name="name" min="1" value="1"
                   data-target="#number-target-id" data-price="8" data-free="1">
            <button type="button" dir="+">+</button>
          </div>
        </li>
      </menu>
    

    6.1 HTML

      <div class="number-box">
        <button type="button" dir="-">-</button>
        <input type="text" name="name" min="1" value="1">
        <button type="button" dir="+">+</button>
      </div>
    


    7 滑动导航组件 Offcanvas

    Demo—offcanvas

    查看代码 | 查看效果
      <div class="offcanvas-wrapper" style="height:100%">
        <div class="offcanvas-container" style="height:100%">
          <section class="offcanvas">
            <article class="offcanvas-panel scrollable">
              <div class="offcanvas-inner">
                &#12288;offcanvas-inner
              </div>
            </article>
          </section>
          &#12288;<button class="btn" type="button" data-open-offcanvas>
            offcanvas
          </button>
        </div>
      </div>
    

    7.1 HTML

      <div class="offcanvas-wrapper">
        <div class="offcanvas-container" style="height:80px">
          <section class="offcanvas">
            <article class="offcanvas-panel scrollable">
              <div class="offcanvas-inner">
                offcanvas-inner
              </div>
            </article>
          </section>
          <button class="btn" type="button" data-open-offcanvas>
            offcanvas
          </button>
        </div>
      </div>
    





    模块 Module

    1 核心模块 Core

    底层核心模块,参考 jQuery API 实现其中的一些功能

    1.1 命名空间 $

    1.1.1 选择器/包装器

      1. $(selector);                       // 包装所查询的元素集合
    

    1.1.2 核心方法

      1. $.isArray(data);                   // 判断数据是否数组类型
      2. $.inArray(data, array);            // 判断数据是否在数组中
      3. $.each(array, handler);            // 遍历数组
    

    1.2 原型方法 $.fn

      1. $.fn.eq(index);                    // 选择元素
      2. $.fn.add(array);                   // 添加元素
      4. $.fn.hasClass(className);          // 判断是否含有某个类名
      5. $.fn.addClass(className);          // 添加类名
      6. $.fn.removeClass(className);       // 删除类名
      7. $.fn.toggleClass(className);       // 切换类名
      8. $.fn.find(selector);               // 查询后代元素
      9. $.fn.closest(selector);            // 查询最近的祖先元素
    

    1.3 事件封装 Event

      1. $.Event(type, [props], [detail]);         // 创建 Event 对象
      2. $.fn.on(eventName, [delegate], handler);  // 绑定事件
      3. $.fn.one(eventName, handler);             // 绑定一次性事件
      4. $.fn.trigger(eventName, [data]);          // 触发事件
    

    1.4 异步通信 AJAX

    1.4.1 核心方法

      1. $.ajax(url, [settings]);           // AJAX 方法
      2. $.get(url, [data], [callback]);    // GET 方法
      3. $.post(url, [data], [callback]);   // POST 方法
      4. $.ajaxSetup(settings);             // 设置全局参数
    

    1.4.2 Promise 回调

      $.ajax(url, settings)
       .done(callback)                      // 处理成功
       .fail(callback)                      // 处理失败
       .always(callback);                   // 处理完毕 (成功或失败都执行)
    

    1.5 设备检测 Device

    静态布尔值

      $.device.Wechat
      $.device.WindowsPhone
      $.device.BlackBerry10
      $.device.Android
      $.device.iOS
      $.device.iOS4
      $.device.iOS9
      $.device.iOSWithBadTarget
    



    2 表单模块 Form

    2.1 表单验证 Validate

    覆盖 HTML5 原生 checkValidity 方法

    Demo—validate

    查看代码 | 查看效果
    <form name="form" novalidate>
      <input class="form-control" type="tel" name="mobile"
             placeholder="请填写手机"
             maxLength="11" required data-label="手机号码">
      <input class="form-control" type="password" name="password"
             placeholder="请填写密码"
             required data-label="密码">
      <input class="form-control" type="text" name="label"
             placeholder="不设置 data-label 的示例"
             minlength="3" required>
      <button class="btn btn-default btn-block" type="submit">提交</button>
    </form>
    <script>
      var form = document.forms("form");
      form.onsubmit = function (event) {
        event.preventDefault();
        if (!form["mobile"].checkValidity()) {
          return false;
        }
        if (!form.checkValidity()) {
          return false;
        }
        alert("提交成功");
      };
    </script>
    

    2.1.1 HTML API

      <!-- 需添加 novalidate 属性 -->
      <form novalidate>
    
        <!-- 支持的类型 -->
        <input type="tel">                        <!-- 手机 -->
        <input type="url">                        <!-- 网址 -->
        <input type="email">                      <!-- 邮箱 -->
        <input type="password">                   <!-- 密码 -->
    
        <!-- 支持的自定义类型 -->
        <input type="text" data-type="date">      <!-- 日期-->
        <input type="text" data-type="phone">     <!-- 电话-->
        <input type="text" data-type="zipcode">   <!-- 邮编-->
        <input type="text" data-type="noun">      <!-- 名词 (非纯数字/非纯特殊字符)-->
        <input type="text" data-type="chinese">   <!-- 中文名-->
        <input type="text" data-type="english">   <!-- 英文名-->
        <input type="text" data-type="resident">  <!-- 身份证号-->
        <input type="text" data-type="receipt">   <!-- 回执号-->
    
        <!-- 支持的属性 -->
        <input type="text" required>              <!-- 必填项 -->
        <input type="text" pattern="^\d{11}$">    <!-- 正则表达式 -->
        <input type="text" minLength="6">         <!-- 最小长度 -->
        <input type="text" maxLength="12">        <!-- 最大长度 -->
    
        <!-- 验证失败时的提示文本 (建议必填), 不填默认是 "内容" -->
        <input type="tel" data-label="手机号码">
    
      </form>
    

    2.1.2 Javascript API

      1. HTMLFormElement.checkValidity();   // 验证表单下的所有字段
      2. HTMLInputElement.checkValidity();  // 验证单个表单字段
    


    2.2 字段联动 Linkage

    根据映射关系显示或隐藏字段
    依赖 表单组件(涉及UI展示)
    注:这个 API 需要进一步优化

    Demo—linkage

    查看代码 | 查看效果
      <form class="list list-form" name="form-linkage" novalidate>
        <div class="list-item input">
          <label class="label">input</label>
          <input class="form-control" type="text" name="input" placeholder="输入123">
        </div>
        <div class="list-item checkbox hide">
          <label class="label">checkbox</label>
          <input class="hide" type="checkbox" name="checkbox" hidden>
        </div>
        <fieldset class="hide" name="fieldset">
          <a class="list-item select hide" href="#page-form-linkage-select-1">
            <label class="label">select_1</label>
            <select class="form-control" name="select_1" placeholder="请选择" hidden>
              <option value selected></option>
              <option></option>
            </select>
          </a>
          <a class="list-item select hide" href="#page-form-linkage-select-2">
            <label class="label">select_2</label>
            <select class="form-control" name="select_2" placeholder="请选择" hidden>
              <option value selected></option>
              <option></option>
            </select>
          </a>
        </fieldset>
      </form>
      <section class="page" id="page-form-linkage-select-1">...</section>
      <section class="page" id="page-form-linkage-select-2">...</section>
      <script>
        var form = document.forms["form-linkage"];
        var linkage_items = {
          "input": {
            "123": ["checkbox"]
          },
          "checkbox": {
            "on": ["fieldset"
          },,
        };
        var linkage_values = {
          "select_1": {
            "select_2": {
              "0": ["0", "1"],
              "1": ["1"]
            }
          }
        };
        $.util.form.linkage(form, { items: linkage_items, values: linkage_values }, function (event) {
          if ("input_1" === event.target.name) {
            window.alert("input_1 has changed");
          }
        });
      </script>
    

    2.2.1 HTML API

      <!-- 需要按照 [表单组件] 的规范来写 -->
      <form novalidate>
        <menu class="list list-form">
          <!-- 默认显示的字段 -->
          <div class="list-item">
            <input class="form-control" name="">
          </div>
          <!-- 默认隐藏的字段 -->
          <div class="list-item hide">                   <!-- 需添加 hide 类名 -->
            <input class="form-control" name="" hidden>  <!-- 需添加 hidden 属性 -->
          </div>
          <!-- 用 <fielset> 包含多个字段 -->
          <fieldset name="">
            <!-- 当集合显示/隐藏的时候会自动设置 hide 和 hidden -->
            <div class="list-item">...</div>
            ...
          </fieldset>
          <!-- 添加 data-wrap 表明显示/隐藏的时候不触发 hide 和 hidden 的变化 -->
          <fieldset name="" data-wrap>
            ...
          </fieldset>
          <!-- 默认隐藏的字段集合 -->
          <fieldset class="hide" name="">
            <!-- 内部字段也需要同时都设为隐藏字段 -->
            <div class="list-item hide">...</div>
            ...
          </fieldset>
        </menu>
      </form>
    

    2.2.2 Javascript API

      // 联动数据映射表格式
      var linkage = {
        // 字段->值->字段
        items: {
          "checkbox_name": {
            "on": ["(field|fieldset)_name"...],  // on 为浏览器默认 value
          }
          "(select|input)_name": {
            "value_1": ["(field|fieldset)_name"...]
          }
        },
        // 字段值->字段值
        values: {
          "(select|input)_1_name": {
            "select_2_name": {
              "select_1_value_1": ["select_2_value_1"...]
            }
          }
        }
      };
    
      /**
       * 表单数据联动
       * @todo 优化
       * @param  {Object} form           - 表单元素
       * @param  {Object} linkage.items  - 联动数据映射表: 值->字段
       * @param  {Object} linkage.values - 联动数据映射表: 值->值
       * @param  {Object} mixinHandler   - 监听表单 change 事件的处理函数
       * @return {Object}
       */
      $.util.form.linkage(form, linkage{items, values}, [mixinHandler]);
    
      /**
       * 设置选项列表
       * @param  {Object}  field  选择框元素
       * @param  {Array}   values 选项值范围
       * @param  {Boolean} isInit 是否初始化
       */
      $.util.form.linkage.setOptions(field, values, isInit);
    


    2.3 获取数据 GetData

    1. 遍历表单字段,以 name 属性的值 为 key,以字段的值为 value,生成 JSON 数据
      例:<input name="a[b][]" value="1"> -> { a: { b: [1] } }
    2. <select> 标签会以 name 属性的值加上 _label 后缀生成额外的 key
      例:<select name="a"><option value="1">text</option></select> -> { a: 1, a_label: "text"}
    3. 没有设置 name 属性,或设置了 hidden/data-ignore 属性 的字段不会被获取

    Demo—formdata

    查看代码 | 查看效果
      <form name="form-data" novalidate>
        <small>普通数据 name="normal"</small>
        <input class="form-control" type="text" name="normal" value="normal_value">
        <small>数组 name="array[]"</small>
        <input class="form-control" type="text" name="array[]" value="array_value_1">
        <small>数组 name="array[]"</small>
        <input class="form-control" type="text" name="array[]" value="array_value_2">
        <small>对象 name="object[key_1]"</small>
        <input class="form-control" type="text" name="object[key_1]" value="object_key_1_value">
        <small>对象 name="object[key_2]"</small>
        <input class="form-control" type="text" name="object[key_2]" value="object_key_2_value">
        <small>选择框 name="select"</small>
        <select class="form-control" type="text" name="select">
          <option value="select_value">select_text</option>
        </select>
        <small>忽略 name="ignore"</small>
        <input class="form-control" type="text" name="ignore" value="ignore_value" data-ignore>
        <small>附加字段 name="attached" (试下把值清空)</small>
        <input class="form-control" type="text" name="attached" value="attached_value"
               data-attach-field="attach" data-attach-value="attach_value" data-attach-text="attach_text">
        <button class="btn btn-default btn-block" type="submit">获取JSON</button>
      </form>
      <script>
        var form = document.forms["form-data"];
        form.onsubmit = function (event) {
          event.preventDefault();
          var data = $.util.form.getData(form);
          window.alert("<pre>" + JSON.stringify(data, null, 2) + "</pre>");
        };
      </script>
    

    2.3.1 HTML API

      <!-- 数据类型 -->
      <input type="text" name="normal">              <!-- 普通数据 -->
      <input type="text" name="array[]">             <!-- 数组 -->
      <input type="text" name="object[key]">         <!-- 对象 -->
    
      <!-- 选项 -->
      <input type="text" name="ignore" data-ignore>  <!-- 忽略此字段 -->
    
      <!-- 附加字段 -->
      <!-- 当主字段有值时才生效 -->
      <input type="text" name="attach"
             attach-field="field_name"
             attach-value="field_value"
             attach-text="field_text">
    

    2.3.1 Javascript API

      $.util.form.getData(form);
    


    2.4 表单提交 Submit

    封装表单提交功能
    1. 阻止默认提交事件
    2. 显示页面加载效果
    3. 调用表单验证模块
    4. 支持 AJAX Promise 对象

    Demo—submit

    查看代码 | 查看效果
      <form name="form-submit" novalidate>
        <input class="form-control" type="text" name="key" placeholder="必填项" required>
        <button class="btn btn-default btn-block" type="submit" name="dosubmit">提交表单</button>
      </form>
      <script>
        var form = document.forms["form-submit"];
        $.util.form.submit(form, function (event) {
          return {
            // 模拟 Promise 对象
            always: function (unhold) {
              window.setTimeout(function () {
                window.alert("提交成功");
                unhold();
              }, 1500);
            }
          };
        });
      </script>
    

    2.4.1 HTML API

    必须为 <form> 添加 novalidate 属性
    必须有一个 name="dosubmit"<button> 按钮

      <form novalidate>
        <input type="text">
        <button type="submit" name="dosubmit"></button>
      </form>
    

    2.4.1 Javascript API

      $.util.form.submit(form, function (event, data, unhold) {
        event.holdon = true; // 保持加载状态
        window.setTimeout(function () {
          unhold();            // 解除加载状态
        }, 3000);
        return $.ajax();     // 在 AJAX 结束时才解除加载状态
      });
    



    3 地图模块 Map

    3.1 地理定位 Geolocation

      // 获取地理定位信息
      $.map.getGeolocation({
        type: String,  // 获取方式 [WX|BMap|(Browser)]
        success: function (geo) {
    
          geo = {
            address: {
              province: String,
              city: String
            },
            latitude:  Number,
            longitude: Number,
            point: {
              lat: Number,
              lng: Number
            }
          }
    
        },
        fail: function (geo) {},
        always: function (geo) {}
      };
    
      // 根据坐标获取地理信息
      $.map.getGeoByCoords({
        latitude: Number,
        longitude: Number,
        type: String,      // 定位类型 [GPS|baidu]
        success: function (geo) {},
        fail: function (geo) {},
        always: function (geo) {}
      });
    
      // 初始化百度地图 (加载 script)
      $.map.initBMap(callback);
    





    4 杂项 Misc

    4.1 提示框 Alert

    覆盖了原生方法

      1. window.alert(message, [title]);
      2. window.confirm(message, [yesCallback], [noCallback], [title]);
      3. window.toast(message, [delay]);
    

    4.2 工具方法 Util

      1. $.util.deparam(urlParam);                            // 地址参数反序列化
      2. $.util.img.layzr;                                    // Layzr 实例
      3. $.util.date.format(timestamp);                       // 格式化日期
      5. $.util.render(tmpl, json, [options]);                // 渲染模板
    

    4.3 承诺对象 Promise

      // 设置默认的 key
      $.deferred.keys = ["done", "fail", "always"].concat(["success", "unsuccess"]);
    
      // 示例
      var deferred = new $.deferred(keys);
      var doneCallback = function (data) { ... };
      var failCallback = function (exception) { ... };
      var alwaysCallback = function () { ... };
    
      deferred.promise.done(doneCallback).fail(failCallback).always(alwaysCallback);
    
      // 延迟处理
      window.setTimeout(function () {
        if (true) {
          deferred.resolve.done({ key: "value "});
        } else {
          deferred.resolve.fail({ code: 101 });
        }
        deferred.resolve.always();
      }, 1000);
    
      // 所有 deferred 都 resolve 了之后才执行 callback
      var promisses = [deferred, deferred2...];
      $.promise.all(promises).done(...).fail(...).always(...);
    

    4.4 会话处理 Session

      1. $.session.get(key);                                 // 获取会话数据
      2. $.session.set(key, value);                          // 设置会话数据
      3. $.session.assign(key, value);                       // 覆盖会话数据
      4. $.session.remove(key);                              // 删除会话数据
    

    4.5 前端测试机 Mock

    模拟 后台服务、微信 JSSDK,提供模拟数据

      /**
       * 初始化
       * @param {Object} config - 测试数据
       * @param {Object} config.urls  - 提交地址集合 { key: url }
       * @param {Object} config.datas - 假数据集合 { key: data }
       * @param {Object} config.forms - 表单数据
       * @param {Object} config.jssdk - 模拟微信 JSSDK 方法
       */
      $.mock.init(config, isFocus);