关于guide的研究
[6.0.0.201506290132]新增App首次启动欢迎页,也就是mui项目中examples/guide.html
APP启动流程:
- APP启动打开启动页面,也就是splashscreen,可以在manifest.html中设置自动关闭或者手动关闭:代码视图中plus下的splashscreen,autoclose值为false即需要手动关闭,值为true即自动关闭;
- 进入设置的入口页面webview;在入口页面或者入口页面的子webview即APP启动后就执行js的webview中判断APP是否为第一次启动。如何判断呢?使用localStorage,这个很简单就不说了;若不是第一次打开,则需要使用plus.navigator.closeSplashscreen()来关闭启动画面;若为第一次打开,则进入guide.html,在guide.html加载完后需要关闭启动画面;
- guide.html跳转至入口页面;
在MUI demo中,判断是否为第一次启动APP的代码在入口页面index.html的子页面list.html中;
看demo时发现若是ios则设置全屏(显示顶部状态栏),我测试了下,ios和安卓都可以全屏,不知道hbcui1984为何这样写,我看了下好几个安卓APP的guide都不是全屏的;
关于在使用过程中出现的问题:
1.有的娃娃做出来之后表现是看到启动画面后先看到入口页面,然后才看到guide页面,这是因为未正确设置启动画面的关闭;
若有问题,请在评论中指出。
by 鑫花璐放
[6.0.0.201506290132]新增App首次启动欢迎页,也就是mui项目中examples/guide.html
APP启动流程:
- APP启动打开启动页面,也就是splashscreen,可以在manifest.html中设置自动关闭或者手动关闭:代码视图中plus下的splashscreen,autoclose值为false即需要手动关闭,值为true即自动关闭;
- 进入设置的入口页面webview;在入口页面或者入口页面的子webview即APP启动后就执行js的webview中判断APP是否为第一次启动。如何判断呢?使用localStorage,这个很简单就不说了;若不是第一次打开,则需要使用plus.navigator.closeSplashscreen()来关闭启动画面;若为第一次打开,则进入guide.html,在guide.html加载完后需要关闭启动画面;
- guide.html跳转至入口页面;
在MUI demo中,判断是否为第一次启动APP的代码在入口页面index.html的子页面list.html中;
看demo时发现若是ios则设置全屏(显示顶部状态栏),我测试了下,ios和安卓都可以全屏,不知道hbcui1984为何这样写,我看了下好几个安卓APP的guide都不是全屏的;
关于在使用过程中出现的问题:
1.有的娃娃做出来之后表现是看到启动画面后先看到入口页面,然后才看到guide页面,这是因为未正确设置启动画面的关闭;
若有问题,请在评论中指出。
by 鑫花璐放
WebSQL Demo 给大家参考
初学,发现没有WebSQL的资料(其实google 有很多), 于是写了一个Demo练手,也给没用过的一个参考吧。
WebSQL官方文档在此
发现Sqlite 没有删除某条记录的功能... 只能整表删除,谁知道怎么删除某一条记录吗?
加一个别人写的Html5SQL helper
html5sql
DEMO 在此
初学,发现没有WebSQL的资料(其实google 有很多), 于是写了一个Demo练手,也给没用过的一个参考吧。
WebSQL官方文档在此
发现Sqlite 没有删除某条记录的功能... 只能整表删除,谁知道怎么删除某一条记录吗?
加一个别人写的Html5SQL helper
html5sql
DEMO 在此
增量升级
增量升级的问题
增量、差量升级是H5的一个优势,现在被越来越多的引用采用。但是在使用H5 的增量升级的时候遇到一个问题。纠结我很长时间一直在找解决方案,而且严重影响了用户体验。
我遇到最主要的问题是:
当APP启动是出现升级页面,用户点击增量升级后不重新启动APP。
如果我们的页面中存在父子webview的时候,这个时候有一些业务webview在显示的时候会发现父webview丢失了,导致用户体验直线下降,正常业务无法走通。
在尝试了很多方法后找到了一个解决方案。目前测试下来一切正常,但是可能测试的方法不全面。希望提出来对大家有所帮助
解决方案
其实解决方法很简单,就是关闭所有webview,然后再执行plus.runtime.restart();。下面是我的代码
var wvs=plus.webview.all();
for(var i=0;i<wvs.length;i ){
if(plus.webview.currentWebview().id!=wvs[i].id){
plus.webview.close(wvs[i]);
}
}
plus.runtime.restart();
本人不善言语,希望大家有更好的方法可以提出来,方便大家借鉴。
增量升级的问题
增量、差量升级是H5的一个优势,现在被越来越多的引用采用。但是在使用H5 的增量升级的时候遇到一个问题。纠结我很长时间一直在找解决方案,而且严重影响了用户体验。
我遇到最主要的问题是:
当APP启动是出现升级页面,用户点击增量升级后不重新启动APP。
如果我们的页面中存在父子webview的时候,这个时候有一些业务webview在显示的时候会发现父webview丢失了,导致用户体验直线下降,正常业务无法走通。
在尝试了很多方法后找到了一个解决方案。目前测试下来一切正常,但是可能测试的方法不全面。希望提出来对大家有所帮助
解决方案
其实解决方法很简单,就是关闭所有webview,然后再执行plus.runtime.restart();。下面是我的代码
var wvs=plus.webview.all();
for(var i=0;i<wvs.length;i ){
if(plus.webview.currentWebview().id!=wvs[i].id){
plus.webview.close(wvs[i]);
}
}
plus.runtime.restart();
本人不善言语,希望大家有更好的方法可以提出来,方便大家借鉴。
收起阅读 »分享iOS平台使用H5原生滚动的下拉刷新功能v1.0.0 [不推荐]
上一篇给大家分享了《使用H5原生滚动的上拉加载功能》,但是没有下拉刷新的功能,今天赶快补上。
我们在上一篇中提到,因为iOS下mui中的下拉刷新插件,使用的是自绘的模拟滚动条,不是原生的,而上拉加载和下拉刷新的实现是一体的,因为HTML结构相互依赖,所以无法使用原生的上拉加载功能+mui的下拉刷新,来混合使用。
hello mui中的下拉刷新例子,使用的是新增数据插入头部的方式,这里我使用重新刷新的方式,当然两种情况都有各自使用的场景,请根据各自的需求来写。
功能特性
~原生实现,不依赖任何前端框架
~监听事件下拉刷新,segment+下拉刷新也可轻松支持
~代码轻量模块化
下一阶段功能
下拉刷新的时候列表底部会多出几十像素的小bug,暂不知什么原因,有高人解决了希望相告之
如何使用
1、html,结构与mui的上拉刷新基本一致,但是多了ios-content,因为使用的是区域滚动,来激活iOS的原生滚动
<!--下拉刷新容器 #content -->
<div id="content" class="ios-content mui-scroll-wrapper">
<div id="content_inner" class="mui-scroll">
<!--数据列表
<ul class="mui-table-view">
</ul>
-->
</div><!-- #content_inner -->
</div><!-- #content -->
2、css 使用div的区域滚动产生滚动条,同时新增mui-scroll的动画样式transitioning
.ios-content{
text-align: left;
width: 100%;
position: absolute;
top: 44px;
bottom: 0;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
.transitioning{
-webkit-transition: -webkit-transform 0.25s ease;
transition: transform 0.25s ease;
}
3、js 这里主要为了演示上拉加载,没有使用模板引擎,只是简单创建li元素
document.addEventListener('plusready', plus_ready, false);
var pulldown = null; // 定义全局的下拉刷新对象,ajax请求成功需要endPullDownToRefresh()
function plus_ready(){
// 初始化商品列表
get_goods_list();
// 下拉刷新
pulldown = pulldown_refresh({
container: '#content',
callback: get_goods_list
});
}
var last_length = 20;
function get_goods_list(){
// 模拟ajax加载网络数据
setTimeout(function(){
var table_node = document.createElement('ul');
table_node.setAttribute('class', 'mui-table-view');
for (var i = 0; i < 20; i++) {
var li = document.createElement('li');
li.className = 'mui-table-view-cell';
li.innerHTML = '<a class="mui-navigate-right">Item ' + (last_length-i) + '</a>';
table_node.appendChild(li);
}
// 兼容下拉刷新的情况,先清空节点后插入数据
var parent = document.getElementById("content_inner");
while(parent.firstChild)
parent.removeChild(parent.firstChild);
parent.appendChild(table_node);
// 下拉刷新的时候,区域收回,使用之前定义的全局变量
if(pulldown){
pulldown.endPullDownToRefresh();
}
last_length += 2;
}, 1000);
}
源代码
/**
* 下拉刷新类定义
*/
var PullDownRefresh = function(options){
this.container = options['container'];
this.callback = options['callback'];
this.is_draging = false;
this.start_delta_y = 0;
this.delta_y = 0;
};
PullDownRefresh.prototype = {
//可以在这里提供Person的基本功能
init : function(){
// 创建下拉可以刷新div
var div_node = document.createElement('div');
div_node.setAttribute('class', 'mui-pull-top-pocket mui-block mui-visibility');
var html = '<!--div class="mui-pull-top-pocket mui-block mui-visibility" style="-webkit-transform: translate3d(0px, -50px, 0px);"-->'+
' <div class="mui-pull">'+
' <div class="mui-pull-loading mui-icon mui-icon-pulldown" style="-webkit-transition: -webkit-transform 200ms ease; transition: -webkit-transform 200ms ease; -webkit-transform: rotate(0deg);"></div>'+
' <div class="mui-pull-caption">下拉可以刷新</div>'+
' </div>'+
'<!--/div-->';
div_node.innerHTML = html;
var parent = document.querySelector(this.container);
parent.insertBefore(div_node, parent.childNodes[0]);
// 设置初始位置
document.querySelector(this.container+" .mui-pull-top-pocket").style.webkitTransform = 'translate3d(0,-50px,0)';
document.querySelector(this.container+" .mui-scroll").style.webkitTransform = 'translate3d(0,0,0)';
var that = this;
document.querySelector(this.container).addEventListener('drag', function(e){
// 第一次滑动
if(!that.is_draging){
if(e.detail.direction === 'down'){
that.is_draging = true;
that.start_delta_y = e.detail.deltaY;
document.querySelector(that.container+" .mui-pull-top-pocket").style.webkitTransform = 'translate3d(0,-50px,0)';
document.querySelector(that.container+" .mui-pull-loading").setAttribute('class', 'mui-pull-loading mui-icon mui-icon-pulldown');
document.querySelector(that.container+" .mui-pull-top-pocket").classList.remove('transitioning');
document.querySelector(that.container+" .mui-scroll").classList.remove('transitioning');
}
}
if(that.is_draging){
if(e.detail.direction === 'down'){
e.stopPropagation();
that.delta_y = e.detail.deltaY - that.start_delta_y;
// 判断滑动距离,如果大于下拉加载区域的高,就翻转箭头
if(that.delta_y >= 100){
document.querySelector(that.container+" .mui-pull-caption").innerText = '释放立即刷新';
document.querySelector(that.container+" .mui-pull-loading").style.webkitTransform = 'rotate(-180deg)';
}else{
document.querySelector(that.container+" .mui-pull-caption").innerText = '下拉可以刷新';
document.querySelector(that.container+" .mui-pull-loading").style.webkitTransform = 'rotate(0deg)';
}
}
}
});
document.querySelector(this.container).addEventListener('dragend', function(e){
if(that.is_draging){
that.is_draging = false;
// 放开的时候,判断当前滚动条距离顶部滚动了多远, 如果没有往下拉,滚动条在下面,则return;
var scroll_top = document.querySelector(that.container).scrollTop;
if(scroll_top >= 0){
// 当在底部下拉滑动到顶部时,拖动距离可能超过100,始终保持文字为“下拉可以刷新”
document.querySelector(that.container+" .mui-pull-caption").innerText = '下拉可以刷新';
document.querySelector(that.container+" .mui-pull-loading").style.webkitTransform = 'rotate(0deg)';
return;
}
if(that.delta_y >= 100){
document.querySelector(that.container+" .mui-pull-caption").innerText = '努力加载中...';
document.querySelector(that.container+" .mui-pull-loading").setAttribute('class', 'mui-pull-loading mui-icon mui-spinner');
document.querySelector(that.container+" .mui-pull-top-pocket").style.webkitTransform = 'translate3d(0,0,0)';
document.querySelector(that.container+" .mui-scroll").style.webkitTransform = 'translate3d(0,50px,0)';
document.querySelector(that.container+" .mui-pull-top-pocket").classList.add('transitioning');
//TODO 有点小不足的地方,.mui-scroll加上动画后,在刷新后,底部会出现一块空白,再刷新又正常,循环往复
// 因为.mui-scroll延迟0.25s再滑上去,而框架没有缩回, 需要以后解决
document.querySelector(that.container+" .mui-scroll").classList.add('transitioning');
// callback
that.callback();
}
}
})
},
endPullDownToRefresh: function(){
document.querySelector(this.container+" .mui-pull-top-pocket").style.webkitTransform = 'translate3d(0,-50px,0)';
document.querySelector(this.container+" .mui-scroll").style.webkitTransform = 'translate3d(0,0,0)';
}
}
/**
* 上拉加载功能实现, 使用H5原生滚动
* @param {Array} options
* options: {
* container: '#content' // 容器
* callback: get_list_function // 下拉刷新业务逻辑
* }
* @author fanrong33
* @version 1.0.0 build 20150705
*/
var pulldown_refresh = function(options){
var obj = new PullDownRefresh(options);
obj.init();
return obj;
}
上一篇给大家分享了《使用H5原生滚动的上拉加载功能》,但是没有下拉刷新的功能,今天赶快补上。
我们在上一篇中提到,因为iOS下mui中的下拉刷新插件,使用的是自绘的模拟滚动条,不是原生的,而上拉加载和下拉刷新的实现是一体的,因为HTML结构相互依赖,所以无法使用原生的上拉加载功能+mui的下拉刷新,来混合使用。
hello mui中的下拉刷新例子,使用的是新增数据插入头部的方式,这里我使用重新刷新的方式,当然两种情况都有各自使用的场景,请根据各自的需求来写。
功能特性
~原生实现,不依赖任何前端框架
~监听事件下拉刷新,segment+下拉刷新也可轻松支持
~代码轻量模块化
下一阶段功能
下拉刷新的时候列表底部会多出几十像素的小bug,暂不知什么原因,有高人解决了希望相告之
如何使用
1、html,结构与mui的上拉刷新基本一致,但是多了ios-content,因为使用的是区域滚动,来激活iOS的原生滚动
<!--下拉刷新容器 #content -->
<div id="content" class="ios-content mui-scroll-wrapper">
<div id="content_inner" class="mui-scroll">
<!--数据列表
<ul class="mui-table-view">
</ul>
-->
</div><!-- #content_inner -->
</div><!-- #content -->
2、css 使用div的区域滚动产生滚动条,同时新增mui-scroll的动画样式transitioning
.ios-content{
text-align: left;
width: 100%;
position: absolute;
top: 44px;
bottom: 0;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
.transitioning{
-webkit-transition: -webkit-transform 0.25s ease;
transition: transform 0.25s ease;
}
3、js 这里主要为了演示上拉加载,没有使用模板引擎,只是简单创建li元素
document.addEventListener('plusready', plus_ready, false);
var pulldown = null; // 定义全局的下拉刷新对象,ajax请求成功需要endPullDownToRefresh()
function plus_ready(){
// 初始化商品列表
get_goods_list();
// 下拉刷新
pulldown = pulldown_refresh({
container: '#content',
callback: get_goods_list
});
}
var last_length = 20;
function get_goods_list(){
// 模拟ajax加载网络数据
setTimeout(function(){
var table_node = document.createElement('ul');
table_node.setAttribute('class', 'mui-table-view');
for (var i = 0; i < 20; i++) {
var li = document.createElement('li');
li.className = 'mui-table-view-cell';
li.innerHTML = '<a class="mui-navigate-right">Item ' + (last_length-i) + '</a>';
table_node.appendChild(li);
}
// 兼容下拉刷新的情况,先清空节点后插入数据
var parent = document.getElementById("content_inner");
while(parent.firstChild)
parent.removeChild(parent.firstChild);
parent.appendChild(table_node);
// 下拉刷新的时候,区域收回,使用之前定义的全局变量
if(pulldown){
pulldown.endPullDownToRefresh();
}
last_length += 2;
}, 1000);
}
源代码
/**
* 下拉刷新类定义
*/
var PullDownRefresh = function(options){
this.container = options['container'];
this.callback = options['callback'];
this.is_draging = false;
this.start_delta_y = 0;
this.delta_y = 0;
};
PullDownRefresh.prototype = {
//可以在这里提供Person的基本功能
init : function(){
// 创建下拉可以刷新div
var div_node = document.createElement('div');
div_node.setAttribute('class', 'mui-pull-top-pocket mui-block mui-visibility');
var html = '<!--div class="mui-pull-top-pocket mui-block mui-visibility" style="-webkit-transform: translate3d(0px, -50px, 0px);"-->'+
' <div class="mui-pull">'+
' <div class="mui-pull-loading mui-icon mui-icon-pulldown" style="-webkit-transition: -webkit-transform 200ms ease; transition: -webkit-transform 200ms ease; -webkit-transform: rotate(0deg);"></div>'+
' <div class="mui-pull-caption">下拉可以刷新</div>'+
' </div>'+
'<!--/div-->';
div_node.innerHTML = html;
var parent = document.querySelector(this.container);
parent.insertBefore(div_node, parent.childNodes[0]);
// 设置初始位置
document.querySelector(this.container+" .mui-pull-top-pocket").style.webkitTransform = 'translate3d(0,-50px,0)';
document.querySelector(this.container+" .mui-scroll").style.webkitTransform = 'translate3d(0,0,0)';
var that = this;
document.querySelector(this.container).addEventListener('drag', function(e){
// 第一次滑动
if(!that.is_draging){
if(e.detail.direction === 'down'){
that.is_draging = true;
that.start_delta_y = e.detail.deltaY;
document.querySelector(that.container+" .mui-pull-top-pocket").style.webkitTransform = 'translate3d(0,-50px,0)';
document.querySelector(that.container+" .mui-pull-loading").setAttribute('class', 'mui-pull-loading mui-icon mui-icon-pulldown');
document.querySelector(that.container+" .mui-pull-top-pocket").classList.remove('transitioning');
document.querySelector(that.container+" .mui-scroll").classList.remove('transitioning');
}
}
if(that.is_draging){
if(e.detail.direction === 'down'){
e.stopPropagation();
that.delta_y = e.detail.deltaY - that.start_delta_y;
// 判断滑动距离,如果大于下拉加载区域的高,就翻转箭头
if(that.delta_y >= 100){
document.querySelector(that.container+" .mui-pull-caption").innerText = '释放立即刷新';
document.querySelector(that.container+" .mui-pull-loading").style.webkitTransform = 'rotate(-180deg)';
}else{
document.querySelector(that.container+" .mui-pull-caption").innerText = '下拉可以刷新';
document.querySelector(that.container+" .mui-pull-loading").style.webkitTransform = 'rotate(0deg)';
}
}
}
});
document.querySelector(this.container).addEventListener('dragend', function(e){
if(that.is_draging){
that.is_draging = false;
// 放开的时候,判断当前滚动条距离顶部滚动了多远, 如果没有往下拉,滚动条在下面,则return;
var scroll_top = document.querySelector(that.container).scrollTop;
if(scroll_top >= 0){
// 当在底部下拉滑动到顶部时,拖动距离可能超过100,始终保持文字为“下拉可以刷新”
document.querySelector(that.container+" .mui-pull-caption").innerText = '下拉可以刷新';
document.querySelector(that.container+" .mui-pull-loading").style.webkitTransform = 'rotate(0deg)';
return;
}
if(that.delta_y >= 100){
document.querySelector(that.container+" .mui-pull-caption").innerText = '努力加载中...';
document.querySelector(that.container+" .mui-pull-loading").setAttribute('class', 'mui-pull-loading mui-icon mui-spinner');
document.querySelector(that.container+" .mui-pull-top-pocket").style.webkitTransform = 'translate3d(0,0,0)';
document.querySelector(that.container+" .mui-scroll").style.webkitTransform = 'translate3d(0,50px,0)';
document.querySelector(that.container+" .mui-pull-top-pocket").classList.add('transitioning');
//TODO 有点小不足的地方,.mui-scroll加上动画后,在刷新后,底部会出现一块空白,再刷新又正常,循环往复
// 因为.mui-scroll延迟0.25s再滑上去,而框架没有缩回, 需要以后解决
document.querySelector(that.container+" .mui-scroll").classList.add('transitioning');
// callback
that.callback();
}
}
})
},
endPullDownToRefresh: function(){
document.querySelector(this.container+" .mui-pull-top-pocket").style.webkitTransform = 'translate3d(0,-50px,0)';
document.querySelector(this.container+" .mui-scroll").style.webkitTransform = 'translate3d(0,0,0)';
}
}
/**
* 上拉加载功能实现, 使用H5原生滚动
* @param {Array} options
* options: {
* container: '#content' // 容器
* callback: get_list_function // 下拉刷新业务逻辑
* }
* @author fanrong33
* @version 1.0.0 build 20150705
*/
var pulldown_refresh = function(options){
var obj = new PullDownRefresh(options);
obj.init();
return obj;
}
收起阅读 »
HBuilder初次见面——Android_APP——运行
鄙人第一次应用HBuilder这款软件,很陌生。好了,闲话不多聊。
建立APP就不多说了,自己新建项目试试看,里面可以看到APP字样。建立后如何运行呢?针对AndroidAPP进行说明,要首先保证机器上安装了Android studio或者相关的Android sdk即可。启动Android sdk后,启动相关的avd,说明一点需要在启动HBuilder之前启动sdk。否则需要重启HBuilder之后,就可以在运行中看到相关的模拟器了。
Android sdk建议安装Android studio(翻墙下载最好),会自带sdk以及avd,直接下载即可(需翻墙)。
鄙人第一次应用HBuilder这款软件,很陌生。好了,闲话不多聊。
建立APP就不多说了,自己新建项目试试看,里面可以看到APP字样。建立后如何运行呢?针对AndroidAPP进行说明,要首先保证机器上安装了Android studio或者相关的Android sdk即可。启动Android sdk后,启动相关的avd,说明一点需要在启动HBuilder之前启动sdk。否则需要重启HBuilder之后,就可以在运行中看到相关的模拟器了。
Android sdk建议安装Android studio(翻墙下载最好),会自带sdk以及avd,直接下载即可(需翻墙)。
收起阅读 »
分享基于plus.downloader的图片懒加载功能,支持本地缓存v1.1.0
今天试用了下hello mui上的图片懒加载功能,发现有些地方还无法满足我的需求,ajax动态加载的时候无法实现懒加载。
然后又看了下36kr的示例,因为代码关系实在太多了,耦合度比较高,遂自己动手写了一个轻量级的懒加载功能模块,而且支持图片缓存到本地哦~~~
欢迎各位拍砖,交流碰撞思想!
升级日志
v1.1.0 build 20160107
1、已增加 @LFZ 的代码,不用重复下载两次服务器端的图片
2、新增图片加载淡入特效
3、新增图片加载完成后回调
4、修改data-src为data-lazyload
功能特性
~原生实现,不依赖任何前端框架
~ajax动态加载支持图片懒加载
~支持图片缓存到本地
~轻量模块化
如何使用
1、引入md5.min.js,因为依赖js版md5函数,用于将图片url转换为32位md5
<script s r c="md5.min.js"></script>
2、在头部js包含下面的lazyload方法函数,否则可能报错函数未定义
3、HTML代码使用ajax动态生成如下img标签,src为默认图片,data-src填写图片网络地址,并且必须包含onload事件来触发懒加载功能。
<img s r c="placehold.jpg" data-lazyload="http://...jpg" onload="lazyload(this)" />
注意:因为函数依赖plus.io和plus.downloader接口,所以在plus还没ready的时候img onload执行lazyload可能会报错,lazyload比plus先执行完毕。
当然,在真实环境中,不管是商品列表、订单列表等,我们的图片一般都是动态加载的,所以问题不大。
在代码的写法策略上需要使用动态加载方式,尽量不使用写死在html里面。
4、添加.img-lazyload 支持图片淡入样式
@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}
@keyframes fadeIn{0%{opacity:0}100%{opacity:1}}
.img-lazyload{-webkit-animation: fadeIn 350ms linear 0ms 1 normal both;animation: fadeIn 350ms linear 0ms 1 normal both;opacity:1;}
5、图片默认缓存到_downloads/image/目录下
活动图
函数源代码
/**
* 图片懒加载
* @param {Object} obj DOMElement
* @param {Function} callback 加载完成回调函数
*
* @author fanrong33
* @version 1.1.0 build 20160107
*/
function lazyload(obj, callback){
var debug = false; // 默认打印调试日志
if(obj.getAttribute('data-loaded')){
return;
}
var image_url = obj.getAttribute('data-lazyload');
debug && console.log(image_url);
// 1. 转换网络图片地址为本地缓存图片路径,判断该图片是否存在本地缓存
// http://...jpg -> md5
// 缓存目录 _downloads/image/(md5).jpg
var image_md5 = md5(image_url);
var local_image_url = '_downloads/image/'+image_md5+'.jpg'; // 缓存本地图片url
var absolute_image_path = plus.io.convertLocalFileSystemURL(local_image_url); // 平台绝对路径
// new temp_img 用于判断图片文件是否存在
var temp_img = new Image();
temp_img.src = absolute_image_path;
temp_img.onload = function(){
debug && console.log('存在本地缓存图片文件'+local_image_url+',直接显示');
// 1.1 存在,则直接显示(本地已缓存,不需要淡入动画)
obj.setAttribute('src', absolute_image_path);
obj.setAttribute('data-loaded', true);
obj.classList.add('img-lazyload');
callback && callback();
return;
}
temp_img.onerror = function(){
debug && console.log('不存在本地缓存图片文件');
// 1.2 下载图片缓存到本地
debug && console.log('开始下载图片'+image_url+' 缓存到本地: '+local_image_url);
function download_img(){
var download_task = plus.downloader.createDownload(image_url, {
filename: local_image_url // filename:下载任务在本地保存的文件路径
}, function(download, status) {
if(status != 200){
// 下载失败,删除本地临时文件
debug && console.log('下载失败,status'+status);
if(local_image_url != null){
plus.io.resolveLocalFileSystemURL(local_image_url, function(entry) {
entry.remove(function(entry) {
debug && console.log("临时文件删除成功" + local_image_url);
// 重新下载图片
download_img();
}, function(e) {
debug && console.log("临时文件删除失败" + local_image_url);
});
});
}
}else{
// 把下载成功的图片显示
// 将本地URL路径转换成平台绝对路径
obj.setAttribute('src', plus.io.convertLocalFileSystemURL(local_image_url));
obj.setAttribute('data-loaded', true);
obj.classList.add('img-lazyload');
callback && callback();
}
});
download_task.start();
}
download_img();
}
}
今天试用了下hello mui上的图片懒加载功能,发现有些地方还无法满足我的需求,ajax动态加载的时候无法实现懒加载。
然后又看了下36kr的示例,因为代码关系实在太多了,耦合度比较高,遂自己动手写了一个轻量级的懒加载功能模块,而且支持图片缓存到本地哦~~~
欢迎各位拍砖,交流碰撞思想!
升级日志
v1.1.0 build 20160107
1、已增加 @LFZ 的代码,不用重复下载两次服务器端的图片
2、新增图片加载淡入特效
3、新增图片加载完成后回调
4、修改data-src为data-lazyload
功能特性
~原生实现,不依赖任何前端框架
~ajax动态加载支持图片懒加载
~支持图片缓存到本地
~轻量模块化
如何使用
1、引入md5.min.js,因为依赖js版md5函数,用于将图片url转换为32位md5
<script s r c="md5.min.js"></script>
2、在头部js包含下面的lazyload方法函数,否则可能报错函数未定义
3、HTML代码使用ajax动态生成如下img标签,src为默认图片,data-src填写图片网络地址,并且必须包含onload事件来触发懒加载功能。
<img s r c="placehold.jpg" data-lazyload="http://...jpg" onload="lazyload(this)" />
注意:因为函数依赖plus.io和plus.downloader接口,所以在plus还没ready的时候img onload执行lazyload可能会报错,lazyload比plus先执行完毕。
当然,在真实环境中,不管是商品列表、订单列表等,我们的图片一般都是动态加载的,所以问题不大。
在代码的写法策略上需要使用动态加载方式,尽量不使用写死在html里面。
4、添加.img-lazyload 支持图片淡入样式
@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}
@keyframes fadeIn{0%{opacity:0}100%{opacity:1}}
.img-lazyload{-webkit-animation: fadeIn 350ms linear 0ms 1 normal both;animation: fadeIn 350ms linear 0ms 1 normal both;opacity:1;}
5、图片默认缓存到_downloads/image/目录下
活动图
函数源代码
/**
* 图片懒加载
* @param {Object} obj DOMElement
* @param {Function} callback 加载完成回调函数
*
* @author fanrong33
* @version 1.1.0 build 20160107
*/
function lazyload(obj, callback){
var debug = false; // 默认打印调试日志
if(obj.getAttribute('data-loaded')){
return;
}
var image_url = obj.getAttribute('data-lazyload');
debug && console.log(image_url);
// 1. 转换网络图片地址为本地缓存图片路径,判断该图片是否存在本地缓存
// http://...jpg -> md5
// 缓存目录 _downloads/image/(md5).jpg
var image_md5 = md5(image_url);
var local_image_url = '_downloads/image/'+image_md5+'.jpg'; // 缓存本地图片url
var absolute_image_path = plus.io.convertLocalFileSystemURL(local_image_url); // 平台绝对路径
// new temp_img 用于判断图片文件是否存在
var temp_img = new Image();
temp_img.src = absolute_image_path;
temp_img.onload = function(){
debug && console.log('存在本地缓存图片文件'+local_image_url+',直接显示');
// 1.1 存在,则直接显示(本地已缓存,不需要淡入动画)
obj.setAttribute('src', absolute_image_path);
obj.setAttribute('data-loaded', true);
obj.classList.add('img-lazyload');
callback && callback();
return;
}
temp_img.onerror = function(){
debug && console.log('不存在本地缓存图片文件');
// 1.2 下载图片缓存到本地
debug && console.log('开始下载图片'+image_url+' 缓存到本地: '+local_image_url);
function download_img(){
var download_task = plus.downloader.createDownload(image_url, {
filename: local_image_url // filename:下载任务在本地保存的文件路径
}, function(download, status) {
if(status != 200){
// 下载失败,删除本地临时文件
debug && console.log('下载失败,status'+status);
if(local_image_url != null){
plus.io.resolveLocalFileSystemURL(local_image_url, function(entry) {
entry.remove(function(entry) {
debug && console.log("临时文件删除成功" + local_image_url);
// 重新下载图片
download_img();
}, function(e) {
debug && console.log("临时文件删除失败" + local_image_url);
});
});
}
}else{
// 把下载成功的图片显示
// 将本地URL路径转换成平台绝对路径
obj.setAttribute('src', plus.io.convertLocalFileSystemURL(local_image_url));
obj.setAttribute('data-loaded', true);
obj.classList.add('img-lazyload');
callback && callback();
}
});
download_task.start();
}
download_img();
}
}
收起阅读 »
mui ajax success回调函数为什么会执行二次?
这里应该是一个BUG,我测试了几次都是如此
mui.ajax 成功回调都是执行二次;
这里应该是一个BUG,我测试了几次都是如此
mui.ajax 成功回调都是执行二次;
Js注解
//创建滑动块当前标识盒子
/**
- @param {Number} index null -正整数,索引号
- @param {string} src null -传入的图片URL集合
*/
function createcurr(index, src) {
。。。。。。。
}
//创建滑动块当前标识盒子
/**
- @param {Number} index null -正整数,索引号
- @param {string} src null -传入的图片URL集合
*/
function createslidercurr(index, src) {
。。。。。。。
}
从表面上来看是没有问题。现在问题来了,这两个函数中有一个函数在函数在引用的时候要提示数据类型与注解,有一个不提示。
createcurr 这个函数会提示
createslidercurr 这个数据不会提示
为什么会这样,刚开始的时候我为了让 createslidercurr 这个函数在引用的时候提示数据类型与注解,搞了很久,但是它就是不提示,郁了个闷啊,猫了个咪的,气死我了。
原因:createslidercurr 这个函数包含了 mui 里面的slider关建字 。
写这篇文章,是希望那个做规范开发有团队协作的人可以看一看哈,希望能帮到大家。。
OVER
//创建滑动块当前标识盒子
/**
- @param {Number} index null -正整数,索引号
- @param {string} src null -传入的图片URL集合
*/
function createcurr(index, src) {
。。。。。。。
}
//创建滑动块当前标识盒子
/**
- @param {Number} index null -正整数,索引号
- @param {string} src null -传入的图片URL集合
*/
function createslidercurr(index, src) {
。。。。。。。
}
从表面上来看是没有问题。现在问题来了,这两个函数中有一个函数在函数在引用的时候要提示数据类型与注解,有一个不提示。
createcurr 这个函数会提示
createslidercurr 这个数据不会提示
为什么会这样,刚开始的时候我为了让 createslidercurr 这个函数在引用的时候提示数据类型与注解,搞了很久,但是它就是不提示,郁了个闷啊,猫了个咪的,气死我了。
原因:createslidercurr 这个函数包含了 mui 里面的slider关建字 。
写这篇文章,是希望那个做规范开发有团队协作的人可以看一看哈,希望能帮到大家。。
OVER
收起阅读 »【分享】 content 和 伪元素 哪些控件不支持
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试哪些元素支不支持伪元素</title>
<style>
input{
display: block;
}
body *:after{
content: "after";
color: red;
}
img{
padding:30px;
vertical-align: top;
}
</style>
</head>
<body>
<h1>测试哪些元素支不支持伪元素</h1>
<input type="text">
<input type="checkbox" name="" id="">
<input type="radio" name="" id="">
<input type="submit" value="Submit">
<input type="button" value="input">
<button>button</button>
<textarea name="" id="" cols="30" rows="10"></textarea>
<select name="" id="">
<option value="">select</option>
</select>
<hr>
<img src="https://www.baidu.com/img/bdlogo.png" alt="jb">
<iframe src="http://www.baidu.com" frameborder="0" width="500" height="300"></iframe>
</body>
</html>
text --- no
submit ---no
button --- no
textarea --- no
select ----no
img --- no
iframe -- no
=============
checkbox ----yes
radio ---- yes
button --- yes
hr --- yes
其它可以做成盒子的都支持
=============================
这个写得不全,各位需要测试的可以把这个COPY下去测试就行了。希望可以帮到大家。。。。。。。。。。。。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试哪些元素支不支持伪元素</title>
<style>
input{
display: block;
}
body *:after{
content: "after";
color: red;
}
img{
padding:30px;
vertical-align: top;
}
</style>
</head>
<body>
<h1>测试哪些元素支不支持伪元素</h1>
<input type="text">
<input type="checkbox" name="" id="">
<input type="radio" name="" id="">
<input type="submit" value="Submit">
<input type="button" value="input">
<button>button</button>
<textarea name="" id="" cols="30" rows="10"></textarea>
<select name="" id="">
<option value="">select</option>
</select>
<hr>
<img src="https://www.baidu.com/img/bdlogo.png" alt="jb">
<iframe src="http://www.baidu.com" frameborder="0" width="500" height="300"></iframe>
</body>
</html>
text --- no
submit ---no
button --- no
textarea --- no
select ----no
img --- no
iframe -- no
=============
checkbox ----yes
radio ---- yes
button --- yes
hr --- yes
其它可以做成盒子的都支持
=============================
这个写得不全,各位需要测试的可以把这个COPY下去测试就行了。希望可以帮到大家。。。。。。。。。。。。
收起阅读 »【分享交流】h5+的Downloader下载网络图片缓存到本地的案例
之前展示图片都是通过<img src="网络图片地址"> , 每次都请求服务器, 加载比较慢;
如何做到显示图片的时候先从本地获取,没有则联网下载,缓存到本地;下次直接从本地拿,无需再联网;
看了文档,逛了论坛,没有找到现成的案例,折腾了老半天,走了好多弯路,把自己写的分享给大家,
我用Android机测试是成功的,苹果机还没有试,有问题欢迎指出:
<!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="black">
</head>
<body>
<div class="mui-content">
<img id="img1"/>
<img id="img2"/>
<img id="img3"/>
</div>
</body>
<script src="../js/mui.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
mui.init(); //mui初始化
mui.plusReady(function() {
setImg("img1", "http://ask.dcloud.net.cn/uploads/avatar/000/00/00/16_avatar_max.jpg");
setImg("img2", "http://client.bbzuche.com/resources/product/2014012094648828751145/20150611/logo.jpg");
setImg("img3", "http://www.bbzuche.com/images/tan.jpg");
});
/*<img>设置图片
*1.从本地获取,如果本地存在,则直接设置图片
*2.如果本地不存在则联网下载,缓存到本地,再设置图片
* */
function setImg(imgId, loadUrl) {
if (imgId == null || loadUrl == null) return;
//图片下载成功 默认保存在本地相对路径的"_downloads"文件夹里面, 如"_downloads/logo.jpg"
var filename = loadUrl.substring(loadUrl.lastIndexOf("/") + 1, loadUrl.length);
var relativePath = "_downloads/" + filename;
//检查图片是否已存在
plus.io.resolveLocalFileSystemURL(relativePath, function(entry) {
console.log("图片存在,直接设置=" + relativePath);
//如果文件存在,则直接设置本地图片
setImgFromLocal(imgId, relativePath);
}, function(e) {
console.log("图片不存在,联网下载=" + relativePath);
//如果文件不存在,联网下载图片
setImgFromNet (imgId,loadUrl,relativePath);
});
}
/*给图片标签<img>设置本地图片
* imgId 图片标签<img>的id
* relativePath 本地相对路径 例如:"_downloads/logo.jpg"
*/
function setImgFromLocal(imgId, relativePath) {
//本地相对路径("_downloads/logo.jpg")转成SD卡绝对路径("/storage/emulated/0/Android/data/io.dcloud.HBuilder/.HBuilder/downloads/logo.jpg");
var sd_path = plus.io.convertLocalFileSystemURL(relativePath);
//给<img>设置图片
$id(imgId).setAttribute("src", sd_path);
}
/*联网下载图片,并设置给<img>*/
function setImgFromNet (imgId,loadUrl,relativePath) {
//先设置下载中的默认图片
$id(imgId).setAttribute("src", "../images/loading.png");
//创建下载任务
var dtask = plus.downloader.createDownload(loadUrl, {}, function(d, status) {
if (status == 200) {
//下载成功
console.log("下载成功=" + relativePath);
setImgFromLocal(imgId, d.filename);
} else {
//下载失败,需删除本地临时文件,否则下次进来时会检查到图片已存在
console.log("下载失败=" + status+"=="+relativePath);
//dtask.abort();//文档描述:取消下载,删除临时文件;(但经测试临时文件没有删除,故使用delFile()方法删除);
if (relativePath!=null)
delFile(relativePath);
}
});
//启动下载任务
dtask.start();
}
/*删除指定文件*/
function delFile(relativePath) {
plus.io.resolveLocalFileSystemURL(relativePath, function(entry) {
entry.remove(function(entry) {
console.log("文件删除成功==" + relativePath);
}, function(e) {
console.log("文件删除失败=" + relativePath);
});
});
}
/*根据id查找元素*/
function $id(id) {
return document.getElementById(id);
}
</script>
</html>
之前展示图片都是通过<img src="网络图片地址"> , 每次都请求服务器, 加载比较慢;
如何做到显示图片的时候先从本地获取,没有则联网下载,缓存到本地;下次直接从本地拿,无需再联网;
看了文档,逛了论坛,没有找到现成的案例,折腾了老半天,走了好多弯路,把自己写的分享给大家,
我用Android机测试是成功的,苹果机还没有试,有问题欢迎指出:
<!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="black">
</head>
<body>
<div class="mui-content">
<img id="img1"/>
<img id="img2"/>
<img id="img3"/>
</div>
</body>
<script src="../js/mui.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
mui.init(); //mui初始化
mui.plusReady(function() {
setImg("img1", "http://ask.dcloud.net.cn/uploads/avatar/000/00/00/16_avatar_max.jpg");
setImg("img2", "http://client.bbzuche.com/resources/product/2014012094648828751145/20150611/logo.jpg");
setImg("img3", "http://www.bbzuche.com/images/tan.jpg");
});
/*<img>设置图片
*1.从本地获取,如果本地存在,则直接设置图片
*2.如果本地不存在则联网下载,缓存到本地,再设置图片
* */
function setImg(imgId, loadUrl) {
if (imgId == null || loadUrl == null) return;
//图片下载成功 默认保存在本地相对路径的"_downloads"文件夹里面, 如"_downloads/logo.jpg"
var filename = loadUrl.substring(loadUrl.lastIndexOf("/") + 1, loadUrl.length);
var relativePath = "_downloads/" + filename;
//检查图片是否已存在
plus.io.resolveLocalFileSystemURL(relativePath, function(entry) {
console.log("图片存在,直接设置=" + relativePath);
//如果文件存在,则直接设置本地图片
setImgFromLocal(imgId, relativePath);
}, function(e) {
console.log("图片不存在,联网下载=" + relativePath);
//如果文件不存在,联网下载图片
setImgFromNet (imgId,loadUrl,relativePath);
});
}
/*给图片标签<img>设置本地图片
* imgId 图片标签<img>的id
* relativePath 本地相对路径 例如:"_downloads/logo.jpg"
*/
function setImgFromLocal(imgId, relativePath) {
//本地相对路径("_downloads/logo.jpg")转成SD卡绝对路径("/storage/emulated/0/Android/data/io.dcloud.HBuilder/.HBuilder/downloads/logo.jpg");
var sd_path = plus.io.convertLocalFileSystemURL(relativePath);
//给<img>设置图片
$id(imgId).setAttribute("src", sd_path);
}
/*联网下载图片,并设置给<img>*/
function setImgFromNet (imgId,loadUrl,relativePath) {
//先设置下载中的默认图片
$id(imgId).setAttribute("src", "../images/loading.png");
//创建下载任务
var dtask = plus.downloader.createDownload(loadUrl, {}, function(d, status) {
if (status == 200) {
//下载成功
console.log("下载成功=" + relativePath);
setImgFromLocal(imgId, d.filename);
} else {
//下载失败,需删除本地临时文件,否则下次进来时会检查到图片已存在
console.log("下载失败=" + status+"=="+relativePath);
//dtask.abort();//文档描述:取消下载,删除临时文件;(但经测试临时文件没有删除,故使用delFile()方法删除);
if (relativePath!=null)
delFile(relativePath);
}
});
//启动下载任务
dtask.start();
}
/*删除指定文件*/
function delFile(relativePath) {
plus.io.resolveLocalFileSystemURL(relativePath, function(entry) {
entry.remove(function(entry) {
console.log("文件删除成功==" + relativePath);
}, function(e) {
console.log("文件删除失败=" + relativePath);
});
});
}
/*根据id查找元素*/
function $id(id) {
return document.getElementById(id);
}
</script>
</html>
收起阅读 »