使用Framework7 1.6.5开发APP记录

Framework7介绍

(1)Framework7 是一个开源免费的框架。可以用来开发混合移动应用(原生和 HTML 混合)或者开发 iOS & Android 风格的 WEB APP。也可以用来作为原型开发工具,可以迅速创建一个应用的原型。
(2)使用时只需要一个基本的 HTML 布局,并且把 Framework7 的 CSS 和 JS 文件引入即可!Framework7 不会强制你写任何自定义的标签,也不会通过 JS 来生成任何额外的内容。你不需要通过 JS 或者 JSON 来写页面,只需要普通的 HTML 就可以。
(3)Framework7 有大量可以直接使用的 UI 组件和工具,比如导航栏、侧边栏、弹出层、标签页、虚拟列表、日期控件、手风琴等。大部分的组件你都完全不需要写任何 JS 代码。

一、页面结构

拿到原型图:


Framework7标签栏应用案例:http://examples.framework7.cn/tab-bar/

一开始看到原型图和F7里面的这个案例,果断就把案例直接下载来使用。交给后台开发时被告知“没达到开发要求”,原因:

标签栏应用案例结构:

<div class="views tabs toolbar-fixed">
  <!-- Tab 1 - View 1, active by default -->
  <div id="tab1" class="view tab active">
    ...
  </div>
  <!-- Tab 2 - View 2 -->
  <div id="tab2" class="view tab">
    ...
  </div>
  <!-- Tab 3 - View 3 -->
  <div id="tab3" class="view tab">
    ...
  </div>
  <!-- Tab 4 - View 4 -->
  <div id="tab4" class="view tab">
    ...
  </div>
  <!-- Tab bar with tab links -->
  <div class="toolbar tabbar">
    <div class="toolbar-inner">
      <a href="#tab1" class="tab-link active"><i class="icon demo-icon-1"></i></a>
      <a href="#tab2" class="tab-link"><i class="icon demo-icon-2"></i></a>
      <a href="#tab3" class="tab-link"><i class="icon demo-icon-3"></i></a>
      <a href="#tab4" class="tab-link"><i class="icon demo-icon-3"></i></a>
    </div>
  </div>
</div>

标签页是一个页面,不方便控制和后期维护。于是切分成四个页面,在点击底部导航栏时按需加载进来。

修改后的页面结构如下:
index.html

  <body>
    <!-- Views -->
    <div class="views">
      <div class="view view-main">
        <!-- 顶部导航栏 -->
        <div class="navbar">
            <div class="navbar-inner">
                <div class="center">借款侠</div>
                <div class="right">
                    <a href="javascript:void(0);" class="external icon-only" id="upcity">
                        <img src="/loanheroic/images/icon/icon_positioning_@2x.png" alt="" class="icon icon-pos"><span class="city city-name"></span>
                    </a>
                </div>
            </div>
        </div>
        <div class="pages navbar-through toolbar-through">
          <!-- 首页 -->
          <div data-page="index" class="page view-1">
            <div class="page-content">
                  ...
            </div>
          </div>
        </div>
        <!-- 底部导航 -->
        <div class="toolbar tabbar tabbar-labels">
          <div class="toolbar-inner">
            <a href="javascript:void(0);" id="goIndex" data-url="index.html" class="link active"> <i class="icon tabbar-demo-icon-1"></i><span class="tabbar-label">首页</span></a>
            <a href="javascript:void(0);" id="goProductList" data-url="productList.html" class="link"><i class="icon tabbar-demo-icon-2"></i><span class="tabbar-label">借款</span></a>
            <a href="javascript:void(0);" id="goFavorit" data-url="favorites.html" class="link"> <i class="icon tabbar-demo-icon-3"></i><span class="tabbar-label">收藏</span></a>
            <a href="javascript:void(0);" id="goMine" data-url="mine.html" class="link"> <i class="icon tabbar-demo-icon-4"></i><span class="tabbar-label">我的</span></a>
          </div>
        </div>
      </div>
    </div>
  </body>

其它页面 xxx.html

<div class="pages">
  <div data-page="pageName" class="page navbar-fixed toolbar-fixed">
    <!-- 导航 -->
    <div class="navbar">
      <div class="navbar-inner">
        <div class="left"><a href="javascript:void(0);" class="external back-mine back-android"> <i class="icon icon-back"></i></a></div>
        <div class="center sliding">页面名称</div>
      </div>
    </div> 
    <!-- 内容 -->
    <div class="page-content">
        ...
    </div>
  </div>
</div>

默认情况下 Framework7 会使用 Ajax 加载所有的页面,当我们触发切换页面的事件时,Framework7会通过Ajax获取 xxx.html,解析它的内容,然后把它插入到DOM中,并且做一个动画切换到这个新页面。

因为Framework7有一个非常聪明的解析器,所以在内部页面中我们不需要完整的HTML结构(head,body,views,pages等)。Framework7 解析器会尝试在ajax加载的页面中寻找 <div class="page">

二、Template7 模板

Template7是framework7的内置模板引擎,无需包含额外的 JS 文件。

1. 自动编译模板

<script type="text/template7" id="myTemplate">
    <p>Hello, my name is {{name}} and i am {{age}} years old</p>
</script>  

type="text/template7" 指定了这个script的内容会被 Framework7 当做一个 Template7 模板自动编译

id="myTemplate" 是模板的id,后面可以通过这个id来找到这个模板

你需要在 初始化应用 的时候传入一个参数来启用自动编译模板功能:

var myApp = new Framework7({
    precompileTemplates: true,  // 启用模板
});

渲染:

var Html = Template7.templates.broadTemplate(data);
$$('div').html(Html);

2. 模板页面

Framework7 可以使用 Template7 用特定的上下文来渲染ajax页面或者动态页面,并且提供了很多不同的方法来实现.

首先,我们需要在 应用初始化 的时候传入一个参数来开启这个功能:

var myApp = new Framework7({
    template7Pages: true, // 模板页面
});

xxx.html

<div class="page" data-page="xxx">
    <div class="page-content">
        <p>Hello, my name is {{name}} and i am {{age}} years old {{position}} at {{company}}</p>
    </div>
</div>

模板页面数据:

var myApp = new Framework7({
    template7Pages: true, 
    template7Data: {
        'url:xxx.html': {
            name: 'John Doe',
            age: 38,
            company: 'Apple',
            position: 'Developer'
        },
    }
});

ajax传入数据:

ajax_json({
    url: url,
    success: function(data){
        mainView.router.load({
            url: "xxx.html",
            context: data.result
        })  
    }
});

使用情况:

  1. 首页模块使用<script>自动编译模板
  2. 其它页面使用模板页面

遇到的问题:
在模板页面有多个数据源的时候,不能结合自动编译模板同时使用(表达式混淆。除非把<script>模板放在首页)。

解决:
列表模块使用F7自带的虚拟列表组件进行动态渲染。

3. 虚拟列表

虚拟列表可以用来渲染有大量数据的列表,并且不有有任何的性能问题。并且,它和所有的Framework7组件都是兼容的,包括搜索栏、无限滚动、下拉刷新、滑动删除和可排序列表。

在页面中放一个空的虚拟列表容器

<div class="list-block virtual-list">

</div>

使用Template7模板渲染:

var myList = myApp.virtualList('.list-block.virtual-list', {
    items: data,
    template: '<li class="item-content">' +
                  '<div class="item-media"><img src="{{picture}}"></div>' +
                  '<div class="item-inner">' +
                      '<div class="item-title">{{title}}</div>' +
                  '</div>' +
               '</li>'
});            

三、页面切换

Framework7主要有两个切换页面的方法:

  1. mainView.router.load(options) - 把一个页面加载到当前视图

  2. mainView.router.back(options) - 这个方法会触发一个反向的动画并回到上一个页面,也就是浏览历史上的回退

主要使用到的参数:
url:需要加载的页面的URL
context:渲染Template7 模板时需要的上下文(模板数据)。
query:页面路由传递的参数
force:只对 back 方法有效。如果设置为 true,那么会忽略浏览历史中的上一个页面,而是直接加载指定的页面。
reload:如果设置为 true,那么不会当做新页面加载,而是直接替换当前视图的当前页面。并且在视图浏览历史中替换最后一条历史。

遇到的问题:
在一个页面更改了数据后,使用back回退到上个页面,页面数据没有刷新

解决:

mainView.router.back({
    url: url,   // 指定回退页面的url
    context: data, // 传递模板数据给指定加载的页面
    force: true  // 设置为true,直接加载指定的页面
});

四、滚动加载

在产品页面有一个“下拉加载数据”的需求,F7有一个“无限滚动”组件,即列表滚动到底部时触发加载函数。最初使用的是这个组件,使用方法:

给div.page-content加上infinite-scroll类

<div class="page">
    <div class="page-content infinite-scroll" data-distance="100">
        ... 
    </div>
</div>

初始化“无限滚动”组件

$$('.infinite-scroll').on('infinite', function () {
    // code...
}); 

每一次滚动到底部都会执行回调函数里的代码

遇到的问题:

  1. 一开始产品页面的div.page-content是嵌套在模板里面,而在产品页面初始化时就已经初始化“无限滚动”组件,所以后来动态生成的div.page-content不能触发“无限滚动”。

解决:优化DOM结构,div.page-content一开始就要在页面中存在。

  1. tab页切换后,滚动触发加载数据时加载到了第一个tab页的列表里。

解决:所有tab栏分类公用一个虚拟列表,切换tab页面时清空当前列表,重新加载指定数据。

  1. 一开始没有给虚拟列表高度,它默认是每个条目高度(44px)*条目数量,实际上条目高度大于默认高度,导致ul高度不够影响滚动加载。

解决:给一个固定高度。

  1. 有个业务需求是当前类别的数据加载完后,继续下拉添加进一张“当前数据已加载完”的图片,再拉可以在当前列表继续加载其它类别的数据,该图片仍然存在列表中以示分隔。但是虚拟列表的模板是初始化时固定的(只能添加相同模板的数据),列表更新时图片会被清掉。

解决:在虚拟列表下新增一个DOM容器,用来加载图片。图片的容器下新增一个虚拟列表容器,装其它类别的数据。

  1. 无线滚动触发条件是列表滚动到底部,没有实现“拖拽加载”的效果。

解决:使用iScroll5插件。

五、其它

1. Rem适配问题

rem是相对于根元素<html>,这样就意味着,我们只需要在根元素确定一个px字号,则可以来算出元素的宽高。

例如:

html{
    font-size:20px;
}
div {
    width: 6rem;
    height: 3rem;
}

div的宽 = 6*20 = 120px

使用:

  1. 媒体查询适配根元素字号
html {
    font-size : 20px;
}
@media only screen and (min-width: 401px){
    html {
        font-size: 25px !important;
    }
}
@media only screen and (min-width: 428px){
    html {
        font-size: 26.75px !important;
    }
}
@media only screen and (min-width: 481px){
    html {
        font-size: 30px !important; 
    }
}
@media only screen and (min-width: 569px){
    html {
        font-size: 35px !important; 
    }
}
@media only screen and (min-width: 641px){
    html {
        font-size: 40px !important; 
    }
}
  1. JS动态计算
function tryResize(){
     var docEl=document.documentElement;  
     var clientHeight = docEl.clientWidth;
     if(!clientHeight)
     {
         return
     }
     docEl.style.fontSize=20*(clientHeight/375)+"px"  
 }
 tryResize();
 window.onresize=tryResize;

计算规则:
例如设计稿是375的尺寸,375页面的font-size是20px,那么320的页面呢?320/375 = 0.8533 320是375的0.8533倍,所以320的font-size等于20*0.8533 = 17.0667。

遇到的问题:

  1. 部分安卓机型对rem支持不是很好,出现布局错位问题。
    解决:根据实际情况来考虑元素是运用rem单位还是百分比或者是flex弹性布局。

  2. 文本的字号使用rem会出现小屏字体太小,大屏字体太大的情况
    解决:文本字号使用px单位,结合媒体查询

2. 使用require.Js管理js文件

通常我们js写在一个或多个文件里,用<script>标签引入页面,但js文件过多会出现以下丑陋场景:

<script type="text/javascript" src="a.js"></script>
<script type="text/javascript" src="b.js"></script>
<script type="text/javascript" src="c.js"></script>
<script type="text/javascript" src="d.js"></script>
<script type="text/javascript" src="e.js"></script>
<script type="text/javascript" src="f.js"></script>
<script type="text/javascript" src="g.js"></script>
<script type="text/javascript" src="h.js"></script>
<script type="text/javascript" src="i.js"></script>

并且js的加载会阻塞页面渲染,而且由于js文件之间存在依赖关系,必须严格保证加载顺序,依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。

require.Js就是为了解决以上问题。

使用:

  1. 去官网下载最新版本,引入页面
<script src="js/require.js" defer async="true"></script>  // async属性表明这个文件需要异步加载,避免网页失去响应。IE不支持这个属性,只支持defer,所以把defer也写上。
  1. 全局配置

创建一个main.js

require.config({
    paths : {       // 引用路径
        "jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery", "js/jquery"],
        "a" : "js/a"   
    }
})

然后在页面中使用下面的方式来使用requirejs:

<script src="js/require.js" data-main="js/main" defer async="true"></script>

data-main属性的作用是,指定网页程序的主模块。在上例中,就是js目录下面的main.js,这个文件会第一个被require.js加载。由于require.js默认的文件后缀名是js,所以可以把main.js简写成main。

  1. 基本API

require会定义三个变量:define,require,requirejs,其中require === requirejs,一般使用require更简短

define 从名字就可以看出这个api是用来定义一个模块
require 加载依赖模块,并执行加载完后的回调函数

例:

// a.js

define(function (){
    var add = function (x,y){
      return x+y;
    };
    return {
      add: add
    };
  });

如果这个模块还依赖其他模块,那么define()函数的第一个参数,必须是一个数组,指明该模块的依赖性。

define(['myLib'], function(myLib){
    function foo(){
      myLib.doSomething();
    }
    return {
      foo : foo
    };
  });

当require()函数加载上面这个模块的时候,就会先加载myLib.js文件。

加载方法如下:

// main.js

require(['a'], function (a){
  alert(a.add(1,1));
});
  1. 加载非规范的模块

理论上,require.js加载的模块,必须是按照AMD规范、用define()函数定义的模块。但是实际上,虽然已经有一部分流行的函数库(比如jQuery)符合AMD规范,更多的库并不符合。那么,require.js怎样加载非规范的模块呢?

这样的模块在用require()加载之前,要先用require.config()方法,定义它们的一些特征。

require.config()接受一个配置对象,这个对象除了有前面说过的paths属性之外,还有一个shim属性,专门用来配置不兼容的模块。具体来说,每个模块要定义(1)exports值(输出的变量名),表明这个模块外部调用时的名称;(2)deps数组,表明该模块的依赖性。

比如,jQuery的插件可以这样定义:

require.config({
    shim: {
        'jquery.scroll': {
          deps: ['jquery'],  // 依赖的模块
          exports: 'jQuery.fn.scroll'   // 输出的变量名
        }
      }
  });

遇到的问题:
使用百度的WebUploader上传组件时,报错找不到 WebUploader 变量。
原因: cdn版本较低
解决: 官网下载最新版

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,747评论 1 92
  • 因为本人家庭条件有限去过的地方少之又少,几乎没什么值得提起的,现在想想也许北京算是一个了。四岁时候和我妈妈去过...
    12月5号阅读 227评论 4 0
  • 偶有闲暇时光,躲避雾霾,远离喧闹,嘈杂的都市,徒步终南山里休闲,沿路向前,身边疾驰而过的车辆,风驰电掣。走着走着,...
    古城苍狼阅读 568评论 1 10
  • 做人要有诚信 再穷,不要欠钱玩消失。 再难,不要说话不算数。 再有事,把话说明白不要不接电话。 堂堂正正做人,明明...
    7b9ec122647c阅读 344评论 0 1