HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

mui图片预览(perviewimage)的优化

图片预览

mui图片预览(perviewimage)的优化

更好的显示效果看这http://www.cnblogs.com/phillyx/p/5164231.html
主要对mui图片全屏预览插件做了以下三点补充
1.添加了预览图片文字说明,使用的时候需要添加以下cssDOM属性

            .mui-slider-img-content {  
                position: absolute;  
                bottom: 10px;  
                left: 10px;  
                right: 10px;  
                color: white;  
                text-align: center;  
                line-height: 21px  
            }
<img src="../images/yuantiao.jpg" data-preview-src="" data-preview-group="2" data-content="这里是文字说明"/>

2.如果图片过宽或过长,预加载图片(上一张或下一张)时,会和当前显示的图片重叠
原来的效果是这样

主要对缩放进行了更改

    proto._initImgData = function(itemData, imgEl) {  
        if (!itemData.sWidth) {  
            var img = itemData.el;  
            itemData.sWidth = img.offsetWidth;  
            itemData.sHeight = img.offsetHeight;  
            var offset = $.offset(img);  
            itemData.sTop = offset.top;  
            itemData.sLeft = offset.left;  
            //缩放判断,解决预加载图片时,图片过大,和当前显示图片重叠的问题  
            //未更改之前缩放比例能达到2.5倍以上  
            var scale = Math.max(itemData.sWidth / window.innerWidth, itemData.sHeight / window.innerHeight);  
            itemData.sScale = scale > 1 ? 0.977 : scale;  
        }  
        imgEl.style.webkitTransform = 'translate3d(0,0,0) scale(' + itemData.sScale + ')';  
    };

3.解决了预加载页面返回(mui.back)重新加载数据并打开时,预览无用的问题
主要应用场景是这样的:

  • view是预加载的,返回时view隐藏,DOM重置,
  • 如果不清除当前预览对象previmage的话,加载数据后打开当前页面,重新调用mui.previewImage()无效,依然是第一次的预览的DOM结果
  • 因为插件源码决定了该对象是不变的
    var previewImageApi = null;  
    $.previewImage = function(options) {  
        if (!previewImageApi) {  
            previewImageApi = new PreviewImage(options);  
        }  
        return previewImageApi;  
    };
  • 有朋友会问,为毛要预加载,为什么不通过loadurl或其他方式刷新页面(或DOM)?
  • 就为了优化性能,秒开页面,整个详情页的代码前前后后改了一个多星期
  • 我不可能因为插件的不完整而放弃优化的成果。
  • 所以就有了以下的代码
    //释放当前对象及清除DOM  
    proto.dispose = function() {  
        var prevdom = document.getElementById("__MUI_PREVIEWIMAGE");  
        prevdom && prevdom.parentNode.removeChild(prevdom);  
        previewImageApi = null;  
    };

具体代码在这https://github.com/phillyx/mui/blob/master/examples/hello-mui/examples/imageviewer.html

继续阅读 »

mui图片预览(perviewimage)的优化

更好的显示效果看这http://www.cnblogs.com/phillyx/p/5164231.html
主要对mui图片全屏预览插件做了以下三点补充
1.添加了预览图片文字说明,使用的时候需要添加以下cssDOM属性

            .mui-slider-img-content {  
                position: absolute;  
                bottom: 10px;  
                left: 10px;  
                right: 10px;  
                color: white;  
                text-align: center;  
                line-height: 21px  
            }
<img src="../images/yuantiao.jpg" data-preview-src="" data-preview-group="2" data-content="这里是文字说明"/>

2.如果图片过宽或过长,预加载图片(上一张或下一张)时,会和当前显示的图片重叠
原来的效果是这样

主要对缩放进行了更改

    proto._initImgData = function(itemData, imgEl) {  
        if (!itemData.sWidth) {  
            var img = itemData.el;  
            itemData.sWidth = img.offsetWidth;  
            itemData.sHeight = img.offsetHeight;  
            var offset = $.offset(img);  
            itemData.sTop = offset.top;  
            itemData.sLeft = offset.left;  
            //缩放判断,解决预加载图片时,图片过大,和当前显示图片重叠的问题  
            //未更改之前缩放比例能达到2.5倍以上  
            var scale = Math.max(itemData.sWidth / window.innerWidth, itemData.sHeight / window.innerHeight);  
            itemData.sScale = scale > 1 ? 0.977 : scale;  
        }  
        imgEl.style.webkitTransform = 'translate3d(0,0,0) scale(' + itemData.sScale + ')';  
    };

3.解决了预加载页面返回(mui.back)重新加载数据并打开时,预览无用的问题
主要应用场景是这样的:

  • view是预加载的,返回时view隐藏,DOM重置,
  • 如果不清除当前预览对象previmage的话,加载数据后打开当前页面,重新调用mui.previewImage()无效,依然是第一次的预览的DOM结果
  • 因为插件源码决定了该对象是不变的
    var previewImageApi = null;  
    $.previewImage = function(options) {  
        if (!previewImageApi) {  
            previewImageApi = new PreviewImage(options);  
        }  
        return previewImageApi;  
    };
  • 有朋友会问,为毛要预加载,为什么不通过loadurl或其他方式刷新页面(或DOM)?
  • 就为了优化性能,秒开页面,整个详情页的代码前前后后改了一个多星期
  • 我不可能因为插件的不完整而放弃优化的成果。
  • 所以就有了以下的代码
    //释放当前对象及清除DOM  
    proto.dispose = function() {  
        var prevdom = document.getElementById("__MUI_PREVIEWIMAGE");  
        prevdom && prevdom.parentNode.removeChild(prevdom);  
        previewImageApi = null;  
    };

具体代码在这https://github.com/phillyx/mui/blob/master/examples/hello-mui/examples/imageviewer.html

收起阅读 »

关于H5电子签名的实现。

最近一个项目需要客户在提交单据的时候,附带签名。度娘了一下。果然还是有这个JQuery插件的。学名:jSignature
好了,废话不多说。先来个截图(见附件)。这玩意功能还是比较强大的。支持各种设置和各种姿势的导出。可惜是在JQuery里的,得先引用JQuery.

                <script type="text/javascript" src="js/jquery.js"></script>  
        <script type="text/javascript" src="js/jSignature.min.js"></script>  
        <!--[if lt IE 9]>  
        <script type="text/javascript" src="js/flashcanvas.js"></script>  
        <![endif]-->

下面就简单了,给一个dom.比如这样的:

<div id="signature" style="height: 100%;"></div>

最后呢,就是初始化一下。可以这样的:

$(document).ready(function() {  
                $("#signature").jSignature()  
            });

要是想导出呢,这里是Base64,就要这样的:

var datapair = $("#signature").jSignature("getData", "image");  
                var array = datapair.splice(",");  
                mui.toast(array[1]);

好了,其他也就没什么 了。更多了解就去看 api 吧。
最后在附上js包,希望对大家有帮助。

继续阅读 »

最近一个项目需要客户在提交单据的时候,附带签名。度娘了一下。果然还是有这个JQuery插件的。学名:jSignature
好了,废话不多说。先来个截图(见附件)。这玩意功能还是比较强大的。支持各种设置和各种姿势的导出。可惜是在JQuery里的,得先引用JQuery.

                <script type="text/javascript" src="js/jquery.js"></script>  
        <script type="text/javascript" src="js/jSignature.min.js"></script>  
        <!--[if lt IE 9]>  
        <script type="text/javascript" src="js/flashcanvas.js"></script>  
        <![endif]-->

下面就简单了,给一个dom.比如这样的:

<div id="signature" style="height: 100%;"></div>

最后呢,就是初始化一下。可以这样的:

$(document).ready(function() {  
                $("#signature").jSignature()  
            });

要是想导出呢,这里是Base64,就要这样的:

var datapair = $("#signature").jSignature("getData", "image");  
                var array = datapair.splice(",");  
                mui.toast(array[1]);

好了,其他也就没什么 了。更多了解就去看 api 吧。
最后在附上js包,希望对大家有帮助。

收起阅读 »

修复mui中多选项卡切换时,隐藏选项卡初始化属性不正确的问题.

同页面中多选项卡切换显示时,由于隐藏的选项卡无法获得offsetWidth属性,导致初始隐藏的选项卡后期显示时,选项卡标签条无法根据正确的当前项滚动.

此方法属于补救措施,不修改mui.js源文件.具体事件绑定因项目架构而异,以下只作比方.
假设A, B, C, D控制4个选项卡的显/隐.每个选项卡包含N个子项.
4个选项卡分别为A_s, B_s, C_s, D_s

document.getElementById(A).addEventListener('tap', function (){  
    var slider_id = document.querySelector(A_s).getAttribute('data-slider');  
    var slider_data = mui.data[slider_id];  
    var progressBarWidth = slider_data.progressBarWidth;  

    if (!progressBarWidth) {  
        slider_data.progressBarWidth = document.querySelector(A_s).querySelector('.mui-slider-progress-bar').offsetWidth;  
    }  
})

修复前:

修复后:

继续阅读 »

同页面中多选项卡切换显示时,由于隐藏的选项卡无法获得offsetWidth属性,导致初始隐藏的选项卡后期显示时,选项卡标签条无法根据正确的当前项滚动.

此方法属于补救措施,不修改mui.js源文件.具体事件绑定因项目架构而异,以下只作比方.
假设A, B, C, D控制4个选项卡的显/隐.每个选项卡包含N个子项.
4个选项卡分别为A_s, B_s, C_s, D_s

document.getElementById(A).addEventListener('tap', function (){  
    var slider_id = document.querySelector(A_s).getAttribute('data-slider');  
    var slider_data = mui.data[slider_id];  
    var progressBarWidth = slider_data.progressBarWidth;  

    if (!progressBarWidth) {  
        slider_data.progressBarWidth = document.querySelector(A_s).querySelector('.mui-slider-progress-bar').offsetWidth;  
    }  
})

修复前:

修复后:

收起阅读 »

配合下拉刷新、上拉加载的返回顶部demo(适用任何页面)

看到很多人提到了这个问题,正好自己也需要返回顶部的操作,总结了下各处的问题与回答,把实现的代码放出来,供参考。

下拉刷新、上拉加载的容器和返回顶部按钮,按钮默认不显示:

<div id="pullrefresh" class="mui-scroll-wrapper">  
    <div class="mui-scroll">  
        <ul id="list" class="mui-table-view"></ul>  
    </div>  
</div>  

<a id="scrollToTop" class="backTop hide">  
    <span class="mui-icon mui-icon-arrowup"></span>  
</a>

按钮对应的css:

.hide {  
    display: none;  
}  
.backTop {  
    background: #DDDDDD;  
    border-radius: 50%;  
    position: fixed;  
    right: 10px;  
    bottom: 15px;  
    width: 38px;  
    height: 38px;  
    z-index: 9999;  
    text-align: center;  
    font-size: 18px;  
    color: #666666;  
    padding-top: 8px;  
    opacity: 0.8;  
}

js中添加事件监听:

var scrollToTopBox = document.getElementById('scrollToTop');  
//返回按钮tap  
scrollToTopBox.addEventListener('tap', function(e) {  
    e.stopPropagation();  
    mui('#pullrefresh').pullRefresh().scrollTo(0, 0, 100);//滚动到顶部  
});  
//Android上监听原生滚动,iOS上监听div滚动,上拉超过一屏后显示按钮,否则隐藏,可自行在条件判断中修改  
if (mui.os.android) {  
    window.addEventListener('scroll', function(e) {  
        if (window.pageYOffset >= window.innerHeight && scrollToTopBox.classList.contains('hide'))  
            scrollToTopBox.classList.remove('hide');  
        else if (window.pageYOffset < window.innerHeight && !scrollToTopBox.classList.contains('hide'))  
            scrollToTopBox.classList.add('hide');  
    });  
} else {  
    document.getElementById('pullrefresh').addEventListener('scroll', function() {  
            if (mui('#pullrefresh').pullRefresh().y <= window.innerHeight * (-1) && scrollToTopBox.classList.contains('hide'))  
                scrollToTopBox.classList.remove('hide');  
            else if (mui('#pullrefresh').pullRefresh().y > window.innerHeight * (-1) && !scrollToTopBox.classList.contains('hide'))  
                scrollToTopBox.classList.add('hide');  
    });  
}

该方法也可用于任何需要返回顶部的页面,做一下适当的修改,此时不区分Android和iOS,代码如下:

var scrollToTopBox = document.getElementById('scrollToTop');  
        scrollToTopBox.addEventListener('tap', function(e) {  
            e.stopPropagation();  
            mui('body').pullRefresh().scrollTo(0, 0, 100);  
        });  
        window.addEventListener('scroll', function() {  
            if (window.pageYOffset >= window.innerHeight && scrollToTopBox.classList.contains('hide'))  
                scrollToTopBox.classList.remove('hide');  
            else if (window.pageYOffset < window.innerHeight && !scrollToTopBox.classList.contains('hide'))  
                scrollToTopBox.classList.add('hide');  
        });
继续阅读 »

看到很多人提到了这个问题,正好自己也需要返回顶部的操作,总结了下各处的问题与回答,把实现的代码放出来,供参考。

下拉刷新、上拉加载的容器和返回顶部按钮,按钮默认不显示:

<div id="pullrefresh" class="mui-scroll-wrapper">  
    <div class="mui-scroll">  
        <ul id="list" class="mui-table-view"></ul>  
    </div>  
</div>  

<a id="scrollToTop" class="backTop hide">  
    <span class="mui-icon mui-icon-arrowup"></span>  
</a>

按钮对应的css:

.hide {  
    display: none;  
}  
.backTop {  
    background: #DDDDDD;  
    border-radius: 50%;  
    position: fixed;  
    right: 10px;  
    bottom: 15px;  
    width: 38px;  
    height: 38px;  
    z-index: 9999;  
    text-align: center;  
    font-size: 18px;  
    color: #666666;  
    padding-top: 8px;  
    opacity: 0.8;  
}

js中添加事件监听:

var scrollToTopBox = document.getElementById('scrollToTop');  
//返回按钮tap  
scrollToTopBox.addEventListener('tap', function(e) {  
    e.stopPropagation();  
    mui('#pullrefresh').pullRefresh().scrollTo(0, 0, 100);//滚动到顶部  
});  
//Android上监听原生滚动,iOS上监听div滚动,上拉超过一屏后显示按钮,否则隐藏,可自行在条件判断中修改  
if (mui.os.android) {  
    window.addEventListener('scroll', function(e) {  
        if (window.pageYOffset >= window.innerHeight && scrollToTopBox.classList.contains('hide'))  
            scrollToTopBox.classList.remove('hide');  
        else if (window.pageYOffset < window.innerHeight && !scrollToTopBox.classList.contains('hide'))  
            scrollToTopBox.classList.add('hide');  
    });  
} else {  
    document.getElementById('pullrefresh').addEventListener('scroll', function() {  
            if (mui('#pullrefresh').pullRefresh().y <= window.innerHeight * (-1) && scrollToTopBox.classList.contains('hide'))  
                scrollToTopBox.classList.remove('hide');  
            else if (mui('#pullrefresh').pullRefresh().y > window.innerHeight * (-1) && !scrollToTopBox.classList.contains('hide'))  
                scrollToTopBox.classList.add('hide');  
    });  
}

该方法也可用于任何需要返回顶部的页面,做一下适当的修改,此时不区分Android和iOS,代码如下:

var scrollToTopBox = document.getElementById('scrollToTop');  
        scrollToTopBox.addEventListener('tap', function(e) {  
            e.stopPropagation();  
            mui('body').pullRefresh().scrollTo(0, 0, 100);  
        });  
        window.addEventListener('scroll', function() {  
            if (window.pageYOffset >= window.innerHeight && scrollToTopBox.classList.contains('hide'))  
                scrollToTopBox.classList.remove('hide');  
            else if (window.pageYOffset < window.innerHeight && !scrollToTopBox.classList.contains('hide'))  
                scrollToTopBox.classList.add('hide');  
        });
收起阅读 »

Android Studio 离线打包

离线打包

android studio 版本1.5
android studio新建工程
libs 添加需要的jar包
src/main/assets/apps/对应的id/www/项目
src/main/assets/dataAndroid-SDK/SDK/assets/data 拷贝来的
src/main/java/io/dcloud/RInformation.javaAndroid-SDK\SDK\src 拷贝来的
src/main/resAndroid-SDK\SDK\res 拷贝来的
ps: 1.5下面只有一个drawable,剩下的是mipmap-hdpi、mipmap-mdpi等等,所以是拷贝的文件内容,而不是整个文件夹

androidmanifest.xml中application

<application  
        android:allowBackup="true"  
        android:icon="@mipmap/icon"  
        android:label="@string/app_name"  
        android:supportsRtl="true"  
        android:theme="@style/AppTheme">  
        <activity  
            android:name="io.dcloud.PandoraEntry"  
            android:configChanges="orientation|keyboardHidden"  
            android:label="@string/app_name"  
            android:launchMode="singleTask"  
            android:screenOrientation="user"  
            android:windowSoftInputMode="adjustResize" >  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  

                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
        <activity  
            android:name="io.dcloud.PandoraEntryActivity"  
            android:configChanges="orientation|keyboardHidden|screenSize"  
            android:hardwareAccelerated="true"  
            android:label="5+Debug"  
            android:launchMode="singleTask"  
            android:screenOrientation="user"  
            android:theme="@style/DCloudTheme"  
            android:windowSoftInputMode="adjustResize" >  
        </activity>  

        <service  
            android:name="io.dcloud.common.adapter.io.MiniServerService"  
            android:exported="true" />  

    </application>

activity,service 中 android:name 依赖的是pdr.jar

不知道这个jar包是做什么的,少引用时出错了。猜测和图片有关
universal-image-loader-1.9.0.jar

其他的可以参考如下链接:
SDK下载地址:http://ask.dcloud.net.cn/article/103
Android平台离线打包插件配置:http://ask.dcloud.net.cn/article/216
还有这个文章: http://ask.dcloud.net.cn/question/15183

继续阅读 »

android studio 版本1.5
android studio新建工程
libs 添加需要的jar包
src/main/assets/apps/对应的id/www/项目
src/main/assets/dataAndroid-SDK/SDK/assets/data 拷贝来的
src/main/java/io/dcloud/RInformation.javaAndroid-SDK\SDK\src 拷贝来的
src/main/resAndroid-SDK\SDK\res 拷贝来的
ps: 1.5下面只有一个drawable,剩下的是mipmap-hdpi、mipmap-mdpi等等,所以是拷贝的文件内容,而不是整个文件夹

androidmanifest.xml中application

<application  
        android:allowBackup="true"  
        android:icon="@mipmap/icon"  
        android:label="@string/app_name"  
        android:supportsRtl="true"  
        android:theme="@style/AppTheme">  
        <activity  
            android:name="io.dcloud.PandoraEntry"  
            android:configChanges="orientation|keyboardHidden"  
            android:label="@string/app_name"  
            android:launchMode="singleTask"  
            android:screenOrientation="user"  
            android:windowSoftInputMode="adjustResize" >  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  

                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
        <activity  
            android:name="io.dcloud.PandoraEntryActivity"  
            android:configChanges="orientation|keyboardHidden|screenSize"  
            android:hardwareAccelerated="true"  
            android:label="5+Debug"  
            android:launchMode="singleTask"  
            android:screenOrientation="user"  
            android:theme="@style/DCloudTheme"  
            android:windowSoftInputMode="adjustResize" >  
        </activity>  

        <service  
            android:name="io.dcloud.common.adapter.io.MiniServerService"  
            android:exported="true" />  

    </application>

activity,service 中 android:name 依赖的是pdr.jar

不知道这个jar包是做什么的,少引用时出错了。猜测和图片有关
universal-image-loader-1.9.0.jar

其他的可以参考如下链接:
SDK下载地址:http://ask.dcloud.net.cn/article/103
Android平台离线打包插件配置:http://ask.dcloud.net.cn/article/216
还有这个文章: http://ask.dcloud.net.cn/question/15183

收起阅读 »

将tap模拟成原生click体验

tap

将tap模拟成原生click体验

mui提供了tap事件替换了html5的click事件,解决了300ms延时的问题。不过相比原生app的click体验还是有些许差距的。  
仅用微信为例,只有当手指离开屏幕时才触发click事件,如果对象绑定了长按事件,则触发长按操作,离开时不再触发单击事件。  
这些逻辑无论是android, ios或者仅有1%的windows mobile都已经封装好了,根本不用关心。  

那么,我们应该怎么来实现呢?
下面是详细的填坑历程。。。。。。

坑1.通过原生的touch来实现

//直接对dom添加touchend,这种方法只能针对位置不变且并没有添加longtap事件的DOM有效  
//如果在listview中,你上下滑动,那就歇菜了。  
//那么自然而然就想到了touch.target的位移,并做出判断是下滑还是单击。  
//自己去写复杂度、代码量估计会很可观。  
//因此就想到了了在原有的框架代码上去实现。  
//下面就到了坑2  
document.getElementById("").('touchend', function() {  
    //  
});

坑2.更改mui.gestures.tap.js

坑2.1 自定义事件侦听机制

mui没有提供类似于jq.data('events')获取事件列表的机制,另外官方也推荐使用addEventListener去绑定事件。
我要去获取当前DOM的事件列表应该怎么做呢?

你问我问毛要去获取DOM的事件列表,,,
呵呵,我总要知道DOM有木有绑定longtap事件好做规避吧

csdn的这个帖子看似有用
http://bbs.csdn.net/topics/390250552

function addEvent(dom,type,fn) {  
    if(document.addEventListener) {  
        dom.addEventListener(type, fn, false);  
    } else if(document.attachEvent) {  
        dom.attachEvent('on' + type, fn);  
    } else {  
        dom['on' + type] = fn;  
    };  
    dom[""+type]=!0;  
}

实际上并没有什么卵用
思想是好的.....
我总不能每次addEventListener都去调一下这个方法吧!

坑2.2 使用getEventListeners

找啊找,终于找到了getEventListeners()这个全局方法,在chrome和safari控制台中测试都木有问题。
喜出望外......
这下终于能解决问题了
于是有了以下的方法

    var getEvents = function(obj) {  
        console.log(getEventListeners(obj));  
        return typeof(getEventListeners) == "function" && getEventListeners(obj);  
    }  
    var hasEventype = function(obj, e) {  
        var es = getEvents(obj);  
        console.log(es[e]);  
        return es && !!es[e];  
    }

调用下试试

if (!hasEventype(target, 'longtap')) {}

报错
getEventListeners is undefined

R U kidding?!!!!

你丫在逗我.............

我瞬间感受到了深深地恶意

原来这个方法只能在控制台中用,
呵呵,人艰不拆......

坑2.3 使用全局变量规避

给mui添加一个全局变量isLongTapAtived,看变量名就知道什么意思吧
mui.gestures.longtap.js中初始化,在handle中激活

(function($, name) {  
    $.isLongTapAtived = false;//初始化  
    var timer;  
    var handle = function(event, touch) {  
        switch (event.type) {  
            case $.EVENT_START:  
                clearTimeout(timer);  
                timer = setTimeout(function() {  
                    $.trigger(session.target, name, touch);  
                    //激活了  
                    $.isLongTapAtived = true;  
                }, options.holdTimeout);  
                break;  
        }  
    };  

    });  
})(mui, 'longtap');

mui.gestures.tap.js中判断有无激活

    var handle = function(event, touch) {  
        var session = $.gestures.session;  
        var options = this.options;  
        switch (event.type) {  
            case $.EVENT_END:  
                //......  
                if (touch.distance < options.tapMaxDistance) {  
                    if (touch.deltaTime < options.tapMaxTime) {  
                        //.....  
                    } else {  
                        //如果当前对象添加了长按侦听,略过,否则仍然视为tap事件  
                        //if (!hasEventype(target, 'longtap')) {  
                        if (!$.isLongTapAtived) {  
                            //如果没有longtap事件,离开屏幕是触发tap事件  
                            $.trigger(target, name, touch);  
                        }  
                        //重置  
                        $.isLongTapAtived = false;  
                    }  
                }  
                break;  
        }  
    };  

想法是美好的,现实是他么残酷的。无论有无longtap事件,都要走一遍longtaphandle代码
于是 $.isLongTapAtived === true;
于是 永远trigger tap 事件

呵呵,想死的心都有了


路子看来走对了,但是应该怎么做???

终极解决方案

mui.isLongTapAtived依然添加,只是在每一次DOM添加的longtap事件内激活

document.querySelector("#").addEventListener('longtap',function(){  
    mui.isLongTapAtived=true;  
    console.log('你触发了longtap事件');  
});

这样对开发者是不友好的,不过暂时没办法,只能如此取舍了

代码已提交至https://github.com/phillyx/mui/
并推送给官方

博客已同步至http://www.cnblogs.com/phillyx/p/5157850.html

觉得不错就打赏一下吧

继续阅读 »

将tap模拟成原生click体验

mui提供了tap事件替换了html5的click事件,解决了300ms延时的问题。不过相比原生app的click体验还是有些许差距的。  
仅用微信为例,只有当手指离开屏幕时才触发click事件,如果对象绑定了长按事件,则触发长按操作,离开时不再触发单击事件。  
这些逻辑无论是android, ios或者仅有1%的windows mobile都已经封装好了,根本不用关心。  

那么,我们应该怎么来实现呢?
下面是详细的填坑历程。。。。。。

坑1.通过原生的touch来实现

//直接对dom添加touchend,这种方法只能针对位置不变且并没有添加longtap事件的DOM有效  
//如果在listview中,你上下滑动,那就歇菜了。  
//那么自然而然就想到了touch.target的位移,并做出判断是下滑还是单击。  
//自己去写复杂度、代码量估计会很可观。  
//因此就想到了了在原有的框架代码上去实现。  
//下面就到了坑2  
document.getElementById("").('touchend', function() {  
    //  
});

坑2.更改mui.gestures.tap.js

坑2.1 自定义事件侦听机制

mui没有提供类似于jq.data('events')获取事件列表的机制,另外官方也推荐使用addEventListener去绑定事件。
我要去获取当前DOM的事件列表应该怎么做呢?

你问我问毛要去获取DOM的事件列表,,,
呵呵,我总要知道DOM有木有绑定longtap事件好做规避吧

csdn的这个帖子看似有用
http://bbs.csdn.net/topics/390250552

function addEvent(dom,type,fn) {  
    if(document.addEventListener) {  
        dom.addEventListener(type, fn, false);  
    } else if(document.attachEvent) {  
        dom.attachEvent('on' + type, fn);  
    } else {  
        dom['on' + type] = fn;  
    };  
    dom[""+type]=!0;  
}

实际上并没有什么卵用
思想是好的.....
我总不能每次addEventListener都去调一下这个方法吧!

坑2.2 使用getEventListeners

找啊找,终于找到了getEventListeners()这个全局方法,在chrome和safari控制台中测试都木有问题。
喜出望外......
这下终于能解决问题了
于是有了以下的方法

    var getEvents = function(obj) {  
        console.log(getEventListeners(obj));  
        return typeof(getEventListeners) == "function" && getEventListeners(obj);  
    }  
    var hasEventype = function(obj, e) {  
        var es = getEvents(obj);  
        console.log(es[e]);  
        return es && !!es[e];  
    }

调用下试试

if (!hasEventype(target, 'longtap')) {}

报错
getEventListeners is undefined

R U kidding?!!!!

你丫在逗我.............

我瞬间感受到了深深地恶意

原来这个方法只能在控制台中用,
呵呵,人艰不拆......

坑2.3 使用全局变量规避

给mui添加一个全局变量isLongTapAtived,看变量名就知道什么意思吧
mui.gestures.longtap.js中初始化,在handle中激活

(function($, name) {  
    $.isLongTapAtived = false;//初始化  
    var timer;  
    var handle = function(event, touch) {  
        switch (event.type) {  
            case $.EVENT_START:  
                clearTimeout(timer);  
                timer = setTimeout(function() {  
                    $.trigger(session.target, name, touch);  
                    //激活了  
                    $.isLongTapAtived = true;  
                }, options.holdTimeout);  
                break;  
        }  
    };  

    });  
})(mui, 'longtap');

mui.gestures.tap.js中判断有无激活

    var handle = function(event, touch) {  
        var session = $.gestures.session;  
        var options = this.options;  
        switch (event.type) {  
            case $.EVENT_END:  
                //......  
                if (touch.distance < options.tapMaxDistance) {  
                    if (touch.deltaTime < options.tapMaxTime) {  
                        //.....  
                    } else {  
                        //如果当前对象添加了长按侦听,略过,否则仍然视为tap事件  
                        //if (!hasEventype(target, 'longtap')) {  
                        if (!$.isLongTapAtived) {  
                            //如果没有longtap事件,离开屏幕是触发tap事件  
                            $.trigger(target, name, touch);  
                        }  
                        //重置  
                        $.isLongTapAtived = false;  
                    }  
                }  
                break;  
        }  
    };  

想法是美好的,现实是他么残酷的。无论有无longtap事件,都要走一遍longtaphandle代码
于是 $.isLongTapAtived === true;
于是 永远trigger tap 事件

呵呵,想死的心都有了


路子看来走对了,但是应该怎么做???

终极解决方案

mui.isLongTapAtived依然添加,只是在每一次DOM添加的longtap事件内激活

document.querySelector("#").addEventListener('longtap',function(){  
    mui.isLongTapAtived=true;  
    console.log('你触发了longtap事件');  
});

这样对开发者是不友好的,不过暂时没办法,只能如此取舍了

代码已提交至https://github.com/phillyx/mui/
并推送给官方

博客已同步至http://www.cnblogs.com/phillyx/p/5157850.html

觉得不错就打赏一下吧

收起阅读 »

【交流分享】解决IOS列表滑动不流畅的问题

技术分享 卡顿

很简单的列表:

<body>  
        <div class="list">  
            <h1>图片</h1>  
            <img sr c="xxx.jpg" />  

            ...这里是20个<h1><img>...  

            <h1>图片</h1>  
            <img sr c="xxx.jpg" />  
        </div>  
    </body>

上述很简单的图文列表运行在IOS上列表滑动起来总是不流畅,但是在Android运行就很快;就算把img删掉,只剩h1文字列表,在IOS上滑起来都有点卡顿,手指只要离开屏幕,列表就停了,没有继续惯性滚动一段距离;

分享一下我的解决办法:

方法一: 使用原生div的滚动
如果像上面代码一样,不使用mui框架,则加入以下css:

body,  
            html {  
                height: 100%;  
                -webkit-overflow-scrolling: touch;//允许独立的滚动区域和触摸回弹  
            }  
            .list{  
                height: 100%;  
                overflow-y: scroll;//使用原生div滚动  
            }

如果使用mui框架,则
引入mui.css, 把上面<div class="list">变成 <div class="mui-content">; 加入以下css:

body,  
            html {  
                height: 100%;  
            }  
            .mui-content{  
                height: 100%;  
                overflow-y: scroll;  
            }

方法二: 使用mui的区域滚动
参考:http://dev.dcloud.net.cn/mui/ui/#scroll
但是这种方式,体验不如上面css的; 按照我们公司IOS同事的话来讲:你会感觉滑动飞得太假;当然也能解决问题;

最后附上源码案例, 很简单, 导入到HBuilder就可以在IOS上运行了

继续阅读 »

很简单的列表:

<body>  
        <div class="list">  
            <h1>图片</h1>  
            <img sr c="xxx.jpg" />  

            ...这里是20个<h1><img>...  

            <h1>图片</h1>  
            <img sr c="xxx.jpg" />  
        </div>  
    </body>

上述很简单的图文列表运行在IOS上列表滑动起来总是不流畅,但是在Android运行就很快;就算把img删掉,只剩h1文字列表,在IOS上滑起来都有点卡顿,手指只要离开屏幕,列表就停了,没有继续惯性滚动一段距离;

分享一下我的解决办法:

方法一: 使用原生div的滚动
如果像上面代码一样,不使用mui框架,则加入以下css:

body,  
            html {  
                height: 100%;  
                -webkit-overflow-scrolling: touch;//允许独立的滚动区域和触摸回弹  
            }  
            .list{  
                height: 100%;  
                overflow-y: scroll;//使用原生div滚动  
            }

如果使用mui框架,则
引入mui.css, 把上面<div class="list">变成 <div class="mui-content">; 加入以下css:

body,  
            html {  
                height: 100%;  
            }  
            .mui-content{  
                height: 100%;  
                overflow-y: scroll;  
            }

方法二: 使用mui的区域滚动
参考:http://dev.dcloud.net.cn/mui/ui/#scroll
但是这种方式,体验不如上面css的; 按照我们公司IOS同事的话来讲:你会感觉滑动飞得太假;当然也能解决问题;

最后附上源码案例, 很简单, 导入到HBuilder就可以在IOS上运行了

收起阅读 »

DCloud学习资料【自用】

1、首先记住以下3个常用网站:
DCloud官网:http://www.dcloud.io/
MUI官网:http://dev.dcloud.net.cn/mui/
HTML5+联盟:http://www.html5plus.org/

2、学习顺序
(1)MUI、5+、Native.js等相关知识参照DCloud官方文档
(2)5+API,即HTML5+联盟中的HTML5+规范
(3)MUI

3、资源汇总
MUI-FAQ:http://ask.dcloud.net.cn/docs/#http://ask.dcloud.net.cn/article/122
APP优化技巧:http://ask.dcloud.net.cn/docs/#http://ask.dcloud.net.cn/article/25
视频教程:http://edu.yuantuan.com/classroom/5/courses

4、官方相关视频
如何让Android手机的HTML5 App性能体验接近原生 王安(DCloud CEO
http://v.youku.com/v_show/id_XNzYyNzI3NDQw.html

mui—让HTML5达到原生体验的高性能框架 崔红保(Dcloud 前端工程
http://v.youku.com/v_show/id_XNzYyOTEyMjcy.html?from=s1.8-1-1.2

Native.js,让js像原生一样强大+++江树源(数字天堂CTO)
http://v.youku.com/v_show/id_XNzYzNTcwNDI4.html

(最新)DCloud流应用大会:http://e.vhall.com/944470274

继续阅读 »

1、首先记住以下3个常用网站:
DCloud官网:http://www.dcloud.io/
MUI官网:http://dev.dcloud.net.cn/mui/
HTML5+联盟:http://www.html5plus.org/

2、学习顺序
(1)MUI、5+、Native.js等相关知识参照DCloud官方文档
(2)5+API,即HTML5+联盟中的HTML5+规范
(3)MUI

3、资源汇总
MUI-FAQ:http://ask.dcloud.net.cn/docs/#http://ask.dcloud.net.cn/article/122
APP优化技巧:http://ask.dcloud.net.cn/docs/#http://ask.dcloud.net.cn/article/25
视频教程:http://edu.yuantuan.com/classroom/5/courses

4、官方相关视频
如何让Android手机的HTML5 App性能体验接近原生 王安(DCloud CEO
http://v.youku.com/v_show/id_XNzYyNzI3NDQw.html

mui—让HTML5达到原生体验的高性能框架 崔红保(Dcloud 前端工程
http://v.youku.com/v_show/id_XNzYyOTEyMjcy.html?from=s1.8-1-1.2

Native.js,让js像原生一样强大+++江树源(数字天堂CTO)
http://v.youku.com/v_show/id_XNzYzNTcwNDI4.html

(最新)DCloud流应用大会:http://e.vhall.com/944470274

收起阅读 »

【交流分享】Android独立应用方式集成HTML5+SDK,Widget方式离线打包,空项目讲解

源码分享 技术分享 SDK widget 集成 Android

最近忙着微信和m站,还有流应用开发,好久没有写文章了.
公司打算把原生app全部改写成html5,方便升级版本,毕竟IOS更新审核太久,耽误运营推广;
我的项目百度地图,友盟推送,反馈,统计,千牛商家聊天都是得用原生的,所以以后用MUI写好html后,得集成到原生项目中去.

首先吐槽下官方的集成方式所提到的概念:
Widget方式: 按照字面的意思就是,html相当于小部件一样和原生代码放一块,在需要的时候调用;
独立应用方式: 这个就是Widget方式,概念真多
Webview方式: 只能打开一个界面,不能打开新界面,这个没搞懂使用场景~~(>_<)~~我暂且把这个概念忘了,别搞混

当你打开官方http://ask.dcloud.net.cn/docs/#http://ask.dcloud.net.cn/article/38 又多了个概念: 离线打包
当你运行官方集成案例的时候,又多了个Runtime集成方式; 小白迟早会疯掉的

总之,按照我的理解:
1.如果你的项目原生代码和html混合着用,那么选择Widget方式集成,也就是独立应用方式;
2.如果你的项目是HBuilder写的纯html,没有原生代码,那么用Runtime集成方式,比较简单;

离线打包的概念是相对于HBuilder在线云打包而言的; 我们选上面各种集成方式用eclipse,Android Studio 或者XCode把html编译成安装包就属于离线打包了;这样避免云打包排队或者服务器挂掉的时候,自己还能编译安装包,照常发布更新版本;

ok,理清了官方的概念,你也基本懂了我写的标题:
Android独立应用方式集成HTML5 SDK,Widget方式离线打包,空项目讲解

一.准备
1.打开HBuilder,新建-->移动APP-->勾选"Hello mui",项目名叫"HelloMui";(我以官方mui项目来举例了,到时自行改为自己的项目);
2.打开eclipse,打开你的Android项目;(我这里是新建了一个Android项目,名字叫Widget; 如果你还没配置Android开发环境,则点这里http://jingyan.baidu.com/article/bea41d437a41b6b4c51be6c1.html );

  1. 去官方下载最新的sdk: http://ask.dcloud.net.cn/article/103 解压,里面有个名字叫'SDK'的文件夹

二.拷贝
1.把下载的官方SDK文件夹里的res文件夹拷贝到Android项目的res,合并;注意不要替换你项目的资源,不然你配的图标和写的strings.xml就没了

说明: res里面有NativeUI用到的图片资源: 进度条,对话框,动画样式,照片选择,底部弹出框,logo,启动页等等;http://www.html5plus.org/doc/zh_cn/nativeui.html

2.把SDK\assets中的data文件夹到eclipse项目中的assets

3.在eclipse的assets目录中创建apps; 在apps中创建一个文件夹,名字和你HBuilder的项目名相同;我这里就叫HelloMui; 在HelloMui中创建www文件夹; 把HBuilder项目拷贝到www文件夹下;


注意: apps和www文件夹名字是固定的,结构也是固定的,不然读取不到html

4.修改manifest.json和control.xml中的id为你的项目名;我这里是HelloMui

5.拷贝SDK\libs里面的jar包到eclipse项目下的libs;如图:


说明:
pdr.jar, ui.jar, nineoldandroids-2.4.0.jar是Webview基础包,必须导入
因为HelloMui项目中获取设备信息网络状态,需引入device.jar;
设置了浏览器运行环境,需引入navigatorui.jar(设置了状态栏,创建快捷方式,log输出,设置cookie都需引入此包)
使用了plus.storage,需引入nopermission.jar

其实在具体的项目中,这些包远远不够的:
比如ajax联网,需引入xhr.jar
全量更新和差量更新,需引入downloader.jar,invocation.jar
原生对话框和底部弹出或者toast,需引入nativeui.jar
设置用户头像,用到拍照,打开相册,需引入camera.jar,gallery.jar
具体请参照: http://ask.dcloud.net.cn/docs/#http://ask.dcloud.net.cn/article/216

6.打开eclipse项目的AndroidManifest.xml,配置权限,具体请参照官方SDK里的Feature-Android.xls文件

<!-- 联网 -->  
    <uses-permission android:name="android.permission.INTERNET" />  
    <!-- 使用存储卡 -->  
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

7.把HBuilder-Integrate\src下的io文件夹,拷贝到eclipse项目的src

8.把Android-SDK\HBuilder-Integrate\src\com\HBuilder\integrate\SDK_WebApp.java 拷贝到eclipse项目的src包名下,并修改122行的appBasePath, 为assets的app路径

9.SDK_WebApp.java里面的FrameLayout是用来承载html的,可以放到任何你想放到的位置,比如点击一个按钮,弹窗或者打开新Activity展示; 我这里的话,直接用activity展示,并在AndroidManifest.xml设置启动就打开本界面


10.ok 完了 ,运行吧. 附上eclipse项目源码

继续阅读 »

最近忙着微信和m站,还有流应用开发,好久没有写文章了.
公司打算把原生app全部改写成html5,方便升级版本,毕竟IOS更新审核太久,耽误运营推广;
我的项目百度地图,友盟推送,反馈,统计,千牛商家聊天都是得用原生的,所以以后用MUI写好html后,得集成到原生项目中去.

首先吐槽下官方的集成方式所提到的概念:
Widget方式: 按照字面的意思就是,html相当于小部件一样和原生代码放一块,在需要的时候调用;
独立应用方式: 这个就是Widget方式,概念真多
Webview方式: 只能打开一个界面,不能打开新界面,这个没搞懂使用场景~~(>_<)~~我暂且把这个概念忘了,别搞混

当你打开官方http://ask.dcloud.net.cn/docs/#http://ask.dcloud.net.cn/article/38 又多了个概念: 离线打包
当你运行官方集成案例的时候,又多了个Runtime集成方式; 小白迟早会疯掉的

总之,按照我的理解:
1.如果你的项目原生代码和html混合着用,那么选择Widget方式集成,也就是独立应用方式;
2.如果你的项目是HBuilder写的纯html,没有原生代码,那么用Runtime集成方式,比较简单;

离线打包的概念是相对于HBuilder在线云打包而言的; 我们选上面各种集成方式用eclipse,Android Studio 或者XCode把html编译成安装包就属于离线打包了;这样避免云打包排队或者服务器挂掉的时候,自己还能编译安装包,照常发布更新版本;

ok,理清了官方的概念,你也基本懂了我写的标题:
Android独立应用方式集成HTML5 SDK,Widget方式离线打包,空项目讲解

一.准备
1.打开HBuilder,新建-->移动APP-->勾选"Hello mui",项目名叫"HelloMui";(我以官方mui项目来举例了,到时自行改为自己的项目);
2.打开eclipse,打开你的Android项目;(我这里是新建了一个Android项目,名字叫Widget; 如果你还没配置Android开发环境,则点这里http://jingyan.baidu.com/article/bea41d437a41b6b4c51be6c1.html );

  1. 去官方下载最新的sdk: http://ask.dcloud.net.cn/article/103 解压,里面有个名字叫'SDK'的文件夹

二.拷贝
1.把下载的官方SDK文件夹里的res文件夹拷贝到Android项目的res,合并;注意不要替换你项目的资源,不然你配的图标和写的strings.xml就没了

说明: res里面有NativeUI用到的图片资源: 进度条,对话框,动画样式,照片选择,底部弹出框,logo,启动页等等;http://www.html5plus.org/doc/zh_cn/nativeui.html

2.把SDK\assets中的data文件夹到eclipse项目中的assets

3.在eclipse的assets目录中创建apps; 在apps中创建一个文件夹,名字和你HBuilder的项目名相同;我这里就叫HelloMui; 在HelloMui中创建www文件夹; 把HBuilder项目拷贝到www文件夹下;


注意: apps和www文件夹名字是固定的,结构也是固定的,不然读取不到html

4.修改manifest.json和control.xml中的id为你的项目名;我这里是HelloMui

5.拷贝SDK\libs里面的jar包到eclipse项目下的libs;如图:


说明:
pdr.jar, ui.jar, nineoldandroids-2.4.0.jar是Webview基础包,必须导入
因为HelloMui项目中获取设备信息网络状态,需引入device.jar;
设置了浏览器运行环境,需引入navigatorui.jar(设置了状态栏,创建快捷方式,log输出,设置cookie都需引入此包)
使用了plus.storage,需引入nopermission.jar

其实在具体的项目中,这些包远远不够的:
比如ajax联网,需引入xhr.jar
全量更新和差量更新,需引入downloader.jar,invocation.jar
原生对话框和底部弹出或者toast,需引入nativeui.jar
设置用户头像,用到拍照,打开相册,需引入camera.jar,gallery.jar
具体请参照: http://ask.dcloud.net.cn/docs/#http://ask.dcloud.net.cn/article/216

6.打开eclipse项目的AndroidManifest.xml,配置权限,具体请参照官方SDK里的Feature-Android.xls文件

<!-- 联网 -->  
    <uses-permission android:name="android.permission.INTERNET" />  
    <!-- 使用存储卡 -->  
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

7.把HBuilder-Integrate\src下的io文件夹,拷贝到eclipse项目的src

8.把Android-SDK\HBuilder-Integrate\src\com\HBuilder\integrate\SDK_WebApp.java 拷贝到eclipse项目的src包名下,并修改122行的appBasePath, 为assets的app路径

9.SDK_WebApp.java里面的FrameLayout是用来承载html的,可以放到任何你想放到的位置,比如点击一个按钮,弹窗或者打开新Activity展示; 我这里的话,直接用activity展示,并在AndroidManifest.xml设置启动就打开本界面


10.ok 完了 ,运行吧. 附上eclipse项目源码

收起阅读 »

离线打包下打开浏览器调试模式

调试 离线打包

由于自己编写了一些插件,所以不得不采取离线打包的方式来发布应用,在这个过程中,被不能浏览器调试浪费了不少时间,最后狠下心反编译了官方云打包的apk,发现需要修改一个配置文件

配置文件的位置:assets\data\control.xml

作如下修改即可打开调试模式

<hbuilder version="1.9.9.21259" debug="true">  
    <apps>  
        <app  
            appid="HBuilder"  
            appver="1.5.3" />  
    </apps>  
</hbuilder>
继续阅读 »

由于自己编写了一些插件,所以不得不采取离线打包的方式来发布应用,在这个过程中,被不能浏览器调试浪费了不少时间,最后狠下心反编译了官方云打包的apk,发现需要修改一个配置文件

配置文件的位置:assets\data\control.xml

作如下修改即可打开调试模式

<hbuilder version="1.9.9.21259" debug="true">  
    <apps>  
        <app  
            appid="HBuilder"  
            appver="1.5.3" />  
    </apps>  
</hbuilder>
收起阅读 »