前言javascript
如今移動端的大勢所趨,凡是項目勢必都會有移動端的需求,那麼今天就來說講移動端開發吧。html
當今android、ios的開發,若是組建原生開發團隊來開發的話,費用仍是很大的,並且如今很多android應用也都是結合html來進行開發的。java
最近阿里也順勢推出了weex,我還沒去體驗,不過按照阿里以往的尿性,當初推出kissy時也是號稱各類牛逼烘烘的技術,結果開發的過程中卻出現了各類各樣的坑,等到能真的實際使用上也是好幾年之後的事情了。node
cordova跟weex是比較類似的,從2011年開始到如今,通過了這麼多年的發展,api更加穩定,資源比較豐富。android
廢話就到這裏了,開始碼代碼吧,文章中使用的是cordova+angularjs。ios
建立項目angularjs
首先須要安裝nodejs,而後經過npm安裝cordova,完成了環境的需求後,就能夠經過以下命令建立一個cordova項目:web
cordova create 項目名
至於項目內的文件結構這裏就很少介紹了,園內有許多優秀的文章有詳細說明。npm
以上只是稍微簡介一下,因爲cordova的特殊性,使咱們能夠使用構建web的方式來構建手機應用,所以接下來的文章會介紹如何構建一個既能夠在瀏覽器上進行測試,又能夠在手機中運行的應用。bootstrap
示例
首先看一下例子,代碼以下:
<body ng-app="app" ng-controller="ctrl.index"> <div ng-view> </div> </body> <script id="init" type="text/ng-template"> 初始化中,{{ count }}秒後完成 </script> <script id="main" type="text/ng-template"> 設備信息: {{ deviceId }} </script> <script type="text/javascript" src="js/angular.min.js"></script> <script type="text/javascript" src="js/angular-route.min.js"></script> <script type="text/javascript"> var app = angular.module('app', ['ngRoute']); app.config([ '$routeProvider', function ($routeProvider) { $routeProvider.when('/init', { controller: 'ctrl.init', templateUrl: 'init' }).when('/main', { controller: 'ctrl.main', templateUrl: 'main' }); } ]); app.controller('ctrl.index', [ '$location', function ($location) { $location.path('/init'); } ]).controller('ctrl.init', [ '$interval', '$location', '$scope', function ($interval, $location, $scope) { $scope.count = 5; $interval(function () { if ($scope.count != 1) return $scope.count--; $location.path('/main'); }, 1000); } ]).controller('ctrl.main', [ '$scope', function ($scope) { $scope.deviceId = '未知'; } ]) </script>
因爲cordova提供的調用Native並非當即就可以使用的,所以須要讓angular的初始化延遲到deviceready事件中進行,代碼調整以下:
//移除ng-app <body ng-controller="ctrl.index"> //angular延遲初始化 <script type="text/javascript"> if (true) { angular.bootstrap(document.body, ['app']); } else { document.addEventListener('deviceready', function () { angular.bootstrap(document.body, ['app']); }, false); } </script>
至於cordova.js的話,編譯時須要手動將路徑添加上去。
重構
觀察以上的代碼,其中有很多內容是能夠分離出去的,好比:每一個路由的頁面html、每一個路由對應的控制器代碼、路由配置代碼等,接下來咱們一步步分離這些代碼,並使用nodejs來合併這些代碼從新生成當前的index.html。
首先在項目文件夾下建立一個src的文件,並建立index.tpl做爲模板,用ejs來生成最終的index.html,部分代碼以下:
<% if (!DEV) { %> <script type="text/javascript" src="cordova.js"></script> <% } %> //其餘代碼略 <script type="text/javascript"> <% if (DEV) { %> angular.bootstrap(document.body, ['app']); <% } else { %> document.addEventListener('deviceready', function () { angular.bootstrap(document.body, ['app']); }, false); <% } %> </script>
建立一個app.js用來執行生成,代碼以下:
var async = require('async'); var ejs = require('ejs'); var fs = require('fs'); var path = require('path'); global.DEV = false; async.waterfall([ function (fn) { fs.readFile( path.join(__dirname, 'index.tpl'), 'utf8', fn ); }, function (htmlTpl, fn) { var html = ejs.render(htmlTpl); fs.writeFile( path.join(__dirname, '../', 'www', 'index.html'), html, fn ); } ], function (err) { console.log(err || 'done'); });
經過變量DEV來控制瀏覽器測試或者app html,接下來將各個路由html分離到src/html目錄中去,分別爲init.html和main.html,只要修改app.js讀取src/html目錄並根據原先的html格式填充到模板中去便可,代碼修改以下:
//index.tpl //略 <% views.forEach(function(view) { %> <script id="<%= view.id %>" type="text/ng-template"> <%- view.html %> </script> <% }); %> //略 //app.js //略 global.views = []; var viewDir = path.join(__dirname, 'view'); async.waterfall([ //略, function (fn) { fs.readdir(viewDir, fn); }, function (filenames, fn) { async.eachSeries(filenames, function (filename, readFn) { if(path.extname(filename) != '.html') return readFn(); fs.readFile( path.join(viewDir, filename), 'utf8', function (err, html) { if (err) return readFn(err); global.views.push({ id: filename.replace('.html', ''), html: html }); readFn(); } ); }, fn); }, //略 ], function (err) { console.log(err || 'done'); });
至於controller的分離跟view是相似的,這裏就再也不提供重複的代碼了。
而$routeProvider配置的配置是從view直接映射過來的,所以只要稍微的修改一下即可以解決了,這裏也不重複編碼了。
接下來引入cordova的組件,如:device,經過命令:cordova plugin add cordova-plugin-device來進行安裝,因爲使用的時候是直接用device對象的,所以須要對其包裝一下,代碼放置在src/release中,代碼以下:
app.factory('sys.device', [ function () { return { uuid: device.uuid } } ]);
那麼能夠建立一份依賴於瀏覽器環境的,目錄爲src/dev,代碼以下:
app.factory('sys.device', [ function () { return { uuid: 'uuid' }; } ]);
修改一下ctrl.main,將device引入,代碼以下:
app.controller('ctrl.main', [ '$scope', 'sys.device', function ($scope, device) { $scope.deviceId = device.uuid; } ]);
在app.js生成index.html的時候,若是DEV爲true則讀取src/dev目錄不然讀取src/release目錄,這樣的話,瀏覽器測試和編譯app運行都沒問題了。
結尾
許久沒有寫博客了,表達可能不是很清晰,若是有什麼問題能夠留言給我,那麼今次的文章就到這裏了,謝謝。