
解决MUI页面切换白屏,初始化慢
MUI的窗口管理是通过预加载解决切页白屏问题,根据这个思路我们不妨把MUI的解决思路再扩展下:
就是我新建一个webview窗口的时候,同时在后台偷偷再新建一个空白的webview界面留待备用,然后每次新建webview都把这个空白的界面ID设置为新建的webview的ID,同时在后台再偷偷建个空白的webview,这样的好处是每次都是直接拿空白的webview界面来渲染新界面,而在后台偷偷创建一个空白的webview,省去了创建webview的时间。
MUI的窗口管理是通过预加载解决切页白屏问题,根据这个思路我们不妨把MUI的解决思路再扩展下:
就是我新建一个webview窗口的时候,同时在后台偷偷再新建一个空白的webview界面留待备用,然后每次新建webview都把这个空白的界面ID设置为新建的webview的ID,同时在后台再偷偷建个空白的webview,这样的好处是每次都是直接拿空白的webview界面来渲染新界面,而在后台偷偷创建一个空白的webview,省去了创建webview的时间。

App版本升级总结
这两天做了App的版本升级功能,发现官方文档下很多同学都在问App资源在线升级后版本号为什么不改变。官方同学也似乎没有回答到点上,这里给大家补充说明一下。
应用升级有三种方式:
- 整包升级:适用于大版本更新,runtime发生变化时(模块、配置、版本等变化)必须使用此更新方法
- 应用资源升级:适用于小版本更新 。runtime不变,前端页面整体压缩包更新
- 应用资源差量升级:适用于小版本更新 。runtime不变,前端页面仅需要更新的部分更新。
传送门:http://ask.dcloud.net.cn/article/431
应用的版本号有两种:
1、应用版本号
plus.runtime.version
2、应用资源版本号
// 获取本地应用资源版本号
plus.runtime.getProperty(plus.runtime.appid,function(inf){
wgtVer=inf.version;
console.log("当前应用版本:"+wgtVer);
});
所以官方文档说明的很清楚,只有在整包升级时,应用的版本号才会改变。而当应用资源升级时,应用的版本号是不会改变的,改变的是应用资源版本号。两种版本号的获取方式参照上述代码。
但是有两个版本号,似乎更新的时候有点困难。我的做法是将两个版本号统一,更方便处理。场景如下:
1、0.0.1版本的应用发布到了应用市场,已经有人下载了
2、开发同学发现有bug,紧急fix掉后将版本号改为了0.0.2,发布了应用资源包,同时也发布了整包到应用市场
3、由于应用市场需要审核应用,所以还没有人下载到最新的0.0.2版本
4、出现bug的用户在重启应用或收到升级推送后成功升级到0.0.2版本,修复了bug
5、第二天,应用市场审核通过0.0.2版本的应用。新用户下载了0.0.2版本。老用户使用的0.0.1版本但是应用资源包已经将App升级到0.0.2版
注:用户在检测版本的时候传最高的版本到服务器,避免重复升级。
这两天做了App的版本升级功能,发现官方文档下很多同学都在问App资源在线升级后版本号为什么不改变。官方同学也似乎没有回答到点上,这里给大家补充说明一下。
应用升级有三种方式:
- 整包升级:适用于大版本更新,runtime发生变化时(模块、配置、版本等变化)必须使用此更新方法
- 应用资源升级:适用于小版本更新 。runtime不变,前端页面整体压缩包更新
- 应用资源差量升级:适用于小版本更新 。runtime不变,前端页面仅需要更新的部分更新。
传送门:http://ask.dcloud.net.cn/article/431
应用的版本号有两种:
1、应用版本号
plus.runtime.version
2、应用资源版本号
// 获取本地应用资源版本号
plus.runtime.getProperty(plus.runtime.appid,function(inf){
wgtVer=inf.version;
console.log("当前应用版本:"+wgtVer);
});
所以官方文档说明的很清楚,只有在整包升级时,应用的版本号才会改变。而当应用资源升级时,应用的版本号是不会改变的,改变的是应用资源版本号。两种版本号的获取方式参照上述代码。
但是有两个版本号,似乎更新的时候有点困难。我的做法是将两个版本号统一,更方便处理。场景如下:
1、0.0.1版本的应用发布到了应用市场,已经有人下载了
2、开发同学发现有bug,紧急fix掉后将版本号改为了0.0.2,发布了应用资源包,同时也发布了整包到应用市场
3、由于应用市场需要审核应用,所以还没有人下载到最新的0.0.2版本
4、出现bug的用户在重启应用或收到升级推送后成功升级到0.0.2版本,修复了bug
5、第二天,应用市场审核通过0.0.2版本的应用。新用户下载了0.0.2版本。老用户使用的0.0.1版本但是应用资源包已经将App升级到0.0.2版
注:用户在检测版本的时候传最高的版本到服务器,避免重复升级。
收起阅读 »
proload加载 undifine或是加载过多
加载过多:preloadLimit:12, 数值可以改大一点,不填的话好像默认是十个。
undifine的原因应该是点击太快,页面未加载完成就被点击了。
加载过多:preloadLimit:12, 数值可以改大一点,不填的话好像默认是十个。
undifine的原因应该是点击太快,页面未加载完成就被点击了。

【经验分享】解决ios页面切换,状态栏背景、文字样式变换不自然问题
ios的沉浸模式默认是开启的,是由配置文件apple节点下的UIReserveStatusbarOffset属性设置的;
但是偷偷听说是创建了一个webview在状态栏位置,所以切换页面的时候并不会跟着打开的webview一起滑动,只能通过plus.navigator.setStatusBarBackground("#e3393c");或者init方法的statusBarBackground参数去设置背景颜色,切换加载webview后才会去执行修改背景颜色的方法,就会有一定的延迟,切换不和谐。
故尝试了放弃UIReserveStatusbarOffset,设置值为false,果然页面整体顶上去了,那么接下来就简单了,ios的状态栏高度固定为20px,剩下的就跟安卓的沉浸模式差不多的做法了, ios中mui会给body添加固定的class:mui-plus mui-ios mui-ios-8 mui-ios-8-4 mui-statusbar,那么写几个.mui-ios 下的样式(如:.mui-ios header{ padding-top:20px;})就轻松预留了状态栏的高度,这样header是什么背景就是状态栏的背景了。
如果需要不同页面去修改状态栏文字颜色就只能通过:plus.navigator.setStatusBarStyle("UIStatusBarStyleDefault");
以及init方法的beforeback:function(){plus.navigator.setStatusBarStyle("UIStatusBarStyleBlackOpaque");} 配合变换;
目前这样使用很流畅,基本无延迟,类似原生(ios原生为渐变)
ios的沉浸模式默认是开启的,是由配置文件apple节点下的UIReserveStatusbarOffset属性设置的;
但是偷偷听说是创建了一个webview在状态栏位置,所以切换页面的时候并不会跟着打开的webview一起滑动,只能通过plus.navigator.setStatusBarBackground("#e3393c");或者init方法的statusBarBackground参数去设置背景颜色,切换加载webview后才会去执行修改背景颜色的方法,就会有一定的延迟,切换不和谐。
故尝试了放弃UIReserveStatusbarOffset,设置值为false,果然页面整体顶上去了,那么接下来就简单了,ios的状态栏高度固定为20px,剩下的就跟安卓的沉浸模式差不多的做法了, ios中mui会给body添加固定的class:mui-plus mui-ios mui-ios-8 mui-ios-8-4 mui-statusbar,那么写几个.mui-ios 下的样式(如:.mui-ios header{ padding-top:20px;})就轻松预留了状态栏的高度,这样header是什么背景就是状态栏的背景了。
如果需要不同页面去修改状态栏文字颜色就只能通过:plus.navigator.setStatusBarStyle("UIStatusBarStyleDefault");
以及init方法的beforeback:function(){plus.navigator.setStatusBarStyle("UIStatusBarStyleBlackOpaque");} 配合变换;
目前这样使用很流畅,基本无延迟,类似原生(ios原生为渐变)
收起阅读 »
【经验分享】滚动浮动导航,iscroll结构滚动固定元素
看问答里面很多人在求滚动到一定位置固定某个结构的方法,分享个简单的方法。
官方给的iscroll获取滚动条高度的在浏览器是有效的,在安卓手机上就无效了,获取transform transitionY同样的问题获取不到,所以放弃获取高度,直接通过固定目标元素距离顶部的距离去判断位置。

// 滚动固定
var headH = document.querySelector('header').offsetHeight, //头部高度
tab = document.getElementById('userTab'), //目标元素
fixed = document.getElementById('fixedNav'); // 浮动元素,默认隐藏,当然也可以直接浮动目标元素
window.addEventListener('scroll', function(e) {
//原理:滚动时判断固定元素的top距离头部的位置
if(himall.hasClass(fixed, 'hidden')) {
if(tab.getBoundingClientRect().top <= headH) {
himall.removeClass(fixed, ' hidden');
}
}else if(!himall.hasClass(fixed, 'hidden')){
if(tab.getBoundingClientRect().top >= headH){
fixed.className += ' hidden';
}
}
});
himall.removeClass = function(el,name) {
if(!el)
return;
if(el.className.indexOf(name)>=0)
el.className=el.className.replace(name,'');
}
himall.hasClass = function(el,name) {
return (el.className.indexOf(name)>=0);
}
看问答里面很多人在求滚动到一定位置固定某个结构的方法,分享个简单的方法。
官方给的iscroll获取滚动条高度的在浏览器是有效的,在安卓手机上就无效了,获取transform transitionY同样的问题获取不到,所以放弃获取高度,直接通过固定目标元素距离顶部的距离去判断位置。
// 滚动固定
var headH = document.querySelector('header').offsetHeight, //头部高度
tab = document.getElementById('userTab'), //目标元素
fixed = document.getElementById('fixedNav'); // 浮动元素,默认隐藏,当然也可以直接浮动目标元素
window.addEventListener('scroll', function(e) {
//原理:滚动时判断固定元素的top距离头部的位置
if(himall.hasClass(fixed, 'hidden')) {
if(tab.getBoundingClientRect().top <= headH) {
himall.removeClass(fixed, ' hidden');
}
}else if(!himall.hasClass(fixed, 'hidden')){
if(tab.getBoundingClientRect().top >= headH){
fixed.className += ' hidden';
}
}
});
himall.removeClass = function(el,name) {
if(!el)
return;
if(el.className.indexOf(name)>=0)
el.className=el.className.replace(name,'');
}
himall.hasClass = function(el,name) {
return (el.className.indexOf(name)>=0);
}
收起阅读 »

Hublider中如何将px转换为rem
屏幕适配一直是困扰工程师的重要课题,各种解决方案层出不穷,百分比布局、响应式设计(媒体查询)、媒体查询与rem结合等方案都各有所长,综合而言,媒体查询与rem、Javascript配合使用的方案最优,但是将px转换为rem需要不停的计算,对一个大型项目会有很多的样式代码,转换的工作量是巨大,有没有一种自动化的解决方案呢?
Hublider提供了解决方法:可在工具>>选项或右键项目>>属性下的代码助手设置中配置。参阅http://ask.dcloud.net.cn/article/982
开发实践中经历了从最初的PC固定布局、手机端固定布局(两端留白)到响应式设计(媒体查询、百分比布局等),直到最终选择rem+Javascript的模式,但是在项目开发中需要将大量的样式由px转换为rem,单位之间的换算虽然不复杂,但是工作量却很大。
这里的参数选择和你在项目中的设计图尺寸和根元素字体大小相关,至于border的处理是因为在安卓下使用rem单位的支持性特别差,你可能写2rem或者3rem都没用默认会变成1px,所以在使用border属性时很多时候不建议处理border。
Javascript控制根元素大小的代码如下图所示,读者可以将代码放在公共的Js文件中,确保每个HTML文件都引用到。
屏幕适配一直是困扰工程师的重要课题,各种解决方案层出不穷,百分比布局、响应式设计(媒体查询)、媒体查询与rem结合等方案都各有所长,综合而言,媒体查询与rem、Javascript配合使用的方案最优,但是将px转换为rem需要不停的计算,对一个大型项目会有很多的样式代码,转换的工作量是巨大,有没有一种自动化的解决方案呢?
Hublider提供了解决方法:可在工具>>选项或右键项目>>属性下的代码助手设置中配置。参阅http://ask.dcloud.net.cn/article/982
开发实践中经历了从最初的PC固定布局、手机端固定布局(两端留白)到响应式设计(媒体查询、百分比布局等),直到最终选择rem+Javascript的模式,但是在项目开发中需要将大量的样式由px转换为rem,单位之间的换算虽然不复杂,但是工作量却很大。
这里的参数选择和你在项目中的设计图尺寸和根元素字体大小相关,至于border的处理是因为在安卓下使用rem单位的支持性特别差,你可能写2rem或者3rem都没用默认会变成1px,所以在使用border属性时很多时候不建议处理border。
Javascript控制根元素大小的代码如下图所示,读者可以将代码放在公共的Js文件中,确保每个HTML文件都引用到。

纯web项目不能使用mui.preload进行页面预加载的解决办法
首先:
纯web项目不能使用mui.preload进行页面预加载的, 比如基于微信的web项目
怎么办呢? 自己写个简单的吧
1.需依赖 jQuery, mui 框架和mui基本样式库
-
iMuiPage.js 内容:
/*--------------------------------------------------------------------* * iMuiPage v2016-7-7 * 只加载页面中body标签内的部分,等同$(document.body).html() * window._iMuiAct 当前显示页的 iMuiPage 对象 * window._iMuiMshDv 加载等待的dom jq对象 * window._iMuiPageObj[] 所有iMuiPage 对象数组 * window._impEvent 当前加载页dom的jq对象, dom创建时刷新 * 加载页事件定义 * init事件 dom创建完成后触发 * show事件 显示完成后触发 * hide事件 隐藏完成后触发 * body尾部加上下面的js * _impEvent.on('init[show|hide]',function(event,imp){this...}); * 参数: event window的event对象,imp iMuiPage对象, this 加载页dom对象 *---------------------------------------------------------------------*/ var iMuiPage=function(opts, pel){ var qp=$(pel); var pi=qp[0]?qp[0]:null; //页对象 不存在则创建 //pel 初始页dom对象或jq筛选条件 //opts 参数 var df = { url:null, //页面地址 data:null, //页面提交数据{....} id: null, //页面id 默认页对象id 若无则为页面url save:1, //是否缓存,不缓存隐藏后即销毁dom setdf:0, //设为根页, 即 window._iMuiPageObj[0] reload:0, //是否每次重新加载, 缓存时有效 refresh:0, //强制重新加载, 重载后该值恢复为0 autoshow:1, //是否加载完成显示 waithtml:'<div class="waiticon">' +'<div class="bounce1"></div><div class="bounce2"></div>' +'<div class="bounce3"></div></div>', //等待提示内容 error:function(){}, //错误处理 hide:function(){}, //隐藏前处理,可与事件并用, 在hide事件前调用 show: function() {}, //显示前处理,可与事件并用, 在show事件前调用 loaded: function() {} //加载前成处理,可与事件并用, 在init事件前调用 }; var pms = {}; opts = opts || {}; for (var k in df) pms[k] = opts[k]==undefined? df[k] : opts[k]; if(!pms.url) return null; //获取或创建等待dom function gMsgdv(){ var g=window._iMuiMshDv; if(!g || !g[0]){ g=$(document.createElement('div')) .attr('class','loadmsgdv'); $(document.body).append(g); g.hide(); } window._iMuiMshDv=g.html(pms.waithtml); return g; }; //获取当前页id, 即此新开页的返回id function gbackid(){ if(pms.setdf) return pms.id; if(!window._iMuiAct) return ''; return window._iMuiAct.pm.id; }; //截取body内容 function exBody(str) { if (!str) return ''; var ar = str.match(/<body.*?>([\s\S]+)<\/body>/i); return (ar&&ar.length > 1) ? ar[1] : ''; }; //根据页id获取iMuiPage原型对象 var _gimp=function(id){ var g=null; $.each(window._iMuiPageObj, function(i,o){ if(o && o.pm.id==id){ g=o; return; } }); return g; }, _code= function(s){return encodeURIComponent(s)}, _uncode= function(s){return decodeURIComponent(s)}; //iMuiPage原型即c属性方法 var c={ el:pi, //当前页面dom对象 pi._imp=this iMuiPage原型 index:0, //页面索引 backid:'', //返回页id pm:pms,//原始参数 mark:null,//遮罩 gimp:_gimp,//根据页id获取原型对象 code :_code,//编码 uncode : _uncode,//解码 showwait:function(open){ if(!pms.autoshow&&!open) return; this.mark= mui.createMask(function(){return false}); this.mark.show(); gMsgdv().show(); return this; }, hidewait:function(open){ if(!pms.autoshow&&!open) return; gMsgdv().hide(); this.mark._remove(); return this; }, hide:function(){ var p=window._iMuiAct; if(p && p.pm.id==pms.id) window._iMuiAct=null; if($.isFunction(pms.hide)) pms.hide(this); qp.fadeOut(500).trigger('hide',this); if(!pms.save) this.die(); console.log(this.index,'pms.id hide',pms.id); return this; }, show:function(){ //本页显示前设置返回页id if(!this.backid) this.backid=gbackid(); var act=window._iMuiAct; if(act && act.pm.id!=pms.id) window._iMuiAct.hide(); if($.isFunction(pms.show)) pms.show(this); qp.fadeIn(500); window._iMuiAct=this; qp.trigger('show',this); console.log(this.index,'show',pms.id); return this; }, back:function(){ console.log(this.index,'back',pms.id); if(this.index==0) return this; var p=_gimp(this.backid) || window._iMuiPageObj[0]; if(!p) return this; console.log(this.index,' -> ',p.index,'toback -> ',p.pm.id); this.hide(); if(p.pm.reload) return p.load(); return p.show(); }, clear:function(){ var r=this.back(); this.die(); return r; }, test:function(){ if(!console){alert('iMuiPage.test ...'); return;} console.log('iMuiPage.test',this); }, //销毁dom die:function (){ var p=window._iMuiPageObj[this.index]; if(p) window._iMuiPageObj[this.index]=null; if(!p.el) return; console.log(p.index,'die: ',p.pm.id); $(p.el).remove(); p=null; } }; //加载或重载url c.load=function(){ this.showwait(); console.log(this.index,'toload',pms.id,pms.data); $.ajax({url: pms.url, data: pms.data, cache: false, dataType: 'html', context: this, //回传this success:function(str,status){ this.hidewait(); //this.backid=gbackid(); //show中定义了 本页显示前设置 window._impEvent=qp; if($.isFunction(pms.loaded)) pms.loaded(this); qp.off().die(); //销毁前定义事件, 防止重复 console.log(this.index,'event.die',pms.id); var htm=exBody(str), wback=qp.html(htm).find('.w-back')[0]; if(wback) wback._imp=this; qp.trigger('init', this); if(pms.autoshow) this.show(); }, error:function(ajx,status){ if($.isFunction(pms.error)) pms.error(ajx,status,this); } }); return this; } // 初始化方法 c.init = function() { if(!window._iMuiPageObj){ window._iMuiPageObj=[]; $(window).resize(function(){ this._wh=document.documentElement.clientHeight; }); } if(pi) pms.id=qp.attr('id'); pms.id=pms.id || _code(pms.url); console.log('init',pms.id); var cx=_gimp(pms.id); if(!pi){//无页对象创建 if(!cx){//检查无重名对象, 创建 pi=document.createElement('div'); qp=$(pi).attr({id:pms.id, class:'w-page'}); $(document.body).append(pi); qp.hide(); console.log('this.create',pms.id); }else{ pi=cx.el; qp=$(pi); console.log(cx.index,'this.find',pms.id); } } pi._imp=this; this.el=pi; if(cx){//已存在 if(pms.setdf){//设置为根页 if(cx.index!=0){ window._iMuiPageObj[cx.index]=null; cx.index=0; this.save=1; this.backid=pms.id; } } this.index=cx.index; this.backid=cx.backid; window._iMuiPageObj[cx.index]=this; if(cx.pm.url==pms.url){ if(pms.reload||!pms.save||pms.refresh){pms.refresh=0;return this.load()}; return this.show(); } }else{ qp.css('height',window._wh+'px'); if(pms.setdf){//设置为根页,并销毁原根页dom if(window._iMuiPageObj[0]) window._iMuiPageObj[0].die(); this.index=0; this.save=1; this.backid=pms.id; window._iMuiPageObj[0]=this; }else this.index=window._iMuiPageObj.push(this)-1; } console.log(this.index,'endinit',pms.id); if(pel && this.index==0) return this; return this.load(); }; return c.init(); } /*初始化事件*/ function iMuiPageInit(){ if(window._iMuiPageObj) return; var de=$('.w-page')[0]; if(!de) return; var u=document.location.pathname+document.location.search; console.log('iMuiPageInit',u); window._iMuiAct=iMuiPage({save:1,setdf:1,url:u},de); $('.w-back').off().die().live('tap',function(){ if(!this._imp) return; console.log('w-back.tap',this._imp.pm.id); this._imp.back(); }); //iMuiPage({url:'welcome.htm',save:0}); } $(function(){ window._wh=document.documentElement.clientHeight; iMuiPageInit(); });
3.调用方法:
//下例可作为预加载或是隐式刷新 iMuiPage({url:'xxx.html',save:1,setdf:1,autoshow:0,refresh:1}); //下例直接打开一个页面 iMuiPage({url:'xxx.html'}); //参数说明 var df = { url:null, //页面地址 data:null, //页面提交数据{....} id: null, //页面id 默认页对象id 若无则为页面url save:1, //是否缓存,不缓存隐藏后即销毁dom setdf:0, //设为根页, 即 window._iMuiPageObj[0] reload:0, //是否每次重新加载, 缓存时有效 refresh:0, //强制重新加载, 重载后该值恢复为0 autoshow:1, //是否加载完成显示 waithtml:'<div class="waiticon">' +'<div class="bounce1"></div><div class="bounce2"></div>' +'<div class="bounce3"></div></div>', //等待提示内容 error:function(){}, //错误处理 hide:function(){}, //隐藏前处理,可与事件并用, 在hide事件前调用 show: function() {}, //显示前处理,可与事件并用, 在show事件前调用 loaded: function() {} //加载前成处理,可与事件并用, 在init事件前调用 };
4.附加样式
/*waiticon -----*/ .waiticon {margin:30px auto 0; width: 150px; text-align: center;} .waiticon > div { width: 30px; height: 30px; background-color: #FE4900; border-radius: 100%; display: inline-block; -webkit-animation: bouncedelay 1.4s infinite ease-in-out; animation: bouncedelay 1.4s infinite ease-in-out; /* Prevent first frame from flickering when animation starts */ -webkit-animation-fill-mode: both; animation-fill-mode: both; } .waiticon .bounce1 { -webkit-animation-delay: -0.32s; animation-delay: -0.32s; } .waiticon .bounce2 { -webkit-animation-delay: -0.16s; animation-delay: -0.16s; } @-webkit-keyframes bouncedelay { 0%, 80%, 100% { -webkit-transform: scale(0.0) } 40% { -webkit-transform: scale(1.0) }} /*waiticon ---end--*/
6.页面布局
<!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">
<link rel="stylesheet" href="css/mui.min.css">
<script src="jquery/jquery.min.js"></script>
<script src="js/mui.min.js"></script>
<script src="js/iMuiPage.js"></script>
<title>iMuiPage示例</title>
</head>
<body>
<div class="w-page">
<header class="mui-bar mui-bar-nav">
<a class="w-back mui-icon mui-icon-left-nav mui-pull-left">返回</a>
<h1 class="mui-title fcfff">iMuiPage示例</h1>
</header>
<div class="mui-content mui-scroll-wrapper">
<div class="mui-scroll">
<ul class="mui-table-view lstbar">
<li class="mui-table-view-cell mui-media">
<a class="mui-navigate-right" url="xxx1.html">
<div class="mui-media-body">
<span class="mui-icon mui-icon-arrowright"></span>xxx1.html
</div>
</a>
</li>
<li class="mui-table-view-cell mui-media">
<a class="mui-navigate-right" url="xxx2.html">
<div class="mui-media-body">
<span class="mui-icon mui-icon-arrowright"></span>xxx2.html
</div>
</a>
</li>
</ul>
</div>
</div>
</div>
<script>
(function($m){
var qi,qback;
function init(){
qback=$('.w-back',qi);
$('a[url]',qi).on('tap',function(){
if(!this._url) this._url=$(this).attr('url');
if(!this._url || this._url.match(/#+/i)) return;
console.log('a.tap:',this._url);
iMuiPage({url:this._url,reload:1});
return false;
});
/*
$(function(){
//重定义返回按钮点击事件
qback.off().die().on('tap',function(){
this._imp=null;
iMuiPage({url:'dft.html',save:1,reload:1});
});
});*/
}
function show(){
$m('.mui-scroll-wrapper',qi[0]).scroll({
indicators: true //是否显示滚动条
});
}
if(!window._impEvent){
qi=$('.w-page');
$m.init({swipeBack: false});
$('.w-back',qi).html('首页');
init(); show(); return;
}
qi=_impEvent;
qi.on('init',function(evt,imp){
init();
console.log(this.id,'init....');
}).on('show',function(){
show();
console.log(this.id,'show....');
}).on('hide',function(){
console.log(this.id,'hide....');
});
})(mui);
</script>
</body>
</html>
以上涉及2个关键命名样式 w-page, w-back
w-page: 页面根容器加上此样式名
w-back: 返回按钮加上此样式名
更多精彩内容请访问DCloud官网(http://www.dcloud.io/)
2016-11-23 修正 iMuiPageInit 中一个小BUG
2016-11-29 修正 c.init 中一个小BUG
不知道115云盘? 雨林木风该知道吧, 赖霖枫出品滴~~推荐!!
首先:
纯web项目不能使用mui.preload进行页面预加载的, 比如基于微信的web项目
怎么办呢? 自己写个简单的吧
1.需依赖 jQuery, mui 框架和mui基本样式库
-
iMuiPage.js 内容:
/*--------------------------------------------------------------------* * iMuiPage v2016-7-7 * 只加载页面中body标签内的部分,等同$(document.body).html() * window._iMuiAct 当前显示页的 iMuiPage 对象 * window._iMuiMshDv 加载等待的dom jq对象 * window._iMuiPageObj[] 所有iMuiPage 对象数组 * window._impEvent 当前加载页dom的jq对象, dom创建时刷新 * 加载页事件定义 * init事件 dom创建完成后触发 * show事件 显示完成后触发 * hide事件 隐藏完成后触发 * body尾部加上下面的js * _impEvent.on('init[show|hide]',function(event,imp){this...}); * 参数: event window的event对象,imp iMuiPage对象, this 加载页dom对象 *---------------------------------------------------------------------*/ var iMuiPage=function(opts, pel){ var qp=$(pel); var pi=qp[0]?qp[0]:null; //页对象 不存在则创建 //pel 初始页dom对象或jq筛选条件 //opts 参数 var df = { url:null, //页面地址 data:null, //页面提交数据{....} id: null, //页面id 默认页对象id 若无则为页面url save:1, //是否缓存,不缓存隐藏后即销毁dom setdf:0, //设为根页, 即 window._iMuiPageObj[0] reload:0, //是否每次重新加载, 缓存时有效 refresh:0, //强制重新加载, 重载后该值恢复为0 autoshow:1, //是否加载完成显示 waithtml:'<div class="waiticon">' +'<div class="bounce1"></div><div class="bounce2"></div>' +'<div class="bounce3"></div></div>', //等待提示内容 error:function(){}, //错误处理 hide:function(){}, //隐藏前处理,可与事件并用, 在hide事件前调用 show: function() {}, //显示前处理,可与事件并用, 在show事件前调用 loaded: function() {} //加载前成处理,可与事件并用, 在init事件前调用 }; var pms = {}; opts = opts || {}; for (var k in df) pms[k] = opts[k]==undefined? df[k] : opts[k]; if(!pms.url) return null; //获取或创建等待dom function gMsgdv(){ var g=window._iMuiMshDv; if(!g || !g[0]){ g=$(document.createElement('div')) .attr('class','loadmsgdv'); $(document.body).append(g); g.hide(); } window._iMuiMshDv=g.html(pms.waithtml); return g; }; //获取当前页id, 即此新开页的返回id function gbackid(){ if(pms.setdf) return pms.id; if(!window._iMuiAct) return ''; return window._iMuiAct.pm.id; }; //截取body内容 function exBody(str) { if (!str) return ''; var ar = str.match(/<body.*?>([\s\S]+)<\/body>/i); return (ar&&ar.length > 1) ? ar[1] : ''; }; //根据页id获取iMuiPage原型对象 var _gimp=function(id){ var g=null; $.each(window._iMuiPageObj, function(i,o){ if(o && o.pm.id==id){ g=o; return; } }); return g; }, _code= function(s){return encodeURIComponent(s)}, _uncode= function(s){return decodeURIComponent(s)}; //iMuiPage原型即c属性方法 var c={ el:pi, //当前页面dom对象 pi._imp=this iMuiPage原型 index:0, //页面索引 backid:'', //返回页id pm:pms,//原始参数 mark:null,//遮罩 gimp:_gimp,//根据页id获取原型对象 code :_code,//编码 uncode : _uncode,//解码 showwait:function(open){ if(!pms.autoshow&&!open) return; this.mark= mui.createMask(function(){return false}); this.mark.show(); gMsgdv().show(); return this; }, hidewait:function(open){ if(!pms.autoshow&&!open) return; gMsgdv().hide(); this.mark._remove(); return this; }, hide:function(){ var p=window._iMuiAct; if(p && p.pm.id==pms.id) window._iMuiAct=null; if($.isFunction(pms.hide)) pms.hide(this); qp.fadeOut(500).trigger('hide',this); if(!pms.save) this.die(); console.log(this.index,'pms.id hide',pms.id); return this; }, show:function(){ //本页显示前设置返回页id if(!this.backid) this.backid=gbackid(); var act=window._iMuiAct; if(act && act.pm.id!=pms.id) window._iMuiAct.hide(); if($.isFunction(pms.show)) pms.show(this); qp.fadeIn(500); window._iMuiAct=this; qp.trigger('show',this); console.log(this.index,'show',pms.id); return this; }, back:function(){ console.log(this.index,'back',pms.id); if(this.index==0) return this; var p=_gimp(this.backid) || window._iMuiPageObj[0]; if(!p) return this; console.log(this.index,' -> ',p.index,'toback -> ',p.pm.id); this.hide(); if(p.pm.reload) return p.load(); return p.show(); }, clear:function(){ var r=this.back(); this.die(); return r; }, test:function(){ if(!console){alert('iMuiPage.test ...'); return;} console.log('iMuiPage.test',this); }, //销毁dom die:function (){ var p=window._iMuiPageObj[this.index]; if(p) window._iMuiPageObj[this.index]=null; if(!p.el) return; console.log(p.index,'die: ',p.pm.id); $(p.el).remove(); p=null; } }; //加载或重载url c.load=function(){ this.showwait(); console.log(this.index,'toload',pms.id,pms.data); $.ajax({url: pms.url, data: pms.data, cache: false, dataType: 'html', context: this, //回传this success:function(str,status){ this.hidewait(); //this.backid=gbackid(); //show中定义了 本页显示前设置 window._impEvent=qp; if($.isFunction(pms.loaded)) pms.loaded(this); qp.off().die(); //销毁前定义事件, 防止重复 console.log(this.index,'event.die',pms.id); var htm=exBody(str), wback=qp.html(htm).find('.w-back')[0]; if(wback) wback._imp=this; qp.trigger('init', this); if(pms.autoshow) this.show(); }, error:function(ajx,status){ if($.isFunction(pms.error)) pms.error(ajx,status,this); } }); return this; } // 初始化方法 c.init = function() { if(!window._iMuiPageObj){ window._iMuiPageObj=[]; $(window).resize(function(){ this._wh=document.documentElement.clientHeight; }); } if(pi) pms.id=qp.attr('id'); pms.id=pms.id || _code(pms.url); console.log('init',pms.id); var cx=_gimp(pms.id); if(!pi){//无页对象创建 if(!cx){//检查无重名对象, 创建 pi=document.createElement('div'); qp=$(pi).attr({id:pms.id, class:'w-page'}); $(document.body).append(pi); qp.hide(); console.log('this.create',pms.id); }else{ pi=cx.el; qp=$(pi); console.log(cx.index,'this.find',pms.id); } } pi._imp=this; this.el=pi; if(cx){//已存在 if(pms.setdf){//设置为根页 if(cx.index!=0){ window._iMuiPageObj[cx.index]=null; cx.index=0; this.save=1; this.backid=pms.id; } } this.index=cx.index; this.backid=cx.backid; window._iMuiPageObj[cx.index]=this; if(cx.pm.url==pms.url){ if(pms.reload||!pms.save||pms.refresh){pms.refresh=0;return this.load()}; return this.show(); } }else{ qp.css('height',window._wh+'px'); if(pms.setdf){//设置为根页,并销毁原根页dom if(window._iMuiPageObj[0]) window._iMuiPageObj[0].die(); this.index=0; this.save=1; this.backid=pms.id; window._iMuiPageObj[0]=this; }else this.index=window._iMuiPageObj.push(this)-1; } console.log(this.index,'endinit',pms.id); if(pel && this.index==0) return this; return this.load(); }; return c.init(); } /*初始化事件*/ function iMuiPageInit(){ if(window._iMuiPageObj) return; var de=$('.w-page')[0]; if(!de) return; var u=document.location.pathname+document.location.search; console.log('iMuiPageInit',u); window._iMuiAct=iMuiPage({save:1,setdf:1,url:u},de); $('.w-back').off().die().live('tap',function(){ if(!this._imp) return; console.log('w-back.tap',this._imp.pm.id); this._imp.back(); }); //iMuiPage({url:'welcome.htm',save:0}); } $(function(){ window._wh=document.documentElement.clientHeight; iMuiPageInit(); });
3.调用方法:
//下例可作为预加载或是隐式刷新 iMuiPage({url:'xxx.html',save:1,setdf:1,autoshow:0,refresh:1}); //下例直接打开一个页面 iMuiPage({url:'xxx.html'}); //参数说明 var df = { url:null, //页面地址 data:null, //页面提交数据{....} id: null, //页面id 默认页对象id 若无则为页面url save:1, //是否缓存,不缓存隐藏后即销毁dom setdf:0, //设为根页, 即 window._iMuiPageObj[0] reload:0, //是否每次重新加载, 缓存时有效 refresh:0, //强制重新加载, 重载后该值恢复为0 autoshow:1, //是否加载完成显示 waithtml:'<div class="waiticon">' +'<div class="bounce1"></div><div class="bounce2"></div>' +'<div class="bounce3"></div></div>', //等待提示内容 error:function(){}, //错误处理 hide:function(){}, //隐藏前处理,可与事件并用, 在hide事件前调用 show: function() {}, //显示前处理,可与事件并用, 在show事件前调用 loaded: function() {} //加载前成处理,可与事件并用, 在init事件前调用 };
4.附加样式
/*waiticon -----*/ .waiticon {margin:30px auto 0; width: 150px; text-align: center;} .waiticon > div { width: 30px; height: 30px; background-color: #FE4900; border-radius: 100%; display: inline-block; -webkit-animation: bouncedelay 1.4s infinite ease-in-out; animation: bouncedelay 1.4s infinite ease-in-out; /* Prevent first frame from flickering when animation starts */ -webkit-animation-fill-mode: both; animation-fill-mode: both; } .waiticon .bounce1 { -webkit-animation-delay: -0.32s; animation-delay: -0.32s; } .waiticon .bounce2 { -webkit-animation-delay: -0.16s; animation-delay: -0.16s; } @-webkit-keyframes bouncedelay { 0%, 80%, 100% { -webkit-transform: scale(0.0) } 40% { -webkit-transform: scale(1.0) }} /*waiticon ---end--*/
6.页面布局
<!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">
<link rel="stylesheet" href="css/mui.min.css">
<script src="jquery/jquery.min.js"></script>
<script src="js/mui.min.js"></script>
<script src="js/iMuiPage.js"></script>
<title>iMuiPage示例</title>
</head>
<body>
<div class="w-page">
<header class="mui-bar mui-bar-nav">
<a class="w-back mui-icon mui-icon-left-nav mui-pull-left">返回</a>
<h1 class="mui-title fcfff">iMuiPage示例</h1>
</header>
<div class="mui-content mui-scroll-wrapper">
<div class="mui-scroll">
<ul class="mui-table-view lstbar">
<li class="mui-table-view-cell mui-media">
<a class="mui-navigate-right" url="xxx1.html">
<div class="mui-media-body">
<span class="mui-icon mui-icon-arrowright"></span>xxx1.html
</div>
</a>
</li>
<li class="mui-table-view-cell mui-media">
<a class="mui-navigate-right" url="xxx2.html">
<div class="mui-media-body">
<span class="mui-icon mui-icon-arrowright"></span>xxx2.html
</div>
</a>
</li>
</ul>
</div>
</div>
</div>
<script>
(function($m){
var qi,qback;
function init(){
qback=$('.w-back',qi);
$('a[url]',qi).on('tap',function(){
if(!this._url) this._url=$(this).attr('url');
if(!this._url || this._url.match(/#+/i)) return;
console.log('a.tap:',this._url);
iMuiPage({url:this._url,reload:1});
return false;
});
/*
$(function(){
//重定义返回按钮点击事件
qback.off().die().on('tap',function(){
this._imp=null;
iMuiPage({url:'dft.html',save:1,reload:1});
});
});*/
}
function show(){
$m('.mui-scroll-wrapper',qi[0]).scroll({
indicators: true //是否显示滚动条
});
}
if(!window._impEvent){
qi=$('.w-page');
$m.init({swipeBack: false});
$('.w-back',qi).html('首页');
init(); show(); return;
}
qi=_impEvent;
qi.on('init',function(evt,imp){
init();
console.log(this.id,'init....');
}).on('show',function(){
show();
console.log(this.id,'show....');
}).on('hide',function(){
console.log(this.id,'hide....');
});
})(mui);
</script>
</body>
</html>
以上涉及2个关键命名样式 w-page, w-back
w-page: 页面根容器加上此样式名
w-back: 返回按钮加上此样式名
更多精彩内容请访问DCloud官网(http://www.dcloud.io/)
2016-11-23 修正 iMuiPageInit 中一个小BUG
2016-11-29 修正 c.init 中一个小BUG
不知道115云盘? 雨林木风该知道吧, 赖霖枫出品滴~~推荐!!

新手研究node socket.io 一个星期的分享
新项目要聊天。居然要 node.js写。。好吧。扛起大旗去研究node。
去socket.io 官网看了一眼居然提供有代码示例 和详解。
基本情况找着抄了一遍代码逻辑基本上已经会了。但是文件就2.。。。好像有点寒酸。
而且 静态资源无法发送到客户端。。于是打算用express框架。
简单了解了下。好方便。express SubjectName 就能创建一个目录文档出来。
运行起来 localhost:3000一切正常。整合程序时候发现 jade 什么鬼。。找度娘科普了一下。。
新东西。我的 demo已经写好了。不想用。。果断的 换HTML。卸载了jade模块,。。按照官网写法引入 ejs。运行
各种BUG 各种报错。。。区区几个BUG 怎么可能打到我。。百度开始查阅各种资料。感觉比 Hbuilder的文档还少
最终看到了 express -e ejs SubjectName。是创建ejs的。直接创建 默认 jade的。。马上备份了一下删除项目。重新创建
ejs换成了html 运行。看到了窗口和静态资源全出现了 虎躯一震。。
忽然考虑 路由 和 socket.io 分开了。。。。我用啥玩意获取 地址栏传入参数。。。。
好吧,继续百度上找 毕竟困难是指引自己的道路。。过了许久。。。居然 没有。。好不容易有个知道没答案。。
我去。。。跟我们社区一个样啊。只好自己想办法了。。
正惆怅的时候 忽然间 想到 用 for in 遍历下 回调参数。。。。然后console.对象 输出出来。
黄天不负有心人啊。。。让我看到了 地址都在。。好感度。。。去百度那个问题回答一下。
回调函数..request.headers 就是这么简单的东西。
后言。我发现许多东西 我可能知道。我想要的问题别人可能知道,对我来说困难的在别人眼中可能非常简单。
帮助了别人也充实了自己。虽然我很菜。但我也想自己出一份力。不做一个伸手党
新项目要聊天。居然要 node.js写。。好吧。扛起大旗去研究node。
去socket.io 官网看了一眼居然提供有代码示例 和详解。
基本情况找着抄了一遍代码逻辑基本上已经会了。但是文件就2.。。。好像有点寒酸。
而且 静态资源无法发送到客户端。。于是打算用express框架。
简单了解了下。好方便。express SubjectName 就能创建一个目录文档出来。
运行起来 localhost:3000一切正常。整合程序时候发现 jade 什么鬼。。找度娘科普了一下。。
新东西。我的 demo已经写好了。不想用。。果断的 换HTML。卸载了jade模块,。。按照官网写法引入 ejs。运行
各种BUG 各种报错。。。区区几个BUG 怎么可能打到我。。百度开始查阅各种资料。感觉比 Hbuilder的文档还少
最终看到了 express -e ejs SubjectName。是创建ejs的。直接创建 默认 jade的。。马上备份了一下删除项目。重新创建
ejs换成了html 运行。看到了窗口和静态资源全出现了 虎躯一震。。
忽然考虑 路由 和 socket.io 分开了。。。。我用啥玩意获取 地址栏传入参数。。。。
好吧,继续百度上找 毕竟困难是指引自己的道路。。过了许久。。。居然 没有。。好不容易有个知道没答案。。
我去。。。跟我们社区一个样啊。只好自己想办法了。。
正惆怅的时候 忽然间 想到 用 for in 遍历下 回调参数。。。。然后console.对象 输出出来。
黄天不负有心人啊。。。让我看到了 地址都在。。好感度。。。去百度那个问题回答一下。
回调函数..request.headers 就是这么简单的东西。
后言。我发现许多东西 我可能知道。我想要的问题别人可能知道,对我来说困难的在别人眼中可能非常简单。
帮助了别人也充实了自己。虽然我很菜。但我也想自己出一份力。不做一个伸手党

关于aes加密(一)
https://developer.mozilla.org/en-US/docs/Web/API/Crypto
https://chromium.googlesource.com/chromium/blink/+/72fef91ac1ef679207f51def81
http://www.oschina.net/code/snippet_552425_46178
<!doctype html>
<html>
<head>
<meta charset='UTF-8'>
</head>
<body>
<div class='test'></div>
<script type="text/javascript">
function encrypt(data, keyJSON){
var data = new TextEncoder("UTF-8").encode(data);
var randomsKeys = geneRandomHexStr(64); // 128 bit keys
var encryptedKey = hexStringToUint8Array(randomsKeys);
var aesAlgo = {name: 'aes-cbc', iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
return crypto.subtle.importKey("jwk", keyJSON, {name: "rsa-oaep", hash: {name: "sha-256"}},true, ['encrypt'])
.then(function(publicKey){
return crypto.subtle.encrypt({name: "rsa-oaep"}, publicKey, encryptedKey);
}).then(function(res){
encryptedKey = bytesToHexString(res)
// use aes to encrypt data
// import aes key
return crypto.subtle.importKey('raw',
hexStringToUint8Array(randomsKeys) , aesAlgo, false, ['encrypt', 'decrypt']);
}).then(function(result){
// use aes to encode
return crypto.subtle.encrypt(aesAlgo,
result, data);
}).then(function(encryptedData){
return Promise.resolve({
'encrypted': bytesToHexString(encryptedData),
'encryptedKey': encryptedKey,
});
});
//console.log(new TextDecoder("UTF-8").decode(data));
// use server public key to encrypt
}
function decrypt(data, keyJSON){
// use local private key to decrypt
var encryptedKey = new hexStringToUint8Array(data.encryptedKey);
var encryptedData = new hexStringToUint8Array(data.encrypted);
var aesAlgo = {name: 'aes-cbc', iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
// decrypt key
return crypto.subtle.importKey('jwk', keyJSON, {name: "rsa-oaep", hash: {name: "sha-256"}}, true,
['decrypt']).then(function(privateKey){
return crypto.subtle.decrypt({name: 'rsa-oaep'}, privateKey, encryptedKey);
}).then(function(decryptedKey){
// import aes key
return crypto.subtle.importKey('raw',
decryptedKey, aesAlgo, false, ['encrypt', 'decrypt']);
}).catch(function(){
console.error("decrypt error");
}).then(function(result){
// decode encrypted data
return crypto.subtle.decrypt(aesAlgo, result, encryptedData);
}).then(function(data){
return Promise.resolve(new TextDecoder("UTF-8").decode(new Uint8Array(data)));
})
}
function createNewUserKey(){
var algorithmKeyGen = {
name: "RSA-OAEP",
hash: {name: "sha-256"},
// RsaKeyGenParams
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // Equivalent to 65537
};
var nonExtractable = false;
var publicKey = "";
var privateKey = "";
var keyPairs = "";
return crypto.subtle.generateKey(algorithmKeyGen, true, ['encrypt', 'decrypt']).then(function(result) {
// gene key pair
keyPairs = result;
return Promise.all([crypto.subtle.exportKey("jwk", keyPairs.publicKey),
crypto.subtle.exportKey("jwk", keyPairs.privateKey)]);
})
}
function _arrayBufferToBase64( buffer ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa( binary );
}
function hexStringToUint8Array(hexString) {
if (hexString.length % 2 != 0)
throw "Invalid hexString";
var arrayBuffer = new Uint8Array(hexString.length / 2);
for (var i = 0; i < hexString.length; i += 2) {
var byteValue = parseInt(hexString.substr(i, 2), 16);
if (byteValue == NaN)
throw "Invalid hexString";
arrayBuffer[i/2] = byteValue;
}
return arrayBuffer;
}
function bytesToHexString(bytes) {
if (!bytes)
return null;
bytes = new Uint8Array(bytes);
var hexBytes = [];
for (var i = 0; i < bytes.length; ++i) {
var byteString = bytes[i].toString(16);
if (byteString.length < 2)
byteString = "0" + byteString;
hexBytes.push(byteString);
}
return hexBytes.join("");
}
function geneRandomHexStr(length){
var text = "";
var possible = "0123456789abcdef";
for( var i=0; i < length; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
createNewUserKey().then(function(keyPairs){
encrypt("this is origin text", keyPairs[0]).then(function(res){
console.log('public', JSON.stringify(keyPairs[0]));
console.log('private', JSON.stringify(keyPairs[1]));
decrypt(res, keyPairs[1]).then(function(decrypted){
console.log('decrypted', decrypted);
});
});
})
</script>
</body>
</html>
https://developer.mozilla.org/en-US/docs/Web/API/Crypto
https://chromium.googlesource.com/chromium/blink/+/72fef91ac1ef679207f51def81
http://www.oschina.net/code/snippet_552425_46178
<!doctype html>
<html>
<head>
<meta charset='UTF-8'>
</head>
<body>
<div class='test'></div>
<script type="text/javascript">
function encrypt(data, keyJSON){
var data = new TextEncoder("UTF-8").encode(data);
var randomsKeys = geneRandomHexStr(64); // 128 bit keys
var encryptedKey = hexStringToUint8Array(randomsKeys);
var aesAlgo = {name: 'aes-cbc', iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
return crypto.subtle.importKey("jwk", keyJSON, {name: "rsa-oaep", hash: {name: "sha-256"}},true, ['encrypt'])
.then(function(publicKey){
return crypto.subtle.encrypt({name: "rsa-oaep"}, publicKey, encryptedKey);
}).then(function(res){
encryptedKey = bytesToHexString(res)
// use aes to encrypt data
// import aes key
return crypto.subtle.importKey('raw',
hexStringToUint8Array(randomsKeys) , aesAlgo, false, ['encrypt', 'decrypt']);
}).then(function(result){
// use aes to encode
return crypto.subtle.encrypt(aesAlgo,
result, data);
}).then(function(encryptedData){
return Promise.resolve({
'encrypted': bytesToHexString(encryptedData),
'encryptedKey': encryptedKey,
});
});
//console.log(new TextDecoder("UTF-8").decode(data));
// use server public key to encrypt
}
function decrypt(data, keyJSON){
// use local private key to decrypt
var encryptedKey = new hexStringToUint8Array(data.encryptedKey);
var encryptedData = new hexStringToUint8Array(data.encrypted);
var aesAlgo = {name: 'aes-cbc', iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
// decrypt key
return crypto.subtle.importKey('jwk', keyJSON, {name: "rsa-oaep", hash: {name: "sha-256"}}, true,
['decrypt']).then(function(privateKey){
return crypto.subtle.decrypt({name: 'rsa-oaep'}, privateKey, encryptedKey);
}).then(function(decryptedKey){
// import aes key
return crypto.subtle.importKey('raw',
decryptedKey, aesAlgo, false, ['encrypt', 'decrypt']);
}).catch(function(){
console.error("decrypt error");
}).then(function(result){
// decode encrypted data
return crypto.subtle.decrypt(aesAlgo, result, encryptedData);
}).then(function(data){
return Promise.resolve(new TextDecoder("UTF-8").decode(new Uint8Array(data)));
})
}
function createNewUserKey(){
var algorithmKeyGen = {
name: "RSA-OAEP",
hash: {name: "sha-256"},
// RsaKeyGenParams
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // Equivalent to 65537
};
var nonExtractable = false;
var publicKey = "";
var privateKey = "";
var keyPairs = "";
return crypto.subtle.generateKey(algorithmKeyGen, true, ['encrypt', 'decrypt']).then(function(result) {
// gene key pair
keyPairs = result;
return Promise.all([crypto.subtle.exportKey("jwk", keyPairs.publicKey),
crypto.subtle.exportKey("jwk", keyPairs.privateKey)]);
})
}
function _arrayBufferToBase64( buffer ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa( binary );
}
function hexStringToUint8Array(hexString) {
if (hexString.length % 2 != 0)
throw "Invalid hexString";
var arrayBuffer = new Uint8Array(hexString.length / 2);
for (var i = 0; i < hexString.length; i += 2) {
var byteValue = parseInt(hexString.substr(i, 2), 16);
if (byteValue == NaN)
throw "Invalid hexString";
arrayBuffer[i/2] = byteValue;
}
return arrayBuffer;
}
function bytesToHexString(bytes) {
if (!bytes)
return null;
bytes = new Uint8Array(bytes);
var hexBytes = [];
for (var i = 0; i < bytes.length; ++i) {
var byteString = bytes[i].toString(16);
if (byteString.length < 2)
byteString = "0" + byteString;
hexBytes.push(byteString);
}
return hexBytes.join("");
}
function geneRandomHexStr(length){
var text = "";
var possible = "0123456789abcdef";
for( var i=0; i < length; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
createNewUserKey().then(function(keyPairs){
encrypt("this is origin text", keyPairs[0]).then(function(res){
console.log('public', JSON.stringify(keyPairs[0]));
console.log('private', JSON.stringify(keyPairs[1]));
decrypt(res, keyPairs[1]).then(function(decrypted){
console.log('decrypted', decrypted);
});
});
})
</script>
</body>
</html>
收起阅读 »
前端动画制作,量大项目hold不过来,诚心找靠谱长期合作的前端技术人员合作(经常使用HBuilder的优先)
因为文件比较大上传源文件到百度云了,如有意愿加我QQ:2206367168,看完要做的项目的话,然后报价和工期,根据自己的能力来,我们这边的话根据你的能力和速度给到相应的单。具体的咱可以加QQ再聊,有不清楚的地方电话里面沟通也可以,是长期合作的项目,非诚勿扰。
因为文件比较大上传源文件到百度云了,如有意愿加我QQ:2206367168,看完要做的项目的话,然后报价和工期,根据自己的能力来,我们这边的话根据你的能力和速度给到相应的单。具体的咱可以加QQ再聊,有不清楚的地方电话里面沟通也可以,是长期合作的项目,非诚勿扰。

webview模式-缩放式侧滑(类手机QQ)
MUI提供了非常多的控件,我想其中的侧滑导航大多数MUI使用者都在使用,并且遇到不少难题,而我就是其中一个。大家可以发现MUI模板里面有一个非常亮眼的侧滑导航当属缩放式导航(类手机QQ),这是一个DIV模式的缩放式侧滑,它的优点是可以跟着手势滑动,缺点是不可以复用,其实它还有其它缺点,比如在主页面拥有子webview的情况下,这种缩放式侧滑就无法使用了,由于是div模式的,子webview并不会跟着一起缩放。这就不得不让人舍弃主页面的子webview了,但是一般主页面都有下拉刷新控件的,而下拉刷新最佳的拖动性能是必须使用一个单独的webview去装载下拉刷新,如下图,中间下拉刷新是一个webview,导航和底部菜单是一个webview,因此遇到这种情况我们就需要采用webview模式的缩放式侧滑。
这里我讲解一下我使用webview模式开发的缩放式侧滑,做的不好的地方请指教。首先有一个侧滑页面的webview和主页面的webview,主页面下有一个子webview。我们先预加载左边的侧滑页面member/left.html,代码如下:
// 预加载侧滑页面,先让页面藏在显示区域之外-100%
var memberLeftView = mui.preload({
url:'views/member/left.html',
id:'views/member/left.html',
styles: {
left: "-100%",
zindex: -9997,
render:'always'
}
});
然后在触发侧滑的时候设置页面webview的移动位置,侧滑页面首先右移到显示区域,主页面的webview移动到left: '70%',top: '10%',bottom: '10%',的位置,同时打开遮罩,动画300毫秒的移动时间,注意:切勿使用mui.createMash(callback);去创建遮罩,因为主页面是有子webview,会造成不同步且会出现闪动情况。接着在关闭遮罩的时候,再移回原来的位置,这样就实现了简单的webview模式的缩放式侧滑。注意:恢复正常界面的时候隐藏侧滑页面,避免资源消耗。代码如下:
// 我的头像的点击事件
document.getElementById('reho-left-me').addEventListener('tap', function() {
// 侧滑页面出现右移到显示区域
GO_Index.memberLeftView.show('none', 0, function() {
GO_Index.memberLeftView.setStyle({
left: '0',
});
});
// 主界面右移
GO_Index.indexView.show('none', 0, function() {
GO_Index.indexView.setStyle({
left: '70%',
top: '10%',
bottom: '10%',
mask: 'rgba(0,0,0,0.5)',
transition: {
duration: 300
}
});
});
// 每次移除遮罩点击事件,避免重复添加监听
GO_Index.indexView.removeEventListener('maskClick');
// 点击关闭遮罩时
GO_Index.indexView.addEventListener('maskClick', function(){
// 主界面移动到最大显示区域
GO_Index.indexView.setStyle({
left: '0',
top: '0',
bottom: '0',
mask: 'none',
transition: {
duration: 300
}
});
// 侧滑界面移出显示区域之外
GO_Index.memberLeftView.setStyle({
left: "-100%",
transition: {
duration: 300
}
});
// 隐藏侧滑页面,setTimeout避免竞争资源
setTimeout(function() {
GO_Index.memberLeftView.hide();
}, 300);
},false);
});
实现效果如下图:
(更多精彩内容请访问DCloud官网(http://www.dcloud.io/))
MUI提供了非常多的控件,我想其中的侧滑导航大多数MUI使用者都在使用,并且遇到不少难题,而我就是其中一个。大家可以发现MUI模板里面有一个非常亮眼的侧滑导航当属缩放式导航(类手机QQ),这是一个DIV模式的缩放式侧滑,它的优点是可以跟着手势滑动,缺点是不可以复用,其实它还有其它缺点,比如在主页面拥有子webview的情况下,这种缩放式侧滑就无法使用了,由于是div模式的,子webview并不会跟着一起缩放。这就不得不让人舍弃主页面的子webview了,但是一般主页面都有下拉刷新控件的,而下拉刷新最佳的拖动性能是必须使用一个单独的webview去装载下拉刷新,如下图,中间下拉刷新是一个webview,导航和底部菜单是一个webview,因此遇到这种情况我们就需要采用webview模式的缩放式侧滑。
这里我讲解一下我使用webview模式开发的缩放式侧滑,做的不好的地方请指教。首先有一个侧滑页面的webview和主页面的webview,主页面下有一个子webview。我们先预加载左边的侧滑页面member/left.html,代码如下:
// 预加载侧滑页面,先让页面藏在显示区域之外-100%
var memberLeftView = mui.preload({
url:'views/member/left.html',
id:'views/member/left.html',
styles: {
left: "-100%",
zindex: -9997,
render:'always'
}
});
然后在触发侧滑的时候设置页面webview的移动位置,侧滑页面首先右移到显示区域,主页面的webview移动到left: '70%',top: '10%',bottom: '10%',的位置,同时打开遮罩,动画300毫秒的移动时间,注意:切勿使用mui.createMash(callback);去创建遮罩,因为主页面是有子webview,会造成不同步且会出现闪动情况。接着在关闭遮罩的时候,再移回原来的位置,这样就实现了简单的webview模式的缩放式侧滑。注意:恢复正常界面的时候隐藏侧滑页面,避免资源消耗。代码如下:
// 我的头像的点击事件
document.getElementById('reho-left-me').addEventListener('tap', function() {
// 侧滑页面出现右移到显示区域
GO_Index.memberLeftView.show('none', 0, function() {
GO_Index.memberLeftView.setStyle({
left: '0',
});
});
// 主界面右移
GO_Index.indexView.show('none', 0, function() {
GO_Index.indexView.setStyle({
left: '70%',
top: '10%',
bottom: '10%',
mask: 'rgba(0,0,0,0.5)',
transition: {
duration: 300
}
});
});
// 每次移除遮罩点击事件,避免重复添加监听
GO_Index.indexView.removeEventListener('maskClick');
// 点击关闭遮罩时
GO_Index.indexView.addEventListener('maskClick', function(){
// 主界面移动到最大显示区域
GO_Index.indexView.setStyle({
left: '0',
top: '0',
bottom: '0',
mask: 'none',
transition: {
duration: 300
}
});
// 侧滑界面移出显示区域之外
GO_Index.memberLeftView.setStyle({
left: "-100%",
transition: {
duration: 300
}
});
// 隐藏侧滑页面,setTimeout避免竞争资源
setTimeout(function() {
GO_Index.memberLeftView.hide();
}, 300);
},false);
});
实现效果如下图:
(更多精彩内容请访问DCloud官网(http://www.dcloud.io/))
收起阅读 »