HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

解决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基本样式库

  1. 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基本样式库

  1. 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 一个星期的分享

nodejs socket Socket.io IM

新项目要聊天。居然要 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/))

收起阅读 »