Framework7介紹
(1)Framework7 是一個開源免費(fèi)的框架∧欠ィ可以用來開發(fā)混合移動應(yīng)用(原生和 HTML 混合)或者開發(fā) iOS & Android 風(fēng)格的 WEB APP用狱。也可以用來作為原型開發(fā)工具彻亲,可以迅速創(chuàng)建一個應(yīng)用的原型封孙。
(2)使用時只需要一個基本的 HTML 布局欢伏,并且把 Framework7 的 CSS 和 JS 文件引入即可!Framework7 不會強(qiáng)制你寫任何自定義的標(biāo)簽闹获,也不會通過 JS 來生成任何額外的內(nèi)容期犬。你不需要通過 JS 或者 JSON 來寫頁面,只需要普通的 HTML 就可以避诽。
(3)Framework7 有大量可以直接使用的 UI 組件和工具龟虎,比如導(dǎo)航欄、側(cè)邊欄沙庐、彈出層鲤妥、標(biāo)簽頁、虛擬列表拱雏、日期控件棉安、手風(fēng)琴等。大部分的組件你都完全不需要寫任何 JS 代碼铸抑。
一贡耽、頁面結(jié)構(gòu)
拿到原型圖:
Framework7標(biāo)簽欄應(yīng)用案例:http://examples.framework7.cn/tab-bar/
一開始看到原型圖和F7里面的這個案例,果斷就把案例直接下載來使用鹊汛。交給后臺開發(fā)時被告知“沒達(dá)到開發(fā)要求”蒲赂,原因:
標(biāo)簽欄應(yīng)用案例結(jié)構(gòu):
<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>
標(biāo)簽頁是一個頁面,不方便控制和后期維護(hù)刁憋。于是切分成四個頁面滥嘴,在點(diǎn)擊底部導(dǎo)航欄時按需加載進(jìn)來。
修改后的頁面結(jié)構(gòu)如下:
index.html
<body>
<!-- Views -->
<div class="views">
<div class="view view-main">
<!-- 頂部導(dǎo)航欄 -->
<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>
<!-- 底部導(dǎo)航 -->
<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">
<!-- 導(dǎo)航 -->
<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>
<!-- 內(nèi)容 -->
<div class="page-content">
...
</div>
</div>
</div>
默認(rèn)情況下 Framework7 會使用 Ajax 加載所有的頁面,當(dāng)我們觸發(fā)切換頁面的事件時至耻,F(xiàn)ramework7會通過Ajax獲取 xxx.html若皱,解析它的內(nèi)容,然后把它插入到DOM中尘颓,并且做一個動畫切換到這個新頁面走触。
因?yàn)镕ramework7有一個非常聰明的解析器,所以在內(nèi)部頁面中我們不需要完整的HTML結(jié)構(gòu)(head,body,views,pages等)疤苹。Framework7 解析器會嘗試在ajax加載的頁面中尋找 <div class="page">
二互广、Template7 模板
Template7是framework7的內(nèi)置模板引擎,無需包含額外的 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的內(nèi)容會被 Framework7 當(dāng)做一個 Template7 模板自動編譯
id="myTemplate" 是模板的id,后面可以通過這個id來找到這個模板
你需要在 初始化應(yīng)用 的時候傳入一個參數(shù)來啟用自動編譯模板功能:
var myApp = new Framework7({
precompileTemplates: true, // 啟用模板
});
渲染:
var Html = Template7.templates.broadTemplate(data);
$$('div').html(Html);
2. 模板頁面
Framework7 可以使用 Template7 用特定的上下文來渲染ajax頁面或者動態(tài)頁面迎瞧,并且提供了很多不同的方法來實(shí)現(xiàn).
首先夸溶,我們需要在 應(yīng)用初始化 的時候傳入一個參數(shù)來開啟這個功能:
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>
模板頁面數(shù)據(jù):
var myApp = new Framework7({
template7Pages: true,
template7Data: {
'url:xxx.html': {
name: 'John Doe',
age: 38,
company: 'Apple',
position: 'Developer'
},
}
});
ajax傳入數(shù)據(jù):
ajax_json({
url: url,
success: function(data){
mainView.router.load({
url: "xxx.html",
context: data.result
})
}
});
使用情況:
- 首頁模塊使用
<script>
自動編譯模板 - 其它頁面使用模板頁面
遇到的問題:
在模板頁面有多個數(shù)據(jù)源的時候,不能結(jié)合自動編譯模板同時使用(表達(dá)式混淆凶硅。除非把<script>
模板放在首頁)缝裁。
解決:
列表模塊使用F7自帶的虛擬列表組件進(jìn)行動態(tài)渲染。
3. 虛擬列表
虛擬列表可以用來渲染有大量數(shù)據(jù)的列表,并且不有有任何的性能問題捷绑。并且韩脑,它和所有的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主要有兩個切換頁面的方法:
mainView.router.load(options) - 把一個頁面加載到當(dāng)前視圖
mainView.router.back(options) - 這個方法會觸發(fā)一個反向的動畫并回到上一個頁面,也就是瀏覽歷史上的回退
主要使用到的參數(shù):
url:需要加載的頁面的URL
context:渲染Template7 模板時需要的上下文(模板數(shù)據(jù))鸭叙。
query:頁面路由傳遞的參數(shù)
force:只對 back 方法有效觉啊。如果設(shè)置為 true,那么會忽略瀏覽歷史中的上一個頁面沈贝,而是直接加載指定的頁面杠人。
reload:如果設(shè)置為 true,那么不會當(dāng)做新頁面加載宋下,而是直接替換當(dāng)前視圖的當(dāng)前頁面嗡善。并且在視圖瀏覽歷史中替換最后一條歷史。
遇到的問題:
在一個頁面更改了數(shù)據(jù)后杨凑,使用back回退到上個頁面滤奈,頁面數(shù)據(jù)沒有刷新
解決:
mainView.router.back({
url: url, // 指定回退頁面的url
context: data, // 傳遞模板數(shù)據(jù)給指定加載的頁面
force: true // 設(shè)置為true,直接加載指定的頁面
});
四、滾動加載
在產(chǎn)品頁面有一個“下拉加載數(shù)據(jù)”的需求撩满,F(xiàn)7有一個“無限滾動”組件蜒程,即列表滾動到底部時觸發(fā)加載函數(shù)。最初使用的是這個組件伺帘,使用方法:
給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...
});
每一次滾動到底部都會執(zhí)行回調(diào)函數(shù)里的代碼
遇到的問題:
- 一開始產(chǎn)品頁面的div.page-content是嵌套在模板里面昭躺,而在產(chǎn)品頁面初始化時就已經(jīng)初始化“無限滾動”組件,所以后來動態(tài)生成的div.page-content不能觸發(fā)“無限滾動”伪嫁。
解決:優(yōu)化DOM結(jié)構(gòu)领炫,div.page-content一開始就要在頁面中存在。
- tab頁切換后张咳,滾動觸發(fā)加載數(shù)據(jù)時加載到了第一個tab頁的列表里帝洪。
解決:所有tab欄分類公用一個虛擬列表,切換tab頁面時清空當(dāng)前列表脚猾,重新加載指定數(shù)據(jù)葱峡。
- 一開始沒有給虛擬列表高度,它默認(rèn)是每個條目高度(44px)*條目數(shù)量龙助,實(shí)際上條目高度大于默認(rèn)高度砰奕,導(dǎo)致ul高度不夠影響滾動加載。
解決:給一個固定高度。
- 有個業(yè)務(wù)需求是當(dāng)前類別的數(shù)據(jù)加載完后军援,繼續(xù)下拉添加進(jìn)一張“當(dāng)前數(shù)據(jù)已加載完”的圖片仅淑,再拉可以在當(dāng)前列表繼續(xù)加載其它類別的數(shù)據(jù),該圖片仍然存在列表中以示分隔胸哥。但是虛擬列表的模板是初始化時固定的(只能添加相同模板的數(shù)據(jù))涯竟,列表更新時圖片會被清掉。
解決:在虛擬列表下新增一個DOM容器烘嘱,用來加載圖片昆禽。圖片的容器下新增一個虛擬列表容器,裝其它類別的數(shù)據(jù)蝇庭。
- 無線滾動觸發(fā)條件是列表滾動到底部醉鳖,沒有實(shí)現(xiàn)“拖拽加載”的效果。
解決:使用iScroll5插件哮内。
五盗棵、其它
1. Rem適配問題
rem是相對于根元素<html>
,這樣就意味著北发,我們只需要在根元素確定一個px字號纹因,則可以來算出元素的寬高。
例如:
html{
font-size:20px;
}
div {
width: 6rem;
height: 3rem;
}
div的寬 = 6*20 = 120px
使用:
- 媒體查詢適配根元素字號
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;
}
}
- JS動態(tài)計(jì)算
function tryResize(){
var docEl=document.documentElement;
var clientHeight = docEl.clientWidth;
if(!clientHeight)
{
return
}
docEl.style.fontSize=20*(clientHeight/375)+"px"
}
tryResize();
window.onresize=tryResize;
計(jì)算規(guī)則:
例如設(shè)計(jì)稿是375的尺寸琳拨,375頁面的font-size是20px瞭恰,那么320的頁面呢?320/375 = 0.8533 320是375的0.8533倍狱庇,所以320的font-size等于20*0.8533 = 17.0667惊畏。
遇到的問題:
部分安卓機(jī)型對rem支持不是很好,出現(xiàn)布局錯位問題密任。
解決:根據(jù)實(shí)際情況來考慮元素是運(yùn)用rem單位還是百分比或者是flex彈性布局颜启。文本的字號使用rem會出現(xiàn)小屏字體太小,大屏字體太大的情況
解決:文本字號使用px單位浪讳,結(jié)合媒體查詢
2. 使用require.Js管理js文件
通常我們js寫在一個或多個文件里缰盏,用<script>
標(biāo)簽引入頁面,但js文件過多會出現(xiàn)以下丑陋場景:
<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文件之間存在依賴關(guān)系口猜,必須嚴(yán)格保證加載順序,依賴性最大的模塊一定要放到最后加載透揣,當(dāng)依賴關(guān)系很復(fù)雜的時候济炎,代碼的編寫和維護(hù)都會變得困難。
require.Js就是為了解決以上問題淌实。
使用:
- 去官網(wǎng)下載最新版本冻辩,引入頁面
<script src="js/require.js" defer async="true"></script> // async屬性表明這個文件需要異步加載,避免網(wǎng)頁失去響應(yīng)拆祈。IE不支持這個屬性恨闪,只支持defer,所以把defer也寫上放坏。
- 全局配置
創(chuàng)建一個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屬性的作用是咙咽,指定網(wǎng)頁程序的主模塊。在上例中淤年,就是js目錄下面的main.js钧敞,這個文件會第一個被require.js加載。由于require.js默認(rèn)的文件后綴名是js麸粮,所以可以把main.js簡寫成main溉苛。
- 基本API
require會定義三個變量:define,require,requirejs,其中require === requirejs弄诲,一般使用require更簡短
define 從名字就可以看出這個api是用來定義一個模塊
require 加載依賴模塊愚战,并執(zhí)行加載完后的回調(diào)函數(shù)
例:
// a.js
define(function (){
var add = function (x,y){
return x+y;
};
return {
add: add
};
});
如果這個模塊還依賴其他模塊,那么define()函數(shù)的第一個參數(shù)齐遵,必須是一個數(shù)組寂玲,指明該模塊的依賴性。
define(['myLib'], function(myLib){
function foo(){
myLib.doSomething();
}
return {
foo : foo
};
});
當(dāng)require()函數(shù)加載上面這個模塊的時候梗摇,就會先加載myLib.js文件拓哟。
加載方法如下:
// main.js
require(['a'], function (a){
alert(a.add(1,1));
});
- 加載非規(guī)范的模塊
理論上,require.js加載的模塊伶授,必須是按照AMD規(guī)范断序、用define()函數(shù)定義的模塊。但是實(shí)際上谎砾,雖然已經(jīng)有一部分流行的函數(shù)庫(比如jQuery)符合AMD規(guī)范逢倍,更多的庫并不符合。那么景图,require.js怎樣加載非規(guī)范的模塊呢较雕?
這樣的模塊在用require()加載之前,要先用require.config()方法挚币,定義它們的一些特征亮蒋。
require.config()接受一個配置對象,這個對象除了有前面說過的paths屬性之外妆毕,還有一個shim屬性慎玖,專門用來配置不兼容的模塊。具體來說笛粘,每個模塊要定義(1)exports值(輸出的變量名)趁怔,表明這個模塊外部調(diào)用時的名稱湿硝;(2)deps數(shù)組,表明該模塊的依賴性润努。
比如关斜,jQuery的插件可以這樣定義:
require.config({
shim: {
'jquery.scroll': {
deps: ['jquery'], // 依賴的模塊
exports: 'jQuery.fn.scroll' // 輸出的變量名
}
}
});
遇到的問題:
使用百度的WebUploader上傳組件時,報錯找不到 WebUploader 變量铺浇。
原因: cdn版本較低
解決: 官網(wǎng)下載最新版