[关闭]
@njy 2016-03-30T02:12:06.000000Z 字数 16516 阅读 2355

航班管家伙力五星级新版酒店总结

航班管家


伙力五星级新版酒店

项目: 伙力五星级新版酒店

可以在航班管家或者高铁管家APP里底部选项卡(TabBarIOS)第三个旅行服务找到入口: 伙力五星

测试内部地址(http://103.37.151.253:9000/index.html)
正式服务器地址(http://hotel.rsscc.cn/hotel1/index.html)

航班管家NativeAPI(https://www.zybuluo.com/tianfangye/note/105706)

前端是单页面MVVM应用,使用轻量级框架mithril,github文档地址(http://lhorie.github.io/mithril/),用h5页面做的Hybrid App(混合模式移动应用)

代码地址

  1. 前端代码在工程目录的 fstar_mithril(https://github.com/huoli-njy/fstar_mithril.git) 下。

前端自动化工具

1.使用 FIS3(v3.3.15版本,需要运行 node v4.2.5版本) 作为前端代码管理工具,主要功能包括合并文件、JS 压缩、CSS 压缩、LESS 处理、图片雪碧图自动合并等功能。FIS 配置文件在 fstar_mithril/fis-conf.js(fis-conf_3.js)。FIS3 使用文档,参考:http://fis.baidu.com/fis3/docs/beginning/intro.html
2. 使用 FIS(v1.9.14版本,需要运行 node v0.12版本) 作为前端代码管理工具,主要功能包括合并文件、JS 压缩、CSS 压缩、LESS 处理、图片雪碧图自动合并等功能。FIS 配置文件在 fstar_mithril/fis-conf.js(fis-conf_1.js)。FIS 使用文档,参考:http://fex.baidu.com/fis-site/docs/beginning/getting-started.html
3. fis和fis3安装和插件:

  1. npm install -g fis3
  2. npm install -g fis@1.9.14
  3. npm install -g fis-parser-less
  4. npm install -g fis3-postpackager-loader
  5. 根据提示安装缺少的插件

4.fis常用命令:

  1. cd ~/workspace/github/fstar_mithril
  2. <!-- 启动本地服务 -->
  3. sudo fis3 server start -p 15080
  4. <!-- 清除本地服务器内容 -->
  5. sudo fis3 server clean
  6. <!-- 编译本地文件 -->
  7. sudo fis3 release -w
  8. <!-- 停止本地服务 -->
  9. sudo fis3 server stop
  10. <!-- 启动本地服务 -->
  11. sudo fis server start -p 15080
  12. <!-- 清除本地服务器内容 -->
  13. sudo fis server clean
  14. <!-- 编译本地文件 -->
  15. sudo fis release -wp

4.浏览器同源策略的绕过
旧版 chrome 开启跨越服务
可以本地起两个服务,后台(nginx)提供接口,fis的node服务器换一个port访问页面实现自动化

  1. njy@localhost:~$cd /Applications/
  2. njy@localhost:/Applications$ls
  3. njy@localhost:/Applications$open Google\ Chrome.app/ --args --disable-web-security

新版 chrome --args --disable-web-security失效,用
nginx服务器转发

  1. sudo nginx
  2. sudo nginx -s reload
  3. sudo nginx -s stop
  4. cd /usr/local/etc/nginx
  5. nginx.conf
  6. <!-- 访问地址 -->
  7. http://localhost/index.html

nginx.conf 内容

  1. location / {
  2. proxy_pass http://127.0.0.1:15080/;
  3. proxy_redirect off;
  4. proxy_set_header X-Real-IP $remote_addr;
  5. proxy_set_header Host $host;
  6. proxy_set_header X-Forwarded-Host $server_name;
  7. proxy_set_header X-Real-IP $remote_addr;
  8. proxy_set_header X-Forwarded-For $remote_addr;
  9. #root html;
  10. #index index.html index.htm;
  11. }
  12. location /hotel/{
  13. #proxy_pass http://hotel.rsscc.cn/hotel/;
  14. proxy_pass http://103.37.151.253:9000/hotel/;
  15. proxy_redirect off;
  16. proxy_set_header X-Real-IP $remote_addr;
  17. proxy_set_header Host $host;
  18. proxy_set_header X-Forwarded-Host $server_name;
  19. proxy_set_header X-Real-IP $remote_addr;
  20. proxy_set_header X-Forwarded-For $remote_addr;
  21. }
  22. location /rest/{
  23. proxy_pass http://hotel.huoli.com/rest/;
  24. #proxy_pass http://hotel-test.rsscc.com/rest/;
  25. proxy_redirect off;
  26. proxy_set_header X-Real-IP $remote_addr;
  27. proxy_set_header Host $host;
  28. proxy_set_header X-Forwarded-Host $server_name;
  29. proxy_set_header X-Real-IP $remote_addr;
  30. proxy_set_header X-Forwarded-For $remote_addr;
  31. }

5.前端源码下面放了几个shell 脚本,用来更加快捷的运行 FIS 命令。如:

  • debug_new.sh(发布到 search@103.37.151.253服务器)(测试服务器)
  • pb.sh(发布到search@43.241.208.207服务器)(正式服务器)
  • publish.sh(发布到本地当前目录的外层目录)
  • debug.sh(发布到 dev0服务器)
  • debug2.sh(发布到 43.241.208.237服务器)

前端项目详情

航班管家NativeAPI

  1. Web App 是嵌在航班管家和高铁管家中的,两个管家均采用了 WebViewJSBridge 的方式,为前端提供了一系列的 NativeAPI,赋予了 HTML 一些 Native 的能力。要使用 NativeAPI,首先必须要把 HTML 的域名放在两个管家的白名单中,其次需要引入 fstar_mithril/lib/native-api.js。NativeAPI 的文档在:https://www.zybuluo.com/tianfangye/note/105706。 文档由公司的包义德维护,他的 QQ 是:516990345。

选用Mithril

  1. 轻量级,松耦合,压缩后3kb
  2. API 提供一个模板引擎,带 DOM diff实现,支持路由和组合,路由选择上提供了三种(search,hash,pathname),开始选用search(?),为了兼容微信支付(不能占用?),所以选用了hash(#),格式如(http://dev0.xiayizhan.mobi/#list?checkIn=1445996500336&checkOut=1446082900336&city=%E5%8E%A6%E9%97%A8&keyword=&resetCircles=yes)

    1. m.route.mode = 'hash';
  3. 声明式的绑定,将大量代码逻辑、状态转到ViewModel
  4. 比avalon和angularJS更轻量,与Vue.js相当
  5. 前端使用了 Mithril的前端MVVM(数据驱动) 框架,与react原理类似,渲染建立在 Virtual DOM 上——一种在内存中描述 DOM 树状态的数据结构。当状态发生变化时, Mithril 重新渲染 Virtual DOM,比较计算之后给真实 DOM 打补丁。
    Virtual DOM 提供了一个函数式的方法描述视图,这真的很棒。因为它不使用数据观察机制,每次更新都会重新渲染整个应用,因此从定义上保证了视图与数据的同步。它也开辟了 JavaScript 同构应用的可能性。
  6. 整个 Web App 是单页的,只有部分与主体逻辑关系不大的模块采用了新页面,如地图,选择城市页面。

前端js详解

  1. project(fstar_mithril)
  2. ├─ htmls (统一头部配置)
  3. ├─ commonHead.html (头部文件)
  4. ├─ images (图片)
  5. ├─ more
  6. ├─ less (less)
  7. ├─ more
  8. ├─ scripts (工程模块)
  9. ├─ common (公共模块)
  10. └─ actionSheet.js (列表星级价格筛选)
  11. └─ alert.js (弹出框 确定)
  12. └─ base64.js (忽略:base64解析)
  13. └─ common.js (代码集成)
  14. └─ confirm.js (弹出框 确定 取消)
  15. └─ CONSTANT.js (公共不变的变量)
  16. └─ lazyLoad.js (图片惰性加载)
  17. └─ messageBox.js (弹出框容器)
  18. └─ scrollEnd.js (分页)
  19. └─ toast.js (日期提示)
  20. └─ userCenter.js (登录控件)
  21. └─ util.intro.js (util初始化)
  22. └─ util.js (util 公共方法)
  23. └─ more
  24. ├─ lib (基础模块)
  25. └─ lib.js (代码集成)
  26. └─ mithril.js (mvvm基础库)
  27. └─ mithril.loader.js (模块加载)
  28. └─ native-api.js (nativeAPI)
  29. └─ swiper.min.js (图片滚动模块)
  30. └─ more
  31. ├─ account.js (忽略:账户信息)
  32. ├─ accountPhoneApp.js (忽略:验证新手机号)
  33. ├─ activityListApp.js (忽略:优惠活动)
  34. ├─ brandFilter.js (品牌筛选)
  35. ├─ circleFilter.js (位置筛选)
  36. ├─ cityFilter.js (选择城市)
  37. ├─ cityFilterbat.js (忽略:备份选择城市)
  38. ├─ citySelector.js (忽略:老版本选择城市)
  39. ├─ comment.js (详情评论)
  40. ├─ danpin.js (忽略:旧版活动页面)
  41. ├─ dateSelector.js (选择日期)
  42. ├─ demandApp.js (下订单页面床型选择)
  43. ├─ detail.js (供应商源)
  44. ├─ detailProduct.js (床型显示)
  45. ├─ gtOrderList.js (忽略:旧版高铁订单红包)
  46. ├─ hotelDetail.js (忽略:酒店介绍)
  47. ├─ hotelDetail2.js (忽略:酒店介绍)
  48. ├─ indexApp.js (首页面)
  49. ├─ invoiceApp.js (发票信息)
  50. ├─ invoiceInfo.js (发票状态)
  51. ├─ listApp.js (列表)
  52. ├─ modifyOrderApp.js (忽略:修改订单)
  53. ├─ nativeOrderPreview.js (支付显示)
  54. ├─ order.js (下订单)
  55. ├─ orderPre.js (航班管家下单页面中间页)
  56. ├─ pay.js (忽略:微信支付)
  57. ├─ priceFilter.js (忽略:旧版价格筛选)
  58. ├─ run.js (Web App入口,定义了Mithril 的各个路由对应关系)
  59. ├─ searchApp.js (搜索酒店)
  60. ├─ sortFilter.js (忽略:旧版排序)
  61. ├─ userAddress.js (常用地址)
  62. ├─ userAddressForm.js (新增常用地址)
  63. ├─ userBill.js (常用发票抬头)
  64. ├─ userBillForm.js (新增常用发票抬头)
  65. ├─ userHome.js (忽略:我的账户)
  66. ├─ userOrder.js (我的订单)
  67. ├─ userOrderDetail.js (订单状态)
  68. ├─ userPassengerForm.js (新增常用入住人)
  69. ├─ userPassengers.js (常用入住人)
  70. ├─ verify.js (忽略:网页版登录)
  71. ├─ voucher.js (忽略:代金券明细)
  72. ├─ 0.html (改变标题页面)
  73. ├─ ad.html (广告页面)
  74. ├─ cityFilter.html (城市选择页面)
  75. ├─ debug.sh (发布到 dev0服务器)
  76. ├─ debug2.sh (发布到 43.241.208.237服务器)
  77. ├─ debug_new.sh (发布到 search@103.37.151.253服务器)
  78. ├─ fis-conf.js (fis编译配置)
  79. ├─ fis-conf_1.js (备份:fis@1.9.14编译配置)
  80. ├─ fis-conf_3.js (备份:fis3编译配置)
  81. ├─ gjHotelRecommend.html (忽略:旧版本行程跳转中间页面)
  82. ├─ gtgj_ad1.html (忽略:高铁广告页面)
  83. ├─ gtOrderList.html (忽略:订单红包页面)
  84. ├─ gtxcGoList.html (行程跳转中间页面)
  85. ├─ index.html (首页面)
  86. ├─ map.html (地图页面)
  87. ├─ map.jsp (忽略:旧版本地图页面)
  88. ├─ nativeOrderPreview.html (支付显示页面)
  89. ├─ orderDetailButton.html (忽略:旧版本页面)
  90. ├─ pb.sh (发布到search@43.241.208.207正式服务器)
  91. ├─ publish.sh (忽略:发布到本地当前目录的外层目录)
  92. ├─ step.html (快捷步骤页面)
  93. ├─ test.html (忽略:测试页面)
  94. ├─ test.sh (忽略:测试脚本)
  95. ...

html文件

  1. 0.hmtl 空文件 用来改变微信ipone标题
  1. case util.PLATFORM.WEIXIN:
  2. if (/iphone|ipad|ipod/.test(navigator.userAgent.toLowerCase())) {
  3. document.title = title;
  4. var iframeTmp = document.createElement('iframe');
  5. iframeTmp.style.display = 'none';
  6. iframeTmp.src = window.domainName + '/0.html';
  7. iframeTmp.onload = function() {
  8. setTimeout(function() {
  9. iframeTmp.onload = null;
  10. document.body.removeChild(iframeTmp);
  11. }, 0);
  12. };
  13. document.body.appendChild(iframeTmp);
  14. } else {
  15. document.title = title;
  16. }

2.index.html 单页面应用首页

在html中嵌入统一头部资源
  1. <link rel="import" href="htmls/commonHead.html?__inline">

设置全局变量的window.domainName,window.apiRootPath,解决在不同服务器部署的需求

  1. <script>
  2. (function() {
  3. window.domainName = location.origin;
  4. window.apiRootPath = domainName;
  5. window.defaultMain = '';
  6. })();
  7. </script>
引入公共样式
  1. <link rel="stylesheet" href="less/common.less" type="text/css">
引入基础库lib.js 公共common.js 入口路由run.js 图片滚动第三方swiper.min.js 所有其他样式app.less

样式一开始和js一样 是按需加载的 考虑到每个css样式都较小,所以合并所有的样式文件,统一加载

  1. <script src="scripts/lib/lib.js"></script>
  2. <script src="scripts/common/common.js"></script>
  3. <script src="scripts/run.js"></script>
  4. <script src="scripts/lib/swiper.min.js"></script>
  5. <link rel="stylesheet" href="less/app.less" type="text/css">

主dom容器,根据hash路由在#main里渲染各个模块

  1. <div class="main" id="main"></div>

3.cityFilter.html 城市选择(城市数据量较多2K+,新开一个页面)

  1. var url = './cityFilter.html#cityFilter' +flag;
  2. location.href = url;

4.gtxcGoList.html 行程跳转中间页面
5.nativeOrderPreview.html 支付预览
6.htmls/commonHead.html 统一头部

images

相关图片和雪碧图(图片会被发布为绝对路径)

  1. .common-icon-search-city{
  2. width: 19px;
  3. height: 20px;
  4. background: url(../images/searchIconCity@2x.png?__sprite) no-repeat;
  5. }

Less

样式文件才用less 发布为css

  1. @import url('./constant.less');

通过@import 集成为 common.less 和 app.less

Script

scripts/lib/lib.js 包括mithril.js 和mithril.loader.js

  • mithril.js 让全局有了m函数
  • mithril.loader.js 模块按需加载

scripts/common/common.js

设置了全局变量util方法,在common文件夹查阅

  1. ";util.HOTEL_SUGGEST_TYPE;util.HOTEL_SEARCH_TYPE;util.HOTEL_TYPE_ID;util.HOTEL_NEARBYTYPE;util.HOTEL_PLATFORM_TYPE;util.NCOMMON_PARAMS;util.INTERFACE_GETHOTELDATA;util.INTERFACE_GETHOTELMENUDATA;util.INTERFACE_ADDORDERDATA;util.PS;util.PRICESRC;util.ADDBED;util.PAYTYPE;util.PHONE_REG;util.IMAGE_DIR;util.SCREEN_WIDTH;util.WEEK_NAME;util.CURRENT_CITY;util.ORDER_MAIL_TYPE;util.BREAKFASE_TYPE;util.PAYMENT_METHOD;util.HOTEL_STAR;util.HOTEL_STAR_SIMPLE;util.HOTEL_STAR_OFFICIALSTAR;util.CUSTOMER_PHONE;util.VOUCHER_STATUS;util.STAR_TYPES;util.STAR_TYPES_VALUES;util.SEARCH_PRICE_RANGES;util.SEARCH_PRICE_RANGES_VALUES;util.SORT_TYPES;util.SORT_TYPE_VALUES;util.NO_PAY_NOTICE_NATIVE;util.ACTIVITY_MAIN;util.ACTIVITY_DETAIL;util.PRODUCT_TYPES;util.OS;util.COMMON_PARAMS;util.debug;util.log;util.showLoading;util.hideLoading;util.formatDate;util.dateCount;util.isSameDay;util.getCurrentWeek;util.secretNumber;util.nextDate;util.dateFormatFmt;util.extend;util.extendProp;util.extendCommon;util.readableNum;util.viewData;util.cookie;util.storage;util.sessionStorage;util.updateTitle;util.adjustImage;util.redraw;util.calMaxVoucher;util.calUseableVoucher;util.speedUpNativeAPI;util.openWindow;util.closeWindow;util.closeWebView;util.reload;util.reloadByTime;util.reloadByTimeLocal;util.isPlatform;util.lastestDate;util.rightButtonText;util.showToast;util.hideToast;util.messageBox;util.alert;util.confirm;util.notice;util.stopPropagation;util.actionSheet;util.DEVICE_INFO;util._getDeviceInfo;util.userCenter;util.lazyLoad;util.scrollEnd;util.startApp;util.PLATFORM;util.localTime;util.isReload;util.hasCurPos;util.currentPosition;util.header;util.HUOLIUSER_INFO"

scripts/run.js(单页面逻辑入口文件)

由于indexApp.js 较小,所以直接嵌入到run.js

  1. // util 全局变量 会提前载入
  2. util.startApp = function(){
  3. __inline('indexApp.js');
  4. }

在app中打开webView,都会在cookie里写入appName

  1. var appName = util.cookie.getItem('appName');

根据util.PLATFORM.CURRENT平台的不同,都调用run()函数,会生成一个全局的虚拟dom对象window.fstar(真实的路由) 和 window.__realRoutes(默认的路由)

  1. function run() {
  2. m.route.mode = 'hash'; //用hash作为路由
  3. m.route2(document.getElementById('main'), window.defaultMain, {
  4. '': {
  5. name: 'indexApp',
  6. path: __uri('./indexApp.js')
  7. },
  8. 'cityFilter': { //m.route('cityFilter')
  9. name: 'cityFilter', // fstar.cityFilter
  10. path: __uri('./cityFilter.js') //文件的位置
  11. },
  12. ...
  13. }, {
  14. 'namespace': 'fstar' //命名空间
  15. });
  16. }

调用方法有:

  1. m.loadRoute('list').then(function(listApp) {
  2. m.route('list', {
  3. checkIn: self.currentDate().getTime(),
  4. checkOut: checkOut.getTime(),
  5. city: util.NCOMMON_PARAMS.city
  6. }, true);
  7. });

scripts/lib/swiper.min.js调用初始化:

  1. var swiper = new Swiper('.swiper-container', {
  2. pagination: '.swiper-pagination',
  3. paginationClickable: true
  4. });

按需加载indexApp.js:

所有的文件写法固定:
1.命名空间上加路由name函数,函数内部加同名对象,返回这个对象。

  1. fstar.indexApp= (function() {
  2. var indexApp = {};
  3. return indexApp;
  4. })();

2.mvvm 分为三层:

  1. //控制层
  2. indexApp.controller=function(){
  3. //返回数据层对象
  4. return indexApp.viewModel;
  5. }
  6. //视图层
  7. indexApp.view=function(ctrl){ //ctrl就是数据层对象
  8. return m('.indexApp',{},[]);
  9. }
  10. //数据层对象
  11. indexApp.viewModel = {
  12. }

3.mithril 内部方法实现:

  1. //跳转首页 ‘’对应run.js 的路由key
  2. m.route('');
  3. //dom容器#main 虚拟dom对象indexApp
  4. m.module(document.getElementById('main'), fstar.indexApp);
  5. //dom容器#main 虚拟dom对象indexApp
  6. m.render(
  7. document.getElementById('main'),
  8. indexApp.view( //视图层
  9. indexApp.controller() //调用controller() 对数据层对象viewModule的数据进行处理 返回数据层对象ctrl
  10. )
  11. );

4.闭包赋值取值

  1. city: m.prop(''), //默认m.prop('')初始化
  2. vm.ctiy() //取值
  3. vm.city('北京') //赋值

5.文件第一次加载进入会执行一次init().

  1. if (!indexApp.isInitialized) {
  2. indexApp.init();
  3. }

6.view 视图模板层

  1. m(
  2. '.indexApp', //类名
  3. {honclick: ctrl.selectCity.bind(ctrl)},//属性
  4. []//子dom虚拟对象
  5. )
  6. todo.view = function() {
  7. return m("html", [
  8. m("body", [
  9. m("input"),
  10. m("button", "Add"),
  11. m("table", [
  12. m("tr", [
  13. m("td", [
  14. m("input[type=checkbox]")
  15. ]),
  16. m("td", "task description"),
  17. ])
  18. ])
  19. ])
  20. ]);
  21. };
  22. m.render(document, todo.view());
  23. <html>
  24. <body>
  25. <input />
  26. <button>Add</button>
  27. <table>
  28. <tr>
  29. <td><input type="checkbox" /></td>
  30. <td>task description</td>
  31. </tr>
  32. </table>
  33. </body>
  34. </html>

6.具体代码解释如下:

  1. fstar.indexApp = (function() {
  2. var indexApp = {
  3. isInitialized: false, //首次加载为false
  4. viewModel: { //viewModel 数据层
  5. city: m.prop(''), //初始化变量名
  6. cityid: m.prop(''),
  7. cityLoc: m.prop(false),
  8. checkIn: m.prop(''),
  9. checkOut: m.prop(''),
  10. priceStar: m.prop(''),
  11. starLevel: m.prop(['不限']),
  12. priceRange: m.prop('不限'),
  13. keyword: m.prop(''),
  14. type: m.prop('q'),
  15. sid: m.prop(''),
  16. sids: m.prop(''),
  17. lat: m.prop(''),
  18. lon: m.prop(''),
  19. typeid: m.prop(''),
  20. unreadMessageCount: m.prop(0),
  21. checkTime: function(){}, //添加方法
  22. selectCity: function() {},
  23. selectDate: function() {},
  24. searchKeyword: function() {},
  25. goToList: function() {},
  26. cancelKeyword: function() { },
  27. checkNewMessage: function() { },
  28. goToDetail: function(hotelId, name) {},
  29. goToOrder: function() {},
  30. getCoorByAPI: function(){},
  31. getAddressByCoor: function(currentPlatName){},
  32. priceFilter: function() {},
  33. cancelPriceStar: function() {},
  34. reloadTime: function(){},
  35. onunload: function(){} //路由跳转会执行
  36. },
  37. init: function() {
  38. this.isInitialized = true;
  39. }
  40. };
  41. indexApp.controller = function() { //控制器
  42. var vm = indexApp.viewModel;
  43. // 同步日期
  44. vm.reloadTime();
  45. vm.city(util.NCOMMON_PARAMS.city);
  46. vm.cityid(util.NCOMMON_PARAMS.cityid);
  47. var cityLoc = util.cookie.getItem("fstar_cityLoc");
  48. if(cityLoc && cityLoc!=="0"){
  49. cityLoc = JSON.parse(cityLoc);
  50. vm.cityLoc(cityLoc || false);
  51. } else {
  52. vm.cityLoc(false);
  53. }
  54. if (!indexApp.isInitialized) {
  55. indexApp.init();
  56. }
  57. util.updateTitle('伙力特惠五星');
  58. util.hideLoading();
  59. vm.unreadMessageCount(0);
  60. util.userCenter._checkLogin();
  61. // indexApp.viewModel.checkNewMessage();
  62. return indexApp.viewModel;
  63. };
  64. indexApp.view = function(ctrl) { //view 视图层
  65. return m('.indexApp', [
  66. indexApp.searchView(ctrl),
  67. m('.common-border'),
  68. indexApp.myBillView(ctrl),
  69. indexApp.redPacketsView(ctrl),
  70. ]);
  71. };
  72. indexApp.searchView = function(ctrl) {
  73. ...
  74. };
  75. indexApp.myBillView = function(ctrl) {
  76. ...
  77. };
  78. indexApp.redPacketsView = function(ctrl) {
  79. ...
  80. };
  81. return indexApp;
  82. })();

在使用中也遇到一些问题

  1. mithril的事件绑定自动渲染问题autoredraw,它通过绑定 "onhashchange" 或 "onpopstate"事件 来检测变化后redirect(path)来加载js渲染页面, 而onclick后它会自动渲染一次本页面,所以onclick是一个route重定向的命令, 在内存较小的手机,有可能会本页面的render比重定向的render慢,导致本页面不跳转, 目前解决方案自己新添加util.redraw()方法里延时处理
  1. util.redraw = function(){
  2. setTimeout(function(){
  3. m.redraw();
  4. },100);
  5. };

增加了honclick事件,点击不重新渲染redraw本页面

2.auto focus问题, 在做搜索功能时,进入搜索页面,手机键盘自动弹出,异步加载文件或者延时el.focus()后只获取焦点,键盘不弹出,页面是按需加载模块js的,所以导致第一次进入搜索页面键盘不能弹出, 解决方案:把serachApp.js 这个模块合并到indexApp.js这个文件中,不异步加载解决。

  1. m('input.searchApp-input', {
  2. config: function(el, isInit, context) {
  3. if(!isInit){
  4. el.focus();
  5. }
  6. },
  7. type: 'search',
  8. value: ctrl.typingSearchKey(),
  9. oninput: ctrl.searchInputInput.bind(ctrl),
  10. onkeyup: ctrl.searchInputKeyup.bind(ctrl),
  11. placeholder: '搜索位置/酒店名称'
  12. })

3.在定时拉取聊天数据时, 先使用了setInterval, 3s拉取一次, 发现app在实现时,退出打开的聊天webView,回到主页面,聊天webView里的setInterval没有清楚,解决方案,用css3的transition动画代替setInterval

  1. html:
  2. <div id="transitionTimeout"></div>
  3. css:
  4. #transitionTimeout{height: 0; overflow: hidden; opacity: 1; -webkit-transition: 3s ease opacity;}
  5. #transitionTimeout.hide{opacity:0;}
  6. js:
  7. /**
  8. * 每隔 3 秒钟刷新一次消息
  9. */
  10. function initPullTimer(){
  11. $('#transitionTimeout').on('webkitTransitionEnd', function() {
  12. $(this).toggleClass('hide');
  13. pull();
  14. });
  15. $('#transitionTimeout').addClass('hide');
  16. }

4.单页面的拆分:在列表页面做分页后,点击进入详情,然后回退到列表页面,一般浏览器会保留在之前列表页面的位置。但在航班管家的app内发现回直接回退到顶部,无法保留这个位置。解决方案:
单页面的拆分,新建一个createWebView来显示详情,代码结构都不变,只是指定默认的入口文件修改

  1. util.openWindow = function(url, flag) {
  2. if (util.PLATFORM.CURRENT == util.PLATFORM.HBGJ || (flag && util.PLATFORM.CURRENT == util.PLATFORM.GTGJ) ) {
  3. _nativeAPI.invoke('createWebView', {
  4. url: url
  5. });
  6. } else {
  7. window.location.href = url;
  8. }
  9. };
  10. 主页面文件入口:
  11. window.defaultMain = '';
  12. 详情页面文件入口:
  13. window.defaultMain = 'detail/:hotelId/:currentDate/:stayDayCount';

5.http请求文件遭遇拦截问题,在手机移动网络状态下,出现了移动强行插入广告问题。解决方案:改用https的请求文件

6.Promise的使用,越来越多的使用回调了。 mithril使用了大量的闭包,可以使用chrome开发工具Profiles的Collect Javascript CPU Profile 来查看

  1. 核心代码:
  2. var deferred = m.deferred();
  3. return deferred.promise;
  4. 例子:
  5. m.loadRoute = function(route) {
  6. var deferred = m.deferred();
  7. if (__realRoutes[route].ctrl === null) {
  8. loadScript(routesCache[route].path, function() {
  9. realRoutes[route] = window[namespace][routesCache[route].name];
  10. deferred.resolve(window[namespace][routesCache[route].name]);
  11. });
  12. } else {
  13. deferred.resolve(window[namespace][routesCache[route].name]);
  14. }
  15. return deferred.promise;
  16. };
  17. 调用:
  18. m.loadRoute('cityFilter').then(function(cityFilter) {});

Mithril载入页面的3个方法

默认:m.route(dom, home, realRoutes);
单页面:m.module(document.getElementById('login'), fstar.verifyApp);
m.render(document.getElementById('main2'), myActivity.view(myActivity.controller()));

版本控制gitHub

https://github.com/huoli-njy/fstar_mithril.git

Worktile

团队协作办公工具选用了Worktile(https://worktile.com/teams/ff731115e7274c7f81de22493a42c690)

sketch

UI交互使用sketch(http://www.sketchcn.com/)来制作

七牛云存储

服务器储存选用了 七牛云存储(http://www.qiniu.com/),有windows版自动化上传工具

.sh命令行

前端使用debug.sh 和 publish.sh 执行命令行文件 来在测试服务器和七牛上发布文件

nproxy代理

前端使用nproxy(如windows的Fiddler)来调试线上前端代码

studdy 做模拟JSON数据

  1. - request:
  2. method: GET
  3. url: ^/rest/mash?$
  4. response:
  5. headers:
  6. content-type: application/json
  7. file: mash.json
  8. latency : 300
  9. - request:
  10. method: GET
  11. url: ^/rest/messages?$
  12. response:
  13. headers:
  14. content-type: application/json
  15. file: messages.json
  16. latency : 3400
  17. # sudo stubby -d rest/config.yaml
  18. # http://localhost:8882/rest/messages
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注