AppCan Hybrid 跨平台混合开发之天气预报
之前做iOS移动开发好几年,客观的说原生App 开发在加载效率和用户操作体验上确实比混合开发有先天的优势。但同时开发、学习成本也很高,适配也非常棘手。经过对比Flutter、React Native等跨平台混合开发,今天我们得主人公AppCan以学习成本低、门槛低、增量更新备受青睐。主要是使用的H5 + CSS3 + JS + MVVM的搭配组合,来实现我们得项目。并且有丰富的模板和界面可视化的操作以及热更新来提升开发效率。下文主要是以天气预报作为学习探索的入口,一窥AppCan的乾坤(AppCan官网:http://www.appcan.cn/)。本案例官网也有不过不完整,基本跑不起来。
天气预报Demo 主要分为两个页面城市列表(index.html)和查看该城市未来五天的天气详情数据(details.html),天气数据采用的聚合Api,一睹为快先看看整体效果图:
城市列表首页(index.html参考代码:
<!DOCTYPE html>
<html class="um landscape min-width-240px min-width-320px min-width-480px min-width-768px min-width-1024px">
<head>
<title>天气</title>
<meta charset="utf-8">
<meta name="viewport" content="target-densitydpi=device-dpi, width=device-width, initial-scale=1, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" href="css/fonts/font-awesome.min.css">
<link rel="stylesheet" href="css/ui-box.css">
<link rel="stylesheet" href="css/ui-base.css">
<link rel="stylesheet" href="css/ui-color.css">
<link rel="stylesheet" href="css/appcan.icon.css">
<link rel="stylesheet" href="css/appcan.control.css">
<link rel="stylesheet" href="css/index.css">
</head>
<body class="um-pv" ontouchstart>
<!--heade开始-->
<div class="uh bc-head ubb bc-border" data-control="HEADER" id="Header">
<div class="ub">
<h1 class="ut ub-f1 ulev-3 ut-s tx-c" tabindex="0">天气城市列表</h1>
</div>
</div>
<!--heade结束-->
<div class="" data-control="CONTENT" id="ScrollContent">
<component data-import="index_content.html"></component>
</div>
<!--footer开始-->
<div id="footer" class="uinn-z1">
<div class="tx-c t-93 ulev0 ufm1">www.gomro.cn</div>
<div class="tx-c t-93 ulev-4 umar-at1">固买供应链管理有限公司</div>
</div>
<!--footer结束-->
<!-- Js -->
<script src="js/appcan.js"></script>
<script src="js/appcan.control.js"></script>
<script src="js/appcan.listview.js"></script>
<script src="js/template.import.js"></script>
</body>
</html>
城市列表首页-内容页(index_content.html)参考代码:
<div data-component="indexContent">
<!-- 主体内容 -->
<div class="city-list">
</div>
<script>
debugger
var lv = appcan.listview({
selector:".city-list",
hasIcon:true,
hasAngle:true,
});
//初始数据
lv.set([
{
"title": "上海",
"icon": "./css/res/appcan_s.png"
},
{
"title": "北京",
"icon": "./css/res/appcan_s.png"
},
{
"title": "天津",
"icon": "./css/res/appcan_s.png"
},
{
"title": "重庆",
"icon": "./css/res/appcan_s.png"
},
{
"title": "深圳",
"icon": "./css/res/appcan_s.png"
}
]
);
/** 绑定支持的城市 */
function bindWeatherCitys(){
appcan.window.openToast({
msg:"加载城市数据...",
duration:0,
position:5,
type:0
});
var weatherUrl = "http://apis.juhe.cn/simpleWeather/cityList?key=d32a75d4ad0a174b78f9d4f932773913";
console.log(weatherUrl);
appcan.request.ajax({
url:weatherUrl,
type:'GET',
dataType:'json',
success:function(data){
if(data.error_code != 0){
alert(data.reason);
}
else{
var weatherDatas = data.result;
//重新组合数据
var arrCitys = new Array();
weatherDatas.forEach(function(v,i){
arrCitys.push(
{
title:v.district,
icon:"./css/res/appcan_s.png"
}
);
});
lv.set(arrCitys);
}
appcan.window.closeToast();
},
});
}
/** 查看详情 */
function openDetail(city) {
if(appcan.detect.os.phone)return;
appcan.openWinWithUrl('details','details.html');
appcan.locStorage.val('city',city);
}
/** 列点击绑定事件 */
lv.on('click',function(ele,obj,subobj){
console.log(obj.title);
openDetail(obj.title);
});
appcan.ready(function(){
bindWeatherCitys();
});
</script>
</div>
对应城市未来5天天气详情(details.html)参考代码:
<!DOCTYPE html>
<html class="um landscape min-width-240px min-width-320px min-width-480px min-width-768px min-width-1024px">
<head>
<title>天气详情</title>
<meta charset="utf-8">
<meta name="viewport" content="target-densitydpi=device-dpi, width=device-width, initial-scale=1, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" href="css/fonts/font-awesome.min.css">
<link rel="stylesheet" href="css/ui-box.css">
<link rel="stylesheet" href="css/ui-base.css">
<link rel="stylesheet" href="css/ui-color.css">
<link rel="stylesheet" href="css/appcan.icon.css">
<link rel="stylesheet" href="css/appcan.control.css">
<link rel="stylesheet" href="css/index.css">
</head>
<body class="" ontouchstart>
<div class="bc-bg" tabindex="0" data-control="PAGE" id="Page">
<!--heade开始-->
<div class="uh bc-head ubb bc-border" data-control="HEADER" id="Header">
<div class="ub">
<!-- 返回按钮开始 -->
<div class="nav-btn" id="nav-left">
<div class="fa fa-1g ub-img1 fa-angle-left fa-2x"></div>
</div>
<h1 class="ut ub-f1 ulev-3 ut-s tx-c" tabindex="0">
<span class="detail-title">天气详情</span>
</h1>
<!-- 分享 -->
<div class="nav-btn" id="nav-right">
<div class="ub-img1 icon-share ulev2"></div>
</div>
</div>
</div>
<!--heade结束-->
<div class="" data-control="CONTENT" id="ScrollContent">
<component data-import="details_content.html"></component>
</div>
<!--footer开始-->
<div id="footer" class="uinn-z1">
<div class="tx-c t-93 ulev0 ufm1">www.gomro.cn</div>
<div class="tx-c t-93 ulev-4 umar-at1">固买供应链管理有限公司</div>
</div>
<!--footer结束-->
</div>
<!-- Js -->
<script src="js/appcan.js"></script>
<script src="js/appcan.control.js"></script>
<script src="js/appcan.listview.js"></script>
<script src="js/template.import.js"></script>
</body>
</html>
对应城市未来5天天气详情-内容页(details_content.html)参考代码:
<div data-component="detailContent">
<style>
.line1 {
-webkit-line-clamp: 3;
}
</style>
<!--content开始 -->
<div class="city-list">
</div>
<!--content结束 -->
<!--天气模板 -->
<script type="text/template" id="weather-tmp">
<div class="day">
<span class="temperature"><%-weather_data.temperature%></span>
<div>
<span><%-weather_data.direct%></span>
<span><%-weather_data.weather%></span>
</div>
<span class="weather-pic">
<!-- <img src="<%-weather_data.dayPictureUrl%>" /><br> -->
<span><%-weather_data.date%></span>
</span>
</div>
</script>
<script language="JavaScript" type="text/javascript">
debugger
/*返回*/
appcan.button('.nav-btn','btn-act',function(){
appcan.window.close(-1);
});
//更新天气函数,来更新天气数据
function updateForecast(weatherData){
//生成列表模板
var render = appcan.view.template($('#weather-tmp').html());
var weatherList = [];
//遍历并渲染列表
for (var i=0,len=weatherData.length; i < len; i++) {
var resObj = render({weather_data:weatherData[i]});
weatherList.push({
title:resObj
});
};
//创建listView
var lv = appcan.listview({
selector:'.city-list',
hasIcon:false,
hasAngle:false,
});
lv.set(weatherList);
}
//执行更新
function updateInfo(city){
//打开一个没有弹出框的toast
appcan.window.openToast({
msg:"加载天气数据...",
duration:0,
position:5,
type:0
});
var weatherUrl = "http://apis.juhe.cn/simpleWeather/query?city=" + city + "&key=d32a75d4ad0a174b78f9d4f932773913";
console.log(weatherUrl);
appcan.request.ajax({
url:encodeURI(weatherUrl),//含有中文必须编码
type:'GET',
dataType:'json',
success:function(data){
console.log(data);
if(data.error_code != 0){
alert(data.reason);
//临时测试数据
updateForecast([
{
"date": "2019-02-22",
"temperature": "1/7℃",
"weather": "小雨转多云",
"wid": {
"day": "07",
"night": "01"
},
"direct": "北风转西北风"
},
{
"date": "2019-02-23",
"temperature": "2/11℃",
"weather": "多云转阴",
"wid": {
"day": "01",
"night": "02"
},
"direct": "北风转东北风"
},
{
"date": "2019-02-24",
"temperature": "6/12℃",
"weather": "多云",
"wid": {
"day": "01",
"night": "01"
},
"direct": "东北风转北风"
},
{
"date": "2019-02-25",
"temperature": "5/12℃",
"weather": "小雨转多云",
"wid": {
"day": "07",
"night": "01"
},
"direct": "东北风"
},
{
"date": "2019-02-26",
"temperature": "5/11℃",
"weather": "多云转小雨",
"wid": {
"day": "01",
"night": "07"
},
"direct": "东北风"
}
]);
}
else{
var weatherDatas = data.result;
updateForecast(weatherDatas.future);
}
appcan.window.closeToast();
},
error:function(e){
appcan.window.closeToast();
console.log(e);
alert(e);
}
});
}
appcan.ready(function(){
appcan.initBounce();
var city = appcan.locStorage.val('city');
if(city == undefined || city == null || city == ""){
city = "上海";
}
$('.detail-title').html(city + '天气详情');
console.log("详情:"+city);
updateInfo(city);
});
</script>
</div>
结构很简单,功能也不复杂,主要是作为入门的练手学习之用。项目结构图稍后附议,如需源码或其他问题请留言沟通。谢谢!