目 录 | |
---|---|
1 | 热点新闻APP界面认识 |
2 | 一步步搭建应用 |
3 | 热点新闻内容代码详解 |
4 | APP打包及真机查看 |
一、热点新闻APP界面认识
上一章我们大概了解了mui的概念,以及他提供的强大的工具和框架,这一章我们用一个简单的例子来快速构建我们的APP应用
我们要构建的应用非常简单,就是仿一个简单的新闻类的APP,其中包含了2个界面,一个新闻列表页(可以上拉加载更多、下拉刷新),一个新闻详情页,界面如下:
我们已经知道了我们的目标,接下来我们就要开始创建工程了。
二、一步步搭建应用
打开开发工具“HBuilder”,在左侧工程栏中“右键”-“新建”-“移动APP”项目,输入应用名称“News”,默认选择空模版,点击完成,如下图
建好工程后,按照下图的方式创建好相应的目录,同时导入mui相关的js,css等,其中工程目录的一些说明如下图
PS:此工程已经放置于gogs上,有兴趣的同学可以去下载
按照上图中的目录建设完成,我们可以进行相应的界面内容开发
三、APP内容代码详解
A、数据源
百度API Store中有许多的新闻接口,我们就选择使用百度的API接口,如下code段:
$.ajax({
type: "GET",
url: "http://apis.baidu.com/showapi_open_bus/channel_news/search_news?channelId=" + selectedType + "&page=" + pageObj[selectedType],
beforeSend: function(request) {
request.setRequestHeader("apikey", "7f6dfa583fe9406f73f2830a5c2fb99c");
},
success: function(d) {
if(d.showapi_res_body.pagebean) {
var newsArray = d.showapi_res_body.pagebean.contentlist;
var singleModel = '<div class="news-item">' + $('.news-item-model-single').html() + '</div>';
var multiModel = '<div class="news-item">' + $('.news-item-model-multi').html() + '</div>';
var textModel = '<div class="news-item">' + $('.news-item-model-none').html() + '</div>';
for(var i = 0; i < newsArray.length; i++) {
//判断新闻是否已经显示过
if(refreshArt.indexOf(newsArray[i].title) == -1) {
//设置当前新闻格式,无图片格式、单图片格式、多图片格式
var model, type;
if(!newsArray[i].havePic) {
model = textModel;
type = 'text';
} else {
if(newsArray[i].imageurls.length > 1) {
model = multiModel;
type = 'multi';
} else {
model = singleModel;
type = 'single';
}
}
refreshArt.push(newsArray[i].title);
detailObj[selectedType].push(newsArray[i]);
$('.' + newId).append(model);
$('.' + newId).find('.news-item:last').attr('iden', preLength + i);
$('.' + newId).find('.news-item:last').find('.news-title').html(newsArray[i].title);
//设置图片
if(type == 'single') {
$('.' + newId).find('.news-item:last').find('.news-image img').attr('src', newsArray[i].imageurls[0].url);
} else {
for(var j = 0; j < (newsArray[i].imageurls.length > 3 ? 3 : newsArray[i].imageurls.length); j++) {
$('.' + newId).find('.news-item:last').find('.news-image-multi').find('.flex-element-no-padding:eq(' + j + ')').html('<img src="' + newsArray[i].imageurls[j].url + '"/>')
}
}
$('.' + newId).find('.news-item:last').find('.author-name').html(newsArray[i].source);
$('.' + newId).find('.news-item:last').find('.pub-date').html(newsArray[i].pubDate);
//绑定新闻点击事件,点击后进入新闻详情页面
$('.' + newId).find('.news-item:last').on('tap', function() {
storage.setItem('newsContent', JSON.stringify(detailObj[selectedType][$(this).attr('iden')]));
_tl.toUrl('newsDetail.html');
})
}
}
} else {
mui.toast('加载失败,请稍后尝试');
}
//设置上拉、下拉结束标志
mui('#pullrefresh').pullRefresh().endPulldownToRefresh(); //refresh completed
mui('#pullrefresh').pullRefresh().endPullupToRefresh(false);
}
});
这一段的作用则是从百度API中抓取数据展示至界面中
B. List界面由外部的框架页面和内部列表界面
外部框架页
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#fc3434">
<link rel="stylesheet" href="../css/mui.min.css" />
<link rel="stylesheet" href="../css/common/base.css" />
<link rel="stylesheet" href="css/index.css" />
<title></title>
<script type="text/javascript" src="../js/common/jquery.js"></script>
<script type="text/javascript" src="../js/common/flexible/flexible.js"></script>
<script type="text/javascript" src="../js/mui.min.js"></script>
<style>
.android-body .mui-pull-top-pocket{top:1.1rem;margin-top:1.1rem;display: block;height: 1.2rem !important;line-height: 1.2rem;background: #f1f1f1;}
.android-body .mui-pull{top: 0.1rem;}
</style>
</head>
<body>
<header class="mui-bar mui-bar-nav">
<h1 id="title" class="mui-title">热点新闻</h1>
<div class="news-types">
<div class="news-types-wrap">
</div>
</div>
</header>
<script>
var storage = window.localStorage;
var selectType;
function loadChannel() {
$.getJSON('../data/chanel.json', function(d) {
$('.news-types-wrap').html('');
for(var i = 0; i < d.channelList.length; i++) {
var ar = d.channelList[i];
$('.news-types-wrap').append('<span type="' + ar.channelId + '">' + ar.name + '</span>');
}
$('.news-types-wrap').find('span:first').addClass('selected');
storage.setItem('selectType', $('.selected').attr('type'));
//绑定点击事件
$('.news-types span').on('tap', function() {
$('.selected').removeClass('selected');
$(this).addClass('selected');
storage.setItem('selectType', $(this).attr('type'));
})
})
}
mui.init({
statusBarBackground: '#fc3434',
subpages: [{
url: 'index.html',
id: 'index',
styles: {
top: parseInt(2.3 * parseInt($('html').css('font-size'))) + 'px', //mui标题栏默认高度为45px;
bottom: '0px' //默认为0px,可不定义;
}
}]
});
mui.plusReady(function() {
//仅支持竖屏显示
plus.screen.lockOrientation("portrait-primary");
if(mui.os.android){
$('body').addClass('android-body');
}
})
$(function() {
loadChannel();
})
</script>
</body>
</html>
外部框架页定义了,新闻的种类列表,同时使用了mui.init,定义了子页面index.html作为内容列表的提供页
内容列表页index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#fc3434">
<link rel="stylesheet" href="../js/common/swiper/css/swiper.min.css" />
<link rel="stylesheet" href="../css/mui.min.css" />
<link rel="stylesheet" href="css/index.css" />
<title></title>
<script type="text/javascript" src="../js/common/jquery.js"></script>
<script type="text/javascript" src="../js/common/flexible/flexible.js"></script>
<script type="text/javascript" src="../js/common/swiper/js/swiper.jquery.min.js"></script>
<script type="text/javascript" src="../js/common/circle-progress.js"></script>
<script type="text/javascript" src="../js/common/tools.js"></script>
<script type="text/javascript" src="../js/mui.min.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</head>
<body>
<div class="x-panel-content-full">
<!--下拉刷新容器-->
<div id="pullrefresh" class="mui-content mui-scroll-wrapper">
<div class="mui-scroll">
<!--数据列表-->
<ul class="mui-table-view mui-table-view-chevron">
</ul>
</div>
</div>
</div>
<div class="news-item-model-single hide">
<div class="flex-div">
<div class="news-title flex-element3-no-padding">当你最穷的时候,这样做,不成百万富翁至少也是土豪!</div>
<div class="news-image flex-element-no-padding">
<img class="img-01" src="http://05.imgmini.eastday.com/mobile/20161011/20161011123754_349328718cfee5b4d04cd614f1033e3a_1_mwpm_03200403.jpeg" />
</div>
</div>
<div class="news-other flex-div">
<div class="flex-element-no-padding author-name">中国企业家俱乐部</div>
<div class="flex-element-no-padding pub-date text-right">2016-10-11 12:37</div>
</div>
</div>
<div class="news-item-model-multi hide">
<div class="news-title">当你最穷的时候,这样做,不成百万富翁至少也是土豪!</div>
<div class="news-image-multi flex-div">
<div class="flex-element-no-padding">
</div>
<div class="flex-element-no-padding">
</div>
<div class="flex-element-no-padding">
</div>
</div>
<div class="news-other flex-div">
<div class="flex-element-no-padding author-name">中国企业家俱乐部</div>
<div class="flex-element-no-padding pub-date text-right">2016-10-11 12:37</div>
</div>
</div>
<div class="news-item-model-none hide">
<div class="news-title">当你最穷的时候,这样做,不成百万富翁至少也是土豪!</div>
<div class="news-other flex-div">
<div class="flex-element-no-padding author-name">中国企业家俱乐部</div>
<div class="flex-element-no-padding pub-date text-right">2016-10-11 12:37</div>
</div>
</div>
</body>
</html>
内容列表是一个常规的html5界面,定义了一个上拉下拉刷新的容器,我们来看看index的js定义
index.js
var storage = window.localStorage;
var _tl = getTLInstance();
var detailObj = {}, //新闻内容
pageObj = {}, //每个模块的分页数
transObj = {}; //每个模块的滚动条位置
var refreshArt = []; //存储新闻标题的临时数组,防止新闻重复出现
//初始化加载栏
mui.init({
pullRefresh: {
container: '#pullrefresh',
up: {
contentrefresh: '正在加载更多...',
callback: doUpLoading
},
down: {
contentrefresh: '正在刷新...',
callback: doDownLoading
}
}
});
这一部分定义了此页面拥有上拉和下拉的功能,并且指定了相应的容器,同时指定了上拉和下拉的回调函数doUpLoading、doDownLoading
$(function() {
//延迟加载,等待WebView初始化完成
if(mui.os.plus) {
mui.plusReady(function() {
setTimeout(function() {
triggerUp();
tempSolution();
}, 500);
});
} else {
mui.ready(function() {
setTimeout(function() {
triggerUp();
tempSolution();
}, 100);
});
}
//纪录每个模块的滚动条变化
setTimeout(function() {
if(mui.os.android) {
//Android不识别webkitTransform,因此还是使用的滚动条
$(window).scroll(function(e) {
transObj[storage.getItem('selectType')] = document.body.scrollTop;
})
} else {
//IOS、Html识别webkitTransform
$('.mui-scroll').on('touchend touchcancel', function(e) {
var str = document.querySelector('.mui-scroll').style.webkitTransform;
transObj[storage.getItem('selectType')] = $.trim(str.substring(str.indexOf(',') + 1, str.lastIndexOf(',')));
if(parseInt(transObj[storage.getItem('selectType')]) > 0) {
transObj[storage.getItem('selectType')] = '0px';
}
})
}
}, 2100)
})
这一部分定义了页面初始化时要做的事情:触发一个上拉刷新加载内容、同时绑定滚动事件记录当前频道的阅读位置并且存储起来
//触发下拉刷新事件
function triggerUp() {
var selectedType = storage.getItem('selectType');
pageObj[selectedType] = 1;
var newId = 'news-list-' + selectedType;
$('.news-list').hide();
//模块初始化后保留上次的加载纪录,避免切换时再次刷新,提高友好度
if(!$('.' + newId).html()) {
$('.mui-table-view').append('<div class="news-list ' + newId + '"><div></div></div>');
mui('#pullrefresh').pullRefresh().pulldownLoading();
} else {
$('.' + newId).show();
//自动定位到每个模块的滚动条位置
if(mui.os.android) {
document.body.scrollTop = transObj[selectedType];
} else {
mui('.mui-scroll-wrapper').scroll().scrollTo(0, parseInt(transObj[selectedType]), 100);
}
}
}
//下拉刷新操作
function doDownLoading() {
pageObj[storage.getItem('selectType')] = 1;
loadNews();
}
//上拉加载更多操作
function doUpLoading() {
pageObj[storage.getItem('selectType')]++;
loadNews();
}
这一段定义了函数上拉下拉要做的事情;其中triggerUp做了2件事情:1、当点击的频道为第一次加载时,从服务端获取数据;2、当点击的频道为已加载时,自动定位到上次阅读的位置,其中loadNews()为第一段ajax获取数据的部分
//临时解决方案,定时扫描type值,如发生变化则执行刷新操作(IOS、Android无法调用iframe方法)
var lastType;
function tempSolution() {
setInterval(function() {
if(!lastType) {
lastType = storage.getItem('selectType');
} else {
if(lastType != storage.getItem('selectType')) {
lastType = storage.getItem('selectType');
triggerUp();
}
}
}, 300)
}
C、新闻详情页,由于百度的接口返回的列表中包含了新闻的主体内容,因此在点击新闻时,直接将内容传入展示
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#fc3434">
<link rel="stylesheet" href="../js/common/swiper/css/swiper.min.css" />
<link rel="stylesheet" href="../css/mui.min.css" />
<link rel="stylesheet" href="css/newsDetail.css" />
<title></title>
<script type="text/javascript" src="../js/common/jquery.js"></script>
<script type="text/javascript" src="../js/common/flexible/flexible.js"></script>
<script type="text/javascript" src="../js/common/swiper/js/swiper.jquery.min.js"></script>
<script type="text/javascript" src="../js/common/circle-progress.js"></script>
<script type="text/javascript" src="../js/common/tools.js"></script>
<script type="text/javascript" src="../js/mui.min.js"></script>
<script type="text/javascript" src="js/newsDetail.js"></script>
</head>
<body>
<div class="x-panel-top">
<div class="x-panel-top-left" onclick="mui.back()">
<span class="mui-icon mui-icon-back"></span>
</div>
<div class="x-panel-top-center">
<div class="x-title-bar">
热点新闻
</div>
</div>
<div class="x-panel-top-right">
</div>
</div>
<div class="x-panel-content">
<article id="J_article" class="J-article article">
<div id="title">
<div class="article-title">
<h1 class="title"></h1>
</div>
<div class="article-src-time">
<span class="src"></span>
</div>
</div>
<div id="content" class="J-article-content article-content" data-pswp-uid="1">
</div>
</article>
</div>
</body>
</html>
var storage = window.localStorage;
var _tl = getTLInstance();
var _plus;
mui.plusReady(function() {
_plus = plus;
})
$(function() {
var news = JSON.parse(storage.getItem('newsContent'));
$('.title').html(news.title);
$('.src').html(news.pubDate+' 来源:'+news.source);
var newsContent = news.allList;
for(var i=0;i<newsContent.length;i++){
if(typeof(newsContent[i]) == 'string'){
$('.article-content').append('<p class="section txt">'+newsContent[i]+'</p>');
}else{
$('.article-content').append('<figure class="section img"><a class="img-wrap"><img src="'+newsContent[i].url+'"></a></figure>');
}
}
})