Sencha Touch 2天气应用开发全流程指南
1. Sencha Touch 2天气应用开发环境搭建在开始构建天气应用之前我们需要先配置好Sencha Touch 2的开发环境。Sencha Touch是一个基于HTML5的移动应用框架特别适合开发跨平台的移动应用。1.1 安装Sencha CmdSencha Cmd是Sencha框架的配套命令行工具它提供了项目脚手架、代码压缩、打包等一系列功能。安装步骤如下从Sencha官网下载最新版Sencha Cmd运行安装程序Windows下是.exeMac下是.pkg安装完成后在终端/命令行验证安装sencha which配置环境变量如果需要注意Sencha Cmd需要Java运行环境(JRE)支持建议安装Java 8或更高版本。1.2 创建项目骨架使用Sencha Cmd创建新项目sencha -sdk /path/to/sencha-touch-2 generate app WeatherApp ./WeatherApp这个命令会使用指定路径的Sencha Touch 2 SDK创建一个名为WeatherApp的应用在当前目录下生成WeatherApp文件夹作为项目根目录项目结构说明WeatherApp/ ├── app/ # 应用代码 ├── resources/ # 静态资源 ├── sdk/ # Sencha Touch框架 ├── app.json # 应用配置 └── index.html # 入口文件2. 天气应用UI界面设计2.1 主界面布局Sencha Touch使用MVC架构我们先创建主视图。在app/view目录下创建Main.jsExt.define(WeatherApp.view.Main, { extend: Ext.tab.Panel, xtype: main, requires: [ WeatherApp.view.weather.Current, WeatherApp.view.weather.Forecast ], config: { tabBarPosition: bottom, items: [{ xtype: currentweather, title: 当前天气, iconCls: home },{ xtype: forecastweather, title: 预报, iconCls: calendar }] } });2.2 当前天气视图创建app/view/weather/Current.jsExt.define(WeatherApp.view.weather.Current, { extend: Ext.Panel, xtype: currentweather, config: { layout: vbox, items: [{ xtype: component, cls: weather-header, html: div classlocation当前位置/div div classdate{date}/div, flex: 1 },{ xtype: component, cls: weather-main, html: div classtemp{temp}°C/div div classconditions{conditions}/div, flex: 2 },{ xtype: component, cls: weather-details, html: table trtd湿度/tdtd{humidity}%/td/tr trtd风速/tdtd{windSpeed} km/h/td/tr /table, flex: 1 }] } });2.3 天气预报视图创建app/view/weather/Forecast.jsExt.define(WeatherApp.view.weather.Forecast, { extend: Ext.dataview.DataView, xtype: forecastweather, config: { scrollable: true, cls: forecast-list, itemTpl: [ div classforecast-day{day}/div, div classforecast-temp{high}°/{low}°/div, div classforecast-conditions{conditions}/div ], store: Forecast } });3. 数据模型与API集成3.1 天气数据模型创建app/model/Weather.jsExt.define(WeatherApp.model.Weather, { extend: Ext.data.Model, config: { fields: [ {name: location, type: string}, {name: date, type: date}, {name: temp, type: float}, {name: conditions, type: string}, {name: humidity, type: int}, {name: windSpeed, type: float} ] } });创建app/model/Forecast.jsExt.define(WeatherApp.model.Forecast, { extend: Ext.data.Model, config: { fields: [ {name: day, type: string}, {name: high, type: int}, {name: low, type: int}, {name: conditions, type: string} ] } });3.2 天气API服务我们将使用OpenWeatherMap的免费API。首先注册获取API key。创建app/store/Current.jsExt.define(WeatherApp.store.Current, { extend: Ext.data.Store, config: { model: WeatherApp.model.Weather, autoLoad: true, proxy: { type: ajax, url: http://api.openweathermap.org/data/2.5/weather, extraParams: { appid: YOUR_API_KEY, units: metric, lang: zh_cn }, reader: { type: json, rootProperty: , transform: function(data) { return { location: data.name, date: new Date(data.dt * 1000), temp: data.main.temp, conditions: data.weather[0].description, humidity: data.main.humidity, windSpeed: data.wind.speed }; } } } } });创建app/store/Forecast.jsExt.define(WeatherApp.store.Forecast, { extend: Ext.data.Store, config: { model: WeatherApp.model.Forecast, autoLoad: true, proxy: { type: ajax, url: http://api.openweathermap.org/data/2.5/forecast/daily, extraParams: { appid: YOUR_API_KEY, units: metric, cnt: 7, lang: zh_cn }, reader: { type: json, rootProperty: list, transform: function(data) { var days [周日,周一,周二,周三,周四,周五,周六]; return Ext.Array.map(data.list, function(item) { var date new Date(item.dt * 1000); return { day: days[date.getDay()], high: item.temp.max, low: item.temp.min, conditions: item.weather[0].description }; }); } } } } });4. 控制器与业务逻辑4.1 主控制器创建app/controller/Main.jsExt.define(WeatherApp.controller.Main, { extend: Ext.app.Controller, config: { refs: { currentView: currentweather, forecastView: forecastweather }, control: { main: { activeitemchange: onTabChange } } }, onTabChange: function(tabPanel, newItem) { if (newItem.xtype currentweather) { this.refreshCurrent(); } else if (newItem.xtype forecastweather) { this.refreshForecast(); } }, refreshCurrent: function() { var store Ext.getStore(Current); store.load(); }, refreshForecast: function() { var store Ext.getStore(Forecast); store.load(); }, // 初始化时加载当前位置 init: function() { this.locateUser(); }, locateUser: function() { navigator.geolocation.getCurrentPosition( this.onGeolocationSuccess.bind(this), this.onGeolocationError.bind(this) ); }, onGeolocationSuccess: function(position) { var currentStore Ext.getStore(Current); var forecastStore Ext.getStore(Forecast); currentStore.getProxy().setExtraParams({ lat: position.coords.latitude, lon: position.coords.longitude }); forecastStore.getProxy().setExtraParams({ lat: position.coords.latitude, lon: position.coords.longitude }); this.refreshCurrent(); this.refreshForecast(); }, onGeolocationError: function(error) { console.error(Geolocation error:, error); // 默认显示北京天气 var currentStore Ext.getStore(Current); var forecastStore Ext.getStore(Forecast); currentStore.getProxy().setExtraParams({ q: Beijing }); forecastStore.getProxy().setExtraParams({ q: Beijing }); this.refreshCurrent(); this.refreshForecast(); } });4.2 应用启动配置修改app.jsExt.application({ name: WeatherApp, requires: [ Ext.MessageBox ], views: [ Main, weather.Current, weather.Forecast ], models: [ Weather, Forecast ], stores: [ Current, Forecast ], controllers: [ Main ], icon: { 57: resources/icons/Icon.png, 72: resources/icons/Icon~ipad.png, 114: resources/icons/Icon2x.png, 144: resources/icons/Icon~ipad2x.png }, isIconPrecomposed: true, startupImage: { 320x460: resources/startup/320x460.jpg, 640x920: resources/startup/640x920.png, 768x1004: resources/startup/768x1004.png, 748x1024: resources/startup/748x1024.png, 1536x2008: resources/startup/1536x2008.png, 1496x2048: resources/startup/1496x2048.png }, launch: function() { // 销毁启动图片 Ext.fly(appLoadingIndicator).destroy(); // 初始化主视图 Ext.Viewport.add(Ext.create(WeatherApp.view.Main)); }, onUpdated: function() { Ext.Msg.confirm( 应用更新, 这个应用已经更新。是否重新加载, function(buttonId) { if (buttonId yes) { window.location.reload(); } } ); } });5. 样式美化与主题定制5.1 基础样式创建resources/css/app.css/* 通用样式 */ .x-tabbar { background-color: #1976D2 !important; } .x-tab { color: #fff !important; } .x-tab-active { background-color: #0D47A1 !important; } /* 当前天气样式 */ .weather-header { text-align: center; padding: 20px; background-color: #2196F3; color: white; } .weather-header .location { font-size: 1.5em; font-weight: bold; } .weather-header .date { font-size: 0.9em; opacity: 0.8; } .weather-main { text-align: center; padding: 30px; background-color: #64B5F6; color: white; } .weather-main .temp { font-size: 3em; font-weight: bold; } .weather-main .conditions { font-size: 1.2em; text-transform: capitalize; } .weather-details { padding: 20px; background-color: #BBDEFB; } .weather-details table { width: 100%; } .weather-details td { padding: 8px; border-bottom: 1px solid #E3F2FD; } /* 天气预报样式 */ .forecast-list .x-dataview-item { padding: 15px; border-bottom: 1px solid #E3F2FD; background-color: #E3F2FD; } .forecast-day { font-weight: bold; font-size: 1.1em; margin-bottom: 5px; } .forecast-temp { color: #1976D2; font-size: 1.2em; margin-bottom: 5px; } .forecast-conditions { color: #555; text-transform: capitalize; }5.2 主题颜色定制Sencha Touch使用SASS来管理主题样式。我们可以修改resources/sass/app.scss$base-color: #1976D2; $active-color: #0D47A1; $light-color: #BBDEFB; $highlight-color: #2196F3; import sencha-touch/default; import sencha-touch/default/all; // 自定义样式 include sencha-panel; include sencha-buttons; include sencha-sheet; include sencha-picker; include sencha-tabs; include sencha-toolbar; include sencha-toolbar-forms; include sencha-carousel; include sencha-indexbar; include sencha-list; include sencha-layout; include sencha-form; include sencha-msgbox; include sencha-loading-spinner; // 导入自定义CSS import ../css/app.css;6. 打包与发布6.1 测试与调试在开发过程中可以使用Sencha Cmd的内置web服务器进行测试sencha app watch这个命令会启动一个本地开发服务器监听文件变化并自动刷新浏览器提供实时编译和错误提示6.2 打包为原生应用Sencha Touch应用可以通过PhoneGap/Cordova打包为原生应用。首先安装Cordovanpm install -g cordova然后初始化Cordova项目sencha cordova init com.yourcompany.weatherapp WeatherApp修改app.json添加Cordova配置builds: { native: { packager: cordova, cordova: { config: { platforms: ios android, id: com.yourcompany.weatherapp } } } }构建原生应用sencha app build native6.3 平台特定配置iOS配置在config.xml中添加iOS特定配置platform nameios icon srcresources/icons/icon-60.png width60 height60 / icon srcresources/icons/icon-602x.png width120 height120 / icon srcresources/icons/icon-76.png width76 height76 / icon srcresources/icons/icon-762x.png width152 height152 / splash srcresources/splash/Default~iphone.png width320 height480/ splash srcresources/splash/Default2x~iphone.png width640 height960/ splash srcresources/splash/Default-Portrait~ipad.png width768 height1024/ splash srcresources/splash/Default-Portrait2x~ipad.png width1536 height2048/ /platformAndroid配置在config.xml中添加Android特定配置platform nameandroid icon srcresources/icons/icon-36-ldpi.png densityldpi / icon srcresources/icons/icon-48-mdpi.png densitymdpi / icon srcresources/icons/icon-72-hdpi.png densityhdpi / icon srcresources/icons/icon-96-xhdpi.png densityxhdpi / splash srcresources/splash/screen-ldpi-portrait.png densityport-ldpi/ splash srcresources/splash/screen-mdpi-portrait.png densityport-mdpi/ splash srcresources/splash/screen-hdpi-portrait.png densityport-hdpi/ splash srcresources/splash/screen-xhdpi-portrait.png densityport-xhdpi/ /platform6.4 构建发布版本iOS发布打开Xcode项目位于cordova/platforms/ios选择Product Archive在Organizer中选择Archive并点击Distribute App选择发布方式App Store或Ad HocAndroid发布生成签名密钥keytool -genkey -v -keystore weatherapp.keystore -alias weatherapp -keyalg RSA -keysize 2048 -validity 10000构建发布APKcordova build android --release -- --keystoreweatherapp.keystore --storePasswordyourpassword --aliasweatherappAPK文件位于cordova/platforms/android/app/build/outputs/apk/release7. 优化与进阶功能7.1 性能优化建议图片优化使用适当尺寸的图片考虑使用CSS3效果替代图片使用雪碧图减少HTTP请求数据缓存// 在store配置中添加缓存 proxy: { type: ajax, url: ..., noCache: false, timeout: 30000, reader: { type: json } }延迟加载// 只在需要时加载数据 Ext.Viewport.setActiveItem({ xtype: someview, loadData: true });7.2 添加城市搜索功能添加搜索视图 (app/view/Search.js)Ext.define(WeatherApp.view.Search, { extend: Ext.Panel, xtype: searchview, config: { layout: fit, items: [{ xtype: searchfield, placeHolder: 输入城市名称..., listeners: { action: onSearchExecute } },{ xtype: list, itemTpl: {name}, {country}, store: Cities }] } });添加城市模型 (app/model/City.js)Ext.define(WeatherApp.model.City, { extend: Ext.data.Model, config: { fields: [id, name, country] } });添加城市store (app/store/Cities.js)Ext.define(WeatherApp.store.Cities, { extend: Ext.data.Store, config: { model: WeatherApp.model.City, proxy: { type: ajax, url: http://api.openweathermap.org/data/2.5/find, extraParams: { appid: YOUR_API_KEY, type: like, sort: population, cnt: 10 }, reader: { type: json, rootProperty: list } } } });更新主控制器// 在refs中添加 searchView: searchview, // 在control中添加 searchview searchfield: { action: onSearchExecute }, // 添加新方法 onSearchExecute: function(field) { var query field.getValue(); var store Ext.getStore(Cities); store.getProxy().setExtraParams({ q: query }); store.load(); }7.3 添加天气图标下载天气图标集如Climacons添加到resources/images/weather更新Current视图html: div classtemp{temp}°C/div div classconditions{conditions}/div img srcresources/images/weather/{icon}.png classweather-icon更新transform函数transform: function(data) { var iconMap { 01d: clear-day, 01n: clear-night, // 其他天气代码映射... }; return { // 其他字段... icon: iconMap[data.weather[0].icon] || unknown }; }7.4 添加离线功能添加HTML5应用缓存清单 (manifest.appcache)CACHE MANIFEST # v1.0.0 CACHE: index.html app.json resources/css/app.css resources/images/weather/clear-day.png # 其他需要缓存的资源... NETWORK: *在index.html中添加html manifestmanifest.appcache添加离线检测// 在主控制器中添加 checkConnection: function() { var networkState navigator.connection.type; if (networkState Connection.NONE) { Ext.Msg.alert(离线模式, 您当前处于离线状态显示的是上次缓存的数据); // 加载本地缓存数据 } }8. 常见问题解决8.1 跨域请求问题在开发过程中可能会遇到API跨域请求被阻止的情况。解决方法使用JSONP代替AJAXproxy: { type: jsonp, url: http://api.openweathermap.org/..., callbackKey: callback }配置本地代理sencha app watch --proxy http://yourproxy:8080使用Cordova的白名单插件cordova plugin add cordova-plugin-whitelist然后在config.xml中添加access origin* / allow-navigation href* /8.2 样式不生效问题如果自定义样式没有生效检查是否正确编译了SASSsencha app build development是否在app.json中正确引用了CSScss: [ { path: resources/css/app.css, update: delta } ]是否使用了正确的CSS选择器Sencha Touch生成的组件有特定类名8.3 性能问题如果应用运行缓慢减少DOM复杂度使用虚拟列表处理大数据集避免频繁的重绘和布局使用硬件加速的CSS属性.x-container { -webkit-transform: translate3d(0,0,0); transform: translate3d(0,0,0); }8.4 内存泄漏Sencha Touch应用中常见的内存泄漏原因未正确销毁组件未移除事件监听器循环引用解决方法// 在销毁前移除监听器 destroy: function() { this.removeAllListeners(); this.callParent(); } // 使用弱引用 Ext.bind(function() { // 回调代码 }, this, null, true); // 最后一个参数true表示弱引用9. 测试与调试技巧9.1 使用Chrome开发者工具远程调试Android设备在Android设备上启用USB调试在Chrome中访问chrome://inspect选择你的设备进行调试模拟移动设备在Chrome开发者工具中点击手机图标选择设备型号和分辨率9.2 Sencha InspectorSencha官方提供的调试工具可以查看组件层次结构检查数据绑定监控事件实时修改属性安装npm install -g sencha-inspector使用sencha inspector9.3 日志记录使用Ext.log进行分级日志记录Ext.log({ msg: Something happened, level: warn, dump: someObject });配置日志级别Ext.Logger.setLevel(Ext.Logger.INFO);9.4 单元测试使用Sencha Test框架安装Sencha Testsencha package install sencha-test创建测试describe(WeatherApp.controller.Main, function() { var controller null; beforeEach(function() { controller Ext.create(WeatherApp.controller.Main); }); afterEach(function() { controller.destroy(); }); it(should have refs configured, function() { expect(controller.getRefs()).toBeDefined(); }); });运行测试sencha test run10. 项目扩展与进阶方向10.1 添加更多天气数据OpenWeatherMap API提供更多数据可以扩展应用显示紫外线指数降水概率能见度日出/日落时间10.2 实现推送通知使用Cordova插件实现天气预警推送cordova plugin add cordova-plugin-local-notification示例代码cordova.plugins.notification.local.schedule({ title: 天气预警, text: 即将有暴雨请做好准备, at: new Date(new Date().getTime() 3600) });10.3 集成地图显示使用Leaflet或Google Maps API显示天气地图添加Cordova插件cordova plugin add cordova-plugin-googlemaps创建地图视图Ext.define(WeatherApp.view.Map, { extend: Ext.Panel, initialize: function() { this.callParent(); var div document.createElement(div); div.style.width 100%; div.style.height 100%; this.element.dom.appendChild(div); var map plugin.google.maps.Map.getMap(div); map.animateCamera({ target: {lat: 39.9, lng: 116.4}, zoom: 10 }); } });10.4 添加分享功能使用社交分享插件cordova plugin add cordova-plugin-x-socialsharing示例代码window.plugins.socialsharing.share( 当前天气25°C晴朗, 天气分享, null, http://yourwebsite.com );10.5 实现主题切换允许用户在亮色/暗色主题间切换添加主题CSS.x-theme-dark { background-color: #333; color: #fff; } .x-theme-dark .weather-header { background-color: #0D47A1; }添加切换逻辑toggleTheme: function() { var body Ext.getBody(); if (body.hasCls(x-theme-dark)) { body.removeCls(x-theme-dark); localStorage.setItem(theme, light); } else { body.addCls(x-theme-dark); localStorage.setItem(theme, dark); } }初始化时读取设置init: function() { var theme localStorage.getItem(theme) || light; if (theme dark) { Ext.getBody().addCls(x-theme-dark); } }11. 项目部署与维护11.1 持续集成设置自动化构建流程创建Jenkinsfilepipeline { agent any stages { stage(Build) { steps { sh sencha app build production } } stage(Test) { steps { sh sencha test run } } stage(Deploy) { steps { sh ./deploy.sh } } } }配置Jenkins或Travis CI自动构建11.2 错误监控集成错误跟踪服务安装Sentry插件cordova plugin add cordova-plugin-sentry初始化Sentry.init({ dsn: YOUR_DSN, release: 1.0.0 }); // 捕获全局错误 window.onerror function(message, source, lineno, colno, error) { Sentry.captureException(error); };11.3 应用更新实现热更新机制配置app.jsonoutput: { base: ${workspace.build.dir}/${build.environment}, appCache: { enable: true, path: cache.appcache } }检查更新checkUpdate: function() { var appCache window.applicationCache; appCache.addEventListener(updateready, function() { if (confirm(新版本可用是否立即更新)) { window.location.reload(); } }); appCache.update(); }11.4 数据分析集成Google Analytics安装插件cordova plugin add cordova-plugin-google-analytics跟踪使用情况window.ga.startTrackerWithId(UA-XXXXX-YY); window.ga.trackView(Main Screen); window.ga.trackEvent(Navigation, Tab Change, Forecast);12. 项目总结与经验分享在完成这个Sencha Touch 2天气应用项目的过程中我积累了一些有价值的经验数据绑定是关键Sencha Touch的数据绑定机制非常强大正确使用可以大大简化代码。我发现将视图与store直接绑定而不是手动更新DOM能显著提高开发效率。性能优化要趁早移动设备的资源有限在开发初期就应该考虑性能问题。特别是列表视图一定要使用虚拟滚动infinite list处理大量数据。跨平台测试很重要不同平台iOS/Android和不同版本的浏览器内核表现可能有差异应该尽早进行多平台测试。插件选择要谨慎Cordova插件质量参差不齐选择时要查看更新频率、issue数量和社区反馈。我建议优先考虑官方维护的插件。错误处理要全面移动网络环境不稳定API调用失败是常态。完善的错误处理如重试机制、离线缓存能显著提升用户体验。主题系统很强大Sencha Touch的SASS主题系统允许深度定制UI但学习曲线较陡。建议先从小修改开始逐步掌握整个系统。命令行工具是利器Sencha Cmd提供的脚手架、构建和打包功能可以节省大量时间。熟练掌握这些工具能极大提高开发效率。文档和社区是宝库Sencha的官方文档非常全面遇到问题先查文档往往能快速找到解决方案。Sencha论坛也是一个很好的资源。这个天气应用项目展示了Sencha Touch 2的主要功能和开发模式但实际商业应用可能需要更多定制和优化。希望这篇教程能为你的Sencha Touch开发之旅提供一个良好的起点。