sencha touch 入門系列 (五)sencha touch運行及代碼解析(上)


  由於最近項目比較忙,加之還要轉戰原生開發,所以很久沒更新了,今天我們接着上一次的內容往下講:

  首先我們打開index.html,這是我們整個程序的訪問入口,也是整個項目的引入地:

  

 1 <!DOCTYPE HTML>
 2 <html manifest="" lang="en-US">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>MyFirst</title>
 6     <style type="text/css">
 7          /**
 8          * Example of an initial loading indicator.
 9          * It is recommended to keep this as minimal as possible to provide instant feedback
10          * while other resources are still being loaded for the first time
11          */
12         html, body {
13             height: 100%;
14             background-color: #1985D0
15         }
16 
17         #appLoadingIndicator {
18             position: absolute;
19             top: 50%;
20             margin-top: -15px;
21             text-align: center;
22             width: 100%;
23             height: 30px;
24             -webkit-animation-name: appLoadingIndicator;
25             -webkit-animation-duration: 0.5s;
26             -webkit-animation-iteration-count: infinite;
27             -webkit-animation-direction: linear;
28         }
29 
30         #appLoadingIndicator > * {
31             background-color: #FFFFFF;
32             display: inline-block;
33             height: 30px;
34             -webkit-border-radius: 15px;
35             margin: 0 5px;
36             width: 30px;
37             opacity: 0.8;
38         }
39 
40         @-webkit-keyframes appLoadingIndicator{
41             0% {
42                 opacity: 0.8
43             }
44             50% {
45                 opacity: 0
46             }
47             100% {
48                 opacity: 0.8
49             }
50         }
51     </style>
52     <!-- The line below must be kept intact for Sencha Command to build your application -->
53     <script id="microloader" type="text/javascript" src=".sencha/app/microloader/development.js"></script>
54 </head>
55 <body>
56     <div id="appLoadingIndicator">
57         <div></div>
58         <div></div>
59         <div></div>
60     </div>
61 </body>
62 </html>

首先我們看第4行

  

<meta charset="UTF-8">

  這個是設置瀏覽器的默認編碼,創建項目的時候默認會創建為utf-8編碼,當然你也可以設置成GBK這些,根據自己的實際需要來,正常情況下保持utf-8就可以了,若去掉這個標簽,當頁面出現中文的時候將會出現亂碼

 

12行的樣式:

  

html, body {
            height: 100%;
            background-color: #1985D0
 }

這里是用來定義整個頁面的高度為100%,以及它的背景色,開發時根據自己的實際需要修改

 

17到50行的樣式定義了一段css動畫,通過id關聯了body標簽中的div:

  

<div id="appLoadingIndicator">
        <div></div>
        <div></div>
        <div></div>
</div>

也就是我們項目打開時的那三個一直閃爍的小點,在項目的js文件載入完畢后,在app.js中通過Ext.fly('appLoadingIndicator').destroy()對其進行了銷毀

接下來最重要的就是53行引入的js了,這是整個項目js文件的入口:

<script id="microloader" type="text/javascript" src=".sencha/app/microloader/development.js"></script>

你可以打開對應的js文件觀察下代碼,

development.js的主要最用就是解析app.json文件(我們的資源文件的配置都寫在里面,下面我們會給大家介紹下app.json文件的配置項)載入相關的資源文件,並對設備進行判斷並設置一些css3媒體查詢的內容

關於css3的媒體查詢,是個很強大的功能,在移動webapp,以及現在流行的響應式開發中都起着巨大的作用,大家可以網上自己百度或者google了解下,

頁面中meta標簽中viewport的設置在android官方文檔中也有講解:http://developer.android.com/guide/webapps/best-practices.html

下面我對代碼做了簡單的注釋,因為這里的代碼正常情況下我們不用去修改,所以大家簡單了解下就可以,如果覺得看不懂代碼或者想更好的學習js,強烈推薦《javascript高級編程》這本書,

目前最新版本是第三版,看完對js的提升還是相當大的,讀完之后可以再配合看看《javascript權威指南》,這本更適合作為工具書, 目前最新版本第6版

/**
 * Sencha Blink - Development
 * @author Jacky Nguyen <jacky@sencha.com>
 */
(function() {
    var head = document.head;

    function write(content) {
        document.write(content);
    }

    function addMeta(name, content) {
        var meta = document.createElement('meta');

        meta.setAttribute('name', name);
        meta.setAttribute('content', content);
        head.appendChild(meta);
    }

    //通過http請求讀取app.json文件
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'app.json', false);
    xhr.send(null);

    //將讀取的app.json文件的json內容解析為json對象
    var options = eval("(" + xhr.responseText + ")"),
        scripts = options.js || [],//如果存在js屬性將對象中的js屬性賦值給scripts變量,不存在則傳空數組
        styleSheets = options.css || [],//同上,設置css屬性
        i, ln, path, platform, theme, exclude;

    //判斷app.json的json內容是否設置了platform屬性,主要用來配置theme主題的
    if(options.platform && options.platforms && options.platforms[options.platform] && options.platforms[options.platform].js) {
        scripts = options.platforms[options.platform].js.concat(scripts);
    }

    //通過瀏覽器的userAgent來判斷是否是ie10,如果是創建css3媒體查詢設置
    if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
        var msViewportStyle = document.createElement("style");
        msViewportStyle.appendChild(
            document.createTextNode(
                "@media screen and (orientation: portrait) {" +
                    "@-ms-viewport {width: 320px !important;}" +
                "}" +
                "@media screen and (orientation: landscape) {" +
                    "@-ms-viewport {width: 560px !important;}" +
                "}"
            )
        );
        document.getElementsByTagName("head")[0].appendChild(msViewportStyle);
    }

    //設置頁面的meta標簽,控制頁面的縮放以及寬高等
    addMeta('viewport', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no');
    addMeta('apple-mobile-web-app-capable', 'yes');
    addMeta('apple-touch-fullscreen', 'yes');

    if (!window.Ext) {
        window.Ext = {};
    }
    Ext.microloaded = true;

    //平台過濾對象,判斷項目位於什么設備平台上
    var filterPlatform = window.Ext.filterPlatform = function(platform) {
        var profileMatch = false,
            ua = navigator.userAgent,
            j, jln;

        platform = [].concat(platform);

        function isPhone(ua) {
            var isMobile = /Mobile(\/|\s)/.test(ua);

            // Either:
            // - iOS but not iPad
            // - Android 2
            // - Android with "Mobile" in the UA

            return /(iPhone|iPod)/.test(ua) ||
                      (!/(Silk)/.test(ua) && (/(Android)/.test(ua) && (/(Android 2)/.test(ua) || isMobile))) ||
                      (/(BlackBerry|BB)/.test(ua) && isMobile) ||
                      /(Windows Phone)/.test(ua);
        }

        function isTablet(ua) {
            return !isPhone(ua) && (/iPad/.test(ua) || /Android|Silk/.test(ua) || /(RIM Tablet OS)/.test(ua) ||
                (/MSIE 10/.test(ua) && /; Touch/.test(ua)));
        }

        // Check if the ?platform parameter is set in the URL
        var paramsString = window.location.search.substr(1),
            paramsArray = paramsString.split("&"),
            params = {},
            testPlatform, i;

        for (i = 0; i < paramsArray.length; i++) {
            var tmpArray = paramsArray[i].split("=");
            params[tmpArray[0]] = tmpArray[1];
        }

        testPlatform = params.platform;
        if (testPlatform) {
            return platform.indexOf(testPlatform) != -1;
        }

        //如果用戶在app.json中配置了platform設置,判斷當前平台進行匹配
        for (j = 0, jln = platform.length; j < jln; j++) {
            switch (platform[j]) {
                case 'phone':
                    profileMatch = isPhone(ua);
                    break;
                case 'tablet':
                    profileMatch = isTablet(ua);
                    break;
                case 'desktop':
                    profileMatch = !isPhone(ua) && !isTablet(ua);
                    break;
                case 'ios':
                    profileMatch = /(iPad|iPhone|iPod)/.test(ua);
                    break;
                case 'android':
                    profileMatch = /(Android|Silk)/.test(ua);
                    break;
                case 'blackberry':
                    profileMatch = /(BlackBerry|BB)/.test(ua);
                    break;
                case 'safari':
                    profileMatch = /Safari/.test(ua) && !(/(BlackBerry|BB)/.test(ua));
                    break;
                case 'chrome':
                    profileMatch = /Chrome/.test(ua);
                    break;
                case 'ie10':
                    profileMatch = /MSIE 10/.test(ua);
                    break;
                case 'windows':
                    profileMatch = /MSIE 10/.test(ua) || /Trident/.test(ua);
                    break;
                case 'tizen':
                    profileMatch = /Tizen/.test(ua);
                    break;
                case 'firefox':
                    profileMatch = /Firefox/.test(ua);
            }
            if (profileMatch) {
                return true;
            }
        }
        return false;
    };

    //在頁面中動態將app.json中配置的css文件引入
    for (i = 0,ln = styleSheets.length; i < ln; i++) {
        path = styleSheets[i];

        if (typeof path != 'string') {
            platform = path.platform;
            exclude = path.exclude;
            theme = path.theme;
            path = path.path;
        }

        if (platform) {
            if (!filterPlatform(platform) || filterPlatform(exclude)) {
                continue;
            }
            Ext.theme = {
                name: theme || 'Default'
            };
        }

        write('<link rel="stylesheet" href="'+path+'">');//輸出到頁面
    }

    //在頁面中動態將app.json中配置的js文件引入
    for (i = 0,ln = scripts.length; i < ln; i++) {
        path = scripts[i];

        if (typeof path != 'string') {
            platform = path.platform;
            exclude = path.exclude;
            path = path.path;
        }

        if (platform) {
            if (!filterPlatform(platform) || filterPlatform(exclude)) {
                continue;
            }
        }

        write('<script src="'+path+'"></'+'script>');//輸出到頁面
    }

})();

 

好玩developement.js,我們來看下它所解析的app.json文件,

注意:正是因為developement.js里是通過http請求來獲取app.json文件的,所以用sencha cmd創建的項目必須放到服務器環境下或者打包成安裝程序才能運行,直接打開index.html是會報錯,無法運行項目的

 

app.json:

{
    /**
     * 應用的命名空間,在項目中自定義項目文件時都要以這個命名空間開頭,例如自定義一個名為MyTest的view,必須得MyFirst.view.MyTest,否則會找不到文件
     */
    "name": "MyFirst",

    /**
     * 項目的訪問頁面的地址
     */
    "indexHtmlPath": "index.html",

    /**
     * 項目開發環境下的絕對地址
     * 例如在你開發環境下的地址 "http://localhost/myapp/index.html".
     *
     * 這個屬性一般不需要設置,除非你需要發布的時候引用服務端特定的資源文件,這時你可以設置對應的服務端地址
     */
    "url": null,

    /**
     * 項目中自定義的引用的js文件.
     * 每一個js文件都被定義為一個json屬性對象:
     *      {
     *          "path": "path/to/script.js" // 相對於app.json文件的js路徑
     *          "remote": true              // (選項)
     *                                      // - remote:該js文件是否是引用的遠程文件,如果設置為true即遠程文件,在用sencha cmd項目打包的時候這個
   *                     // - js文件就不會被打包壓縮到app.js文件(在app.json文件中配置的資源文件在打包時所有的js文件都會被打包* *                      //   到app.js文件中壓縮成一行)   
   *                      // - 中,其默認值為undefined,也就是被打包壓縮過來 * "update": "delta" // (選項) * // - 如果沒有指定這個選項,這個文件只會被載入一次 * // 同時緩存在localstorage(html5離線緩存)中直到它的值發生了改變 * // - "delta" 設置為改選項將會增量更新即只更新修改的部分,在2.2.1版本中發布production帶離線緩存的版本   *                      //    時設置這個屬性在js需要更新   
   *                      //   時更新后,項目會報錯,新版本是否修復該問題未知 * // - "full" 完全更新整個js文件 * "x-bootstrap": true // (Optional) * // 標明文件跟開發模式的依賴關系 * // 這些文件將不會拷貝到生成目錄中 * // 只會被development.js引用. * * }
*/ "js": [ { "path": "touch/sencha-touch.js", "x-bootstrap": true }, { "path": "bootstrap.js", "x-bootstrap": true }, { "path": "app.js", "bundle": true, /* 表示所有的js文件在打包生成時都合並到app.js文件中 */ "update": "delta" } ], /** * css文件的列表 * 每一項都是一個json對象 * { * "path": "path/to/item.css" // Path to file, if local file it must be relative to this app.json file * "remote": true // (Optional) * // - Defaults to undefined (falsey) to signal a local file which will be copied * // - Specify true if this file is a remote file which will not to be copied * "update": "delta" // (Optional) * // - If not specified, this file will only be loaded once, and * // cached inside localStorage until this value is changed to either one below * // - "delta" to enable over-the-air delta update for this file * // - "full" means full update will be made when this file changes * * } */ "css": [ { "path": "resources/css/app.css", "update": "delta" } ], /** * 設置html5離線緩存的緩存文件 */ "appCache": { /** * 緩存文件 */ "cache": [ "index.html" ], /** * 網絡選擇 */ "network": [ "*" ], /** * 回調項 */ "fallback": [] }, /** * 設置擴展的資源文件路徑,這些文件也會在打包的時候一起被打包進資源文件 */ "resources": [ "resources/images", "resources/icons", "resources/startup" ], /** * File / directory name matchers to ignore when copying to the builds, must be valid regular expressions */ "ignore": [ "\.svn$" ], /** * Directory path to store all previous production builds. Note that the content generated inside this directory * must be kept intact for proper generation of deltas between updates */ "archivePath": "archive", /** * List of package names to require for the cmd build process */ "requires": [ ], /** * Uniquely generated id for this application, used as prefix for localStorage keys. * Normally you should never change this value. */ "id": "23568a9e-e669-4786-b057-738279cffe3f" }

 

developement.js解析完成后,項目就會載入app.js文件,從而進入我們整個項目了.

這里順便提及一下js文件中引入的sencha-touch.js, 這是sencha cmd創建項目時生成的引用,

也是我們項目開發中推薦的引用,當你打開sencha的sdk文件夾時,你應該能看到下面4種js

sencha-touch.js :

  sencha touch壓縮后的核心代碼庫,里面只包括了sencha touch的sdk中的核心代碼,當你需要其他功能得時候,需要通過requires(我們會在后面的教程中詳細講解)的方式來引用指定的js,在項目完成后,使用sencha cmd的打包壓縮功能,只有requires的代碼、核心代碼以及用戶自己寫的項目代碼會被壓縮到app.js中,這樣,就保證了項目文件的最小化。包括phonegap從3.0開始也采用了模塊化的結構,需要的功能才引入,保證文件最小化

  

sencha-touch-all.js:

  顧名思義,這個-all.js就是sencha touch壓縮后的所有代碼了,除非特殊情況,否則我們很少會使用這個文件。

 

sencha-touch-all-debug.js :

  這個是包含了未壓縮的sencha touch的所有代碼的js文件,看到debug,很多有開發經驗的同學應該知道這個文件是用來調試用的了:

 

sencha-touch-debug.js:

  未壓縮的核心代碼庫文件

 

在sdk目錄下的builds文件夾下,還有個

sencha-touch-all-compat.js:

  這個js文件比較特殊,因為sencha touch從1.x版本到2.x版本的變化比較大,兩個版本沒法做到兼容,這個js就是為了讓1.x版本升級到2.x版本來引用的,如果

你手頭的項目是1.x版本的,你想升級為2.x版本,你就需要在更新了sdk版本后引用該js文件來達到兼容升級的作用

 

下一講,我們將從app.js開始介紹整個項目的運行流程及mvc的處理方式

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM