HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

Hybrid APP开发工程师招聘(西安高新区)

AngularJS

Hybrid APP开发工程师招聘,工作地点西安
1、掌握JavaScript语言开发基础,熟悉Javascript面向对象编码者优先;
2、精通Html、Div+Css布局,掌握W3C标准及各种浏览器兼容性调试;
3、熟练Dreamweaver、Fireworks、Photoshop、Webstorm等常用网页、UI设计工具;
4、了解一种以上前端开发框架,如Jquery、Angularjs、ExtJS、LigerUI等;
5、熟悉XML/JSON前端开发技术,了解BootStrap;
熟悉Java开发者优先,具备MUI、AngularJS经验者优先,具备APP Hybrid设计经验者优先;

继续阅读 »

Hybrid APP开发工程师招聘,工作地点西安
1、掌握JavaScript语言开发基础,熟悉Javascript面向对象编码者优先;
2、精通Html、Div+Css布局,掌握W3C标准及各种浏览器兼容性调试;
3、熟练Dreamweaver、Fireworks、Photoshop、Webstorm等常用网页、UI设计工具;
4、了解一种以上前端开发框架,如Jquery、Angularjs、ExtJS、LigerUI等;
5、熟悉XML/JSON前端开发技术,了解BootStrap;
熟悉Java开发者优先,具备MUI、AngularJS经验者优先,具备APP Hybrid设计经验者优先;

收起阅读 »

使用Uploader上传文件,Java做后端的处理方法

由于刚刚接触HTML5+开发APP,对于后端处理不太了解,昨天还发帖询问呢,但是没有人回答,经过不懈的努力,终于搞定了,现将后端处理的代码分享上来!
此程序需要的jar包如下:
commons-fileupload-1.2.1.jar
commons-io-1.4.jar
需将两个jar包放到工程的lib文件夹下,上传页面的代码我用的是HelloH5+项目的uploader.html,这个应该很好找,后端的上传处理我用的是Servlet,具体的配置方法就不讲了,直接来代码:

import java.io.File;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.InputStream;  
import java.util.Calendar;  
import java.util.Iterator;  
import java.util.List;  
import java.util.Random;  
import java.util.UUID;  

import javax.servlet.ServletException;  
import javax.servlet.http.HttpServlet;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import org.apache.commons.fileupload.FileItem;  
import org.apache.commons.fileupload.FileUploadBase;  
import org.apache.commons.fileupload.ProgressListener;  
import org.apache.commons.fileupload.disk.DiskFileItemFactory;  
import org.apache.commons.fileupload.servlet.ServletFileUpload;  
/**  
 * Apache组件上传  
 *   
 * @author 于世海  
 * @date 2016-02-17  
 */  
public class UploadHandleServlet extends HttpServlet {  

    private static final long serialVersionUID = 5827821285414610443L;  

    public void doGet(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
        this.doPost(request, response);  
    }  

    public void doPost(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
        // 上传文件目录  
        String uploadDir = this.getServletContext().getRealPath("/upload");  
        DiskFileItemFactory factory = new DiskFileItemFactory();  
        // 设置内存区块大小4KB  
        factory.setSizeThreshold(4 * 1024);  
        // 设置暂存容器,当上传文件大于设置的内存块大小时,用暂存容器做中转  
        factory.setRepository(new File(this.getServletContext().getRealPath(  
                "/temp")));  
        ServletFileUpload fileUpload = new ServletFileUpload(factory);  
        fileUpload.setSizeMax(1024 * 1024 * 100);  
        //fileUpload.setFileSizeMax(1024 * 1024 * 10);  
        List<FileItem> fileItemList = null;  

        try {  
            fileItemList = fileUpload.parseRequest(request);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        Iterator<FileItem> fileItemIterator = fileItemList.iterator();  
        FileItem fileItem = null;  
        while (fileItemIterator.hasNext()) {  
            fileItem = fileItemIterator.next();  
            // 普通文件框上传  
            if (fileItem.isFormField()) {  
                String filedName = fileItem.getFieldName();  
                String filedValue = fileItem.getString("GBK");// 编码格式  
                System.out.println(filedName);// 文件框名称  
                System.out.println(filedValue);// 文件的值  
            } else {  
                String filedName = fileItem.getFieldName();// 文件上传框的名称  
                // 获取文件上传的文件名  
                String OriginalFileName = takeOutFileName(fileItem.getName());  
                System.out.println("原始文件名:"+OriginalFileName);  
                if (!"".equals(OriginalFileName)) {  
                    // 根据上传的文件名重新命名  
                    String newFileName = getNewFileName(OriginalFileName);  
                    System.out.println("重新名:"+newFileName);  
                    File writeToFile = new File(uploadDir + File.separator  
                            + newFileName);  
                    try {  
                        fileItem.write(writeToFile);  
                    } catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
            }  
        }  
    }  

    private String takeOutFileName(String filePath) {  
        String fileName = filePath;  
        if (null != filePath && !"".equals(filePath)) {  
            int port = filePath.lastIndexOf("\\");  
            if(port != -1){  
                fileName = filePath.substring(port+1);  
            }  
        }  
        return fileName;  
    }  

    private String getNewFileName(String originalFileName) {  
        StringBuffer newFileName = new StringBuffer();  
        if (null != originalFileName && !"".equals(originalFileName)) {  
            int port = originalFileName.lastIndexOf(".");  
            String type = "";  
            String fileName = "";  
            if (port != -1) {  
                type = originalFileName.substring(port + 1);  
                fileName = originalFileName.substring(0, port);  
            } else {  
                fileName = originalFileName;  
            }  
            StringBuffer suffix = new StringBuffer("_");  
            suffix.append(Calendar.getInstance().getTimeInMillis());  
            suffix.append("_");  
            suffix.append(new Random().nextInt(100));  
            newFileName.append(fileName);  
            newFileName.append(suffix);  
            newFileName.append(".");  
            newFileName.append(type);  
        }  
        return newFileName.toString();  
    }  

}

其他的处理代码直接修改就可以了!

继续阅读 »

由于刚刚接触HTML5+开发APP,对于后端处理不太了解,昨天还发帖询问呢,但是没有人回答,经过不懈的努力,终于搞定了,现将后端处理的代码分享上来!
此程序需要的jar包如下:
commons-fileupload-1.2.1.jar
commons-io-1.4.jar
需将两个jar包放到工程的lib文件夹下,上传页面的代码我用的是HelloH5+项目的uploader.html,这个应该很好找,后端的上传处理我用的是Servlet,具体的配置方法就不讲了,直接来代码:

import java.io.File;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.InputStream;  
import java.util.Calendar;  
import java.util.Iterator;  
import java.util.List;  
import java.util.Random;  
import java.util.UUID;  

import javax.servlet.ServletException;  
import javax.servlet.http.HttpServlet;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import org.apache.commons.fileupload.FileItem;  
import org.apache.commons.fileupload.FileUploadBase;  
import org.apache.commons.fileupload.ProgressListener;  
import org.apache.commons.fileupload.disk.DiskFileItemFactory;  
import org.apache.commons.fileupload.servlet.ServletFileUpload;  
/**  
 * Apache组件上传  
 *   
 * @author 于世海  
 * @date 2016-02-17  
 */  
public class UploadHandleServlet extends HttpServlet {  

    private static final long serialVersionUID = 5827821285414610443L;  

    public void doGet(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
        this.doPost(request, response);  
    }  

    public void doPost(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
        // 上传文件目录  
        String uploadDir = this.getServletContext().getRealPath("/upload");  
        DiskFileItemFactory factory = new DiskFileItemFactory();  
        // 设置内存区块大小4KB  
        factory.setSizeThreshold(4 * 1024);  
        // 设置暂存容器,当上传文件大于设置的内存块大小时,用暂存容器做中转  
        factory.setRepository(new File(this.getServletContext().getRealPath(  
                "/temp")));  
        ServletFileUpload fileUpload = new ServletFileUpload(factory);  
        fileUpload.setSizeMax(1024 * 1024 * 100);  
        //fileUpload.setFileSizeMax(1024 * 1024 * 10);  
        List<FileItem> fileItemList = null;  

        try {  
            fileItemList = fileUpload.parseRequest(request);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        Iterator<FileItem> fileItemIterator = fileItemList.iterator();  
        FileItem fileItem = null;  
        while (fileItemIterator.hasNext()) {  
            fileItem = fileItemIterator.next();  
            // 普通文件框上传  
            if (fileItem.isFormField()) {  
                String filedName = fileItem.getFieldName();  
                String filedValue = fileItem.getString("GBK");// 编码格式  
                System.out.println(filedName);// 文件框名称  
                System.out.println(filedValue);// 文件的值  
            } else {  
                String filedName = fileItem.getFieldName();// 文件上传框的名称  
                // 获取文件上传的文件名  
                String OriginalFileName = takeOutFileName(fileItem.getName());  
                System.out.println("原始文件名:"+OriginalFileName);  
                if (!"".equals(OriginalFileName)) {  
                    // 根据上传的文件名重新命名  
                    String newFileName = getNewFileName(OriginalFileName);  
                    System.out.println("重新名:"+newFileName);  
                    File writeToFile = new File(uploadDir + File.separator  
                            + newFileName);  
                    try {  
                        fileItem.write(writeToFile);  
                    } catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
            }  
        }  
    }  

    private String takeOutFileName(String filePath) {  
        String fileName = filePath;  
        if (null != filePath && !"".equals(filePath)) {  
            int port = filePath.lastIndexOf("\\");  
            if(port != -1){  
                fileName = filePath.substring(port+1);  
            }  
        }  
        return fileName;  
    }  

    private String getNewFileName(String originalFileName) {  
        StringBuffer newFileName = new StringBuffer();  
        if (null != originalFileName && !"".equals(originalFileName)) {  
            int port = originalFileName.lastIndexOf(".");  
            String type = "";  
            String fileName = "";  
            if (port != -1) {  
                type = originalFileName.substring(port + 1);  
                fileName = originalFileName.substring(0, port);  
            } else {  
                fileName = originalFileName;  
            }  
            StringBuffer suffix = new StringBuffer("_");  
            suffix.append(Calendar.getInstance().getTimeInMillis());  
            suffix.append("_");  
            suffix.append(new Random().nextInt(100));  
            newFileName.append(fileName);  
            newFileName.append(suffix);  
            newFileName.append(".");  
            newFileName.append(type);  
        }  
        return newFileName.toString();  
    }  

}

其他的处理代码直接修改就可以了!

收起阅读 »

这个是一篇好文章

这是非常好的文章,偶然间读到这个文章,感觉非常有用,但是当时疏忽没有拷贝url,本以为还可以再找到。
关闭页面后开始编程,过一会想找这个页面就找不到了,找了整整3个小时才找到。

以下是链接,没看过的一定要看一下,看过的略过
http://ask.dcloud.net.cn/article/25

,感觉社区目录排版有些混乱,或许是刚来的原因。
支持Dcloud!!

继续阅读 »

这是非常好的文章,偶然间读到这个文章,感觉非常有用,但是当时疏忽没有拷贝url,本以为还可以再找到。
关闭页面后开始编程,过一会想找这个页面就找不到了,找了整整3个小时才找到。

以下是链接,没看过的一定要看一下,看过的略过
http://ask.dcloud.net.cn/article/25

,感觉社区目录排版有些混乱,或许是刚来的原因。
支持Dcloud!!

收起阅读 »

Andriod下拉刷新失效,pullRefresh问题

下拉刷新

今天做一个下拉刷新评论的模块,iOS版本上面正常,在Andriod上面却失效,查了很久最后发现原因是初始化载入数据的问题;
Andriod机器上,如果我一初始化瞬间就加载数据(loadComment),会导致整个下拉失效,后来发现需要延迟一点才可以,所以再plusReady防法上写了下面代码;

mui.plusReady(function(){  
    //加载评论  
    if(mui.os.android){  
        //Andriod容易加载太快导致初始化下拉失败  
        setTimeout('loadComment()',800);  
    }else{  
        loadComment();  
    }  
});  

mui.init({  
    pullRefresh: {  
        container: '#pullrefresh',  
        down:{  
            callback: pulldownRefresh  
        }  
    }  
});

浪费了很多时间,所以写出来希望能给朋友们一些思路;

继续阅读 »

今天做一个下拉刷新评论的模块,iOS版本上面正常,在Andriod上面却失效,查了很久最后发现原因是初始化载入数据的问题;
Andriod机器上,如果我一初始化瞬间就加载数据(loadComment),会导致整个下拉失效,后来发现需要延迟一点才可以,所以再plusReady防法上写了下面代码;

mui.plusReady(function(){  
    //加载评论  
    if(mui.os.android){  
        //Andriod容易加载太快导致初始化下拉失败  
        setTimeout('loadComment()',800);  
    }else{  
        loadComment();  
    }  
});  

mui.init({  
    pullRefresh: {  
        container: '#pullrefresh',  
        down:{  
            callback: pulldownRefresh  
        }  
    }  
});

浪费了很多时间,所以写出来希望能给朋友们一些思路;

收起阅读 »

H5国际化的实现[基于i18n]

国际化 i18n

要过年啦,客户的项目还没开始动工,客户就喊着要 客户端支持国际化,要中英文双语的。
....度娘....,果然还是有解决方案的。 依然是基于 jquery 的,学名:i18n
首先呢,还是加引用,可以是这样的。

<script src="//cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js"></script>  
        <script type="text/javascript" src="js/jquery.i18n.properties-min-1.0.9.js"></script>

其次呢,Dom结构咯;这里我就简单的放了俩按钮,第一个是表现的,第二个用来点击触发改变用的;

<div class="mui-content">  
            <button id='btn'></button>  

            <button id='changelanguage'></button>  
        </div>  
最后呢,就是js代码了
``````javascript  
<script>  
            var lang = '';  
            $(function() {  
                lang = (jQuery.i18n.browserLang().substring(0, 2)); //默认从浏览器语言读取  
                jQuery.i18n.properties({  
                    name: 'strings',  
                    path: 'i18n/', //资源文件路径  
                    mode: 'map', //用Map的方式使用资源文件中的值  
                    language: lang,  
                    callback: function() { //加载成功后设置显示内容  
                        $('#btn').html($.i18n.prop('btn'));  
                        $('#changelanguage').html($.i18n.prop('changelanguage'));  
                    }  
                });  
            })  
            document.getElementById("changelanguage").addEventListener('tap', function() {  
                if ('zh' == lang) {  
                    lang = 'en';  
                } else {  
                    lang = 'zh';  
                }  
                jQuery.i18n.properties({  
                    name: 'strings',  
                    path: 'i18n/', //资源文件路径  
                    mode: 'map', //用Map的方式使用资源文件中的值  
                    language: lang,  
                    callback: function() { //加载成功后设置显示内容  
                        $('#btn').html($.i18n.prop('btn'));  
                        $('#changelanguage').html($.i18n.prop('changelanguage'));  
                    }  
                });  
            });  
        </script>

好了,上面都是页面上代码了,最最后就是对应的配置文件了,你不配置,代码怎么知道你的英文要先显示成什么中文呢??
只要指定要配置的id就行。比如上面的按钮的id是 btn,所以这里配置文件里 写btn;
没了。就这么多了,最后附上包

继续阅读 »

要过年啦,客户的项目还没开始动工,客户就喊着要 客户端支持国际化,要中英文双语的。
....度娘....,果然还是有解决方案的。 依然是基于 jquery 的,学名:i18n
首先呢,还是加引用,可以是这样的。

<script src="//cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js"></script>  
        <script type="text/javascript" src="js/jquery.i18n.properties-min-1.0.9.js"></script>

其次呢,Dom结构咯;这里我就简单的放了俩按钮,第一个是表现的,第二个用来点击触发改变用的;

<div class="mui-content">  
            <button id='btn'></button>  

            <button id='changelanguage'></button>  
        </div>  
最后呢,就是js代码了
``````javascript  
<script>  
            var lang = '';  
            $(function() {  
                lang = (jQuery.i18n.browserLang().substring(0, 2)); //默认从浏览器语言读取  
                jQuery.i18n.properties({  
                    name: 'strings',  
                    path: 'i18n/', //资源文件路径  
                    mode: 'map', //用Map的方式使用资源文件中的值  
                    language: lang,  
                    callback: function() { //加载成功后设置显示内容  
                        $('#btn').html($.i18n.prop('btn'));  
                        $('#changelanguage').html($.i18n.prop('changelanguage'));  
                    }  
                });  
            })  
            document.getElementById("changelanguage").addEventListener('tap', function() {  
                if ('zh' == lang) {  
                    lang = 'en';  
                } else {  
                    lang = 'zh';  
                }  
                jQuery.i18n.properties({  
                    name: 'strings',  
                    path: 'i18n/', //资源文件路径  
                    mode: 'map', //用Map的方式使用资源文件中的值  
                    language: lang,  
                    callback: function() { //加载成功后设置显示内容  
                        $('#btn').html($.i18n.prop('btn'));  
                        $('#changelanguage').html($.i18n.prop('changelanguage'));  
                    }  
                });  
            });  
        </script>

好了,上面都是页面上代码了,最最后就是对应的配置文件了,你不配置,代码怎么知道你的英文要先显示成什么中文呢??
只要指定要配置的id就行。比如上面的按钮的id是 btn,所以这里配置文件里 写btn;
没了。就这么多了,最后附上包

收起阅读 »

MUI的TAP事件在部分手机上会执行2次

已经验证HBuilder 版本 HBuilder 6.9.2.201601052351

MUI框架的事件tap在很多机器上都会被执行2次,换成click事件问题立即解决。
绝对不是两个窗体或者2次绑定引起的。已经在INSPECT里面调试过了。只有一个窗体实例,元素上也只有1个TAP监听。

我一直要求员工都用MUI的TAP事件。例如用TAP打开一个窗口。造成窗口都要闪烁2次,我原来以为是加速造成,结果发现完全是TAP引起的。。一次偶然,用TAP事件上,绑定了一个plus.nativeUI.alert,结果弹了2次框,我这才发现这个问题。。立即把所有TAP都改成CLICK了,结果所有因2次执行引起的闪烁全部消失。

以上问题不是在全部机器上都出现。。我用自己的NOTE5出现,用一个华为的手机出现。。有些小米手机出现,有些不出现。。未深究TAP的JS代码,有时间多的高人看看有没有更好的解决方案。

继续阅读 »

已经验证HBuilder 版本 HBuilder 6.9.2.201601052351

MUI框架的事件tap在很多机器上都会被执行2次,换成click事件问题立即解决。
绝对不是两个窗体或者2次绑定引起的。已经在INSPECT里面调试过了。只有一个窗体实例,元素上也只有1个TAP监听。

我一直要求员工都用MUI的TAP事件。例如用TAP打开一个窗口。造成窗口都要闪烁2次,我原来以为是加速造成,结果发现完全是TAP引起的。。一次偶然,用TAP事件上,绑定了一个plus.nativeUI.alert,结果弹了2次框,我这才发现这个问题。。立即把所有TAP都改成CLICK了,结果所有因2次执行引起的闪烁全部消失。

以上问题不是在全部机器上都出现。。我用自己的NOTE5出现,用一个华为的手机出现。。有些小米手机出现,有些不出现。。未深究TAP的JS代码,有时间多的高人看看有没有更好的解决方案。

收起阅读 »

【分享】常见字符集,字符编码编码和相互之间的转换以及Base64加密

技术分享 base64 字符编码

最近在用JS时,涉及到了不同编码之间的转换.于是汇总了一些网上的资料,整合成了自己的文档.

知识点涉及:
1.字符编码基础,几种常见字符编码的基本概念

  1. 不同编码之间的转换,如UTF-8转UTF-16,如UTF-16转GBK;
  2. Base64加密,GBK型与UTF-8型加密等
  3. 示例demo(js实现),比如如何用js将utf-16编码(js内置编码)转为UTF-8和GBK;比如如何将UTF-16编码的字符串(js内部的字符串)进行base64GBK和UTF-8编码

基础知识:(感谢@maq的提醒,这里普及下,字符集和字符编码的区别)

字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。

字符编码(Character Encoding):是一套法则,使用该法则能够对自然语言的字符的一个集合(如字母表或音节表),与其他东西的一个集合(如号码或电脉冲)进行配对。即在符号集合与数字系统之间建立对应关系,它是信息处理的一项基本技术。通常人们用符号集合(一般情况下就是文字)来表达信息。而以计算机为基础的信息处理系统则是利用元件(硬件)不同状态的组合来存储和处理信息的。元件不同状态的组合能代表数字系统的数字,因此字符编码就是将符号转换为计算机可以接受的数字系统的数,称为数字代码

常用字符集和字符编码

常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。经常说的GB2312即是字符集也是字符编码,所以经常将字符集和字符编码混着说.
参考来源:http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html

注:原文是在csdn博客上的,这里就不重复了.直接给出链接.(里面包含demo)

http://blog.csdn.net/u010979495/article/details/50601511

继续阅读 »

最近在用JS时,涉及到了不同编码之间的转换.于是汇总了一些网上的资料,整合成了自己的文档.

知识点涉及:
1.字符编码基础,几种常见字符编码的基本概念

  1. 不同编码之间的转换,如UTF-8转UTF-16,如UTF-16转GBK;
  2. Base64加密,GBK型与UTF-8型加密等
  3. 示例demo(js实现),比如如何用js将utf-16编码(js内置编码)转为UTF-8和GBK;比如如何将UTF-16编码的字符串(js内部的字符串)进行base64GBK和UTF-8编码

基础知识:(感谢@maq的提醒,这里普及下,字符集和字符编码的区别)

字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。

字符编码(Character Encoding):是一套法则,使用该法则能够对自然语言的字符的一个集合(如字母表或音节表),与其他东西的一个集合(如号码或电脉冲)进行配对。即在符号集合与数字系统之间建立对应关系,它是信息处理的一项基本技术。通常人们用符号集合(一般情况下就是文字)来表达信息。而以计算机为基础的信息处理系统则是利用元件(硬件)不同状态的组合来存储和处理信息的。元件不同状态的组合能代表数字系统的数字,因此字符编码就是将符号转换为计算机可以接受的数字系统的数,称为数字代码

常用字符集和字符编码

常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。经常说的GB2312即是字符集也是字符编码,所以经常将字符集和字符编码混着说.
参考来源:http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html

注:原文是在csdn博客上的,这里就不重复了.直接给出链接.(里面包含demo)

http://blog.csdn.net/u010979495/article/details/50601511

收起阅读 »

webview页面中的子webview之间相互操作

今天开发中遇到A 页面中嵌套了B页面,然后B页面中的数据收到的值变化时,切A页面的稿件的参数也要变化见图!
开始一直通过plus.webview.getWebviewById('URL').evalJS();去操控A页面的函数方法,但是一直不可以,拿不到A的webview,后来去认
真看了API文档后才发现自己进入到了一个误区!
因为是嵌套的webview所以,我们可以先拿到当前我们操作的这个页面,就是我所谓的B页面的webview;
var centerView= plus.webview.currentWebview();
然后我们再去拿到B页面的父页面,就是所谓的A webview页面;
var par=centerView.parent();
关于parent这个方法参考地址:http://www.dcloud.io/docs/api/zh_cn/webview.shtml#plus.webview.WebviewObject.parent
这样我们就拿到了最外层的的父webview,然后操控par.evalJS();就可以执行A页面的函数了!
虽然我的描述方式差,逻辑差,文笔也差,这点东西也算不上什么,给予那些正需要的人的一点帮助吧!因为我就是没有在论坛找到相应
的解决办法(也可能有,但是我没有搜索对关键词,其次就是这个网站的搜索太垃圾了!嘻嘻),才去看文档的,不过建议还是多看文档!

继续阅读 »

今天开发中遇到A 页面中嵌套了B页面,然后B页面中的数据收到的值变化时,切A页面的稿件的参数也要变化见图!
开始一直通过plus.webview.getWebviewById('URL').evalJS();去操控A页面的函数方法,但是一直不可以,拿不到A的webview,后来去认
真看了API文档后才发现自己进入到了一个误区!
因为是嵌套的webview所以,我们可以先拿到当前我们操作的这个页面,就是我所谓的B页面的webview;
var centerView= plus.webview.currentWebview();
然后我们再去拿到B页面的父页面,就是所谓的A webview页面;
var par=centerView.parent();
关于parent这个方法参考地址:http://www.dcloud.io/docs/api/zh_cn/webview.shtml#plus.webview.WebviewObject.parent
这样我们就拿到了最外层的的父webview,然后操控par.evalJS();就可以执行A页面的函数了!
虽然我的描述方式差,逻辑差,文笔也差,这点东西也算不上什么,给予那些正需要的人的一点帮助吧!因为我就是没有在论坛找到相应
的解决办法(也可能有,但是我没有搜索对关键词,其次就是这个网站的搜索太垃圾了!嘻嘻),才去看文档的,不过建议还是多看文档!

收起阅读 »

M站、WAP站改造流应用指南

流应用

在wap2app推出后,开发者根据wap2app即可快速完成app及流应用提交。
具体见http://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/13425

============以下内容已过期=================

背景和问题

流应用本身是可以达到原生app的体验的,从应用体验来讲,c/s方式比b/s方式体验更好:

  1. c/s的首页启动更快;
  2. c/s的页面转场更快;
  3. c/s具有脱线访问性。

所以如果开发新app,我们建议开发者使用mui框架,开发一次多端发布,流应用、wap、app都自动生成。
不过实际情况中大量开发商已经有了wap站和原生app,但仍需要制作流应用,那么此时他们需要一种在开发成本和用户体验之间取得平衡的一种方法。

如何基于m站快速改造出流应用,体验还不错,并维持版本的统一更新发布,这是本文讲解的内容。

前提准备

m站的体验本身要好,控件风格app化而不是浏览器化。
反面例子:有的m站的列表仍然是超链接方式,而不是list方式,体验就很差。举例:http://www.beijing.gov.cn/sjbsy/
正面例子:卖座电影
这些链接如果在pc上打开,请在浏览器控制台里调整为手机模式观看。
当然大多数m站的实际状态是处于2者之间的。

在改造方面,有两种大的思路。

  1. 修改m站源码,根据ua动态引用增强的js,发现ua包含html5plus或stream时,动态引入一些js,实现对HTML5+扩展能力的调用
  2. 不修改m站源码,利用wap2app框架进行wap站配置,完成增强体验,wap2app教程建议从《wap2app快速体验》开始入手。

因为wap2app相对成熟,有完整的教程,本文不做过多解释,重点讲解第一种思路,即:修改m站源码,实现流应用的发布。

改造工作

  1. 首页
    如果是直接改wap站源码,那么在首页引入一个streamapp.js的文件,然后在这个js里编写代码控制整个app的体验强化。
    同时注意在这个js要拦截所有页面切换请求,点击首页后的所有窗体切换均为新开webview,保证首页的webview一直存在,否则强化的js文件也会不见掉,导致无法再生效。

    我们需要在HBuilder里新建一个移动app项目,才能提交流应用。新建工程时注意调整manifest.json:
    a) 项目首页就是wap站地址
    b) 项目的manifest.json 加 popGesture":"close"
    c) 控制页create显示webview时,webview style设置popGesture为none
    不调整的话,在iOS上左滑屏幕返回时会露出空白的控制webview。
    d) 强制打开硬件加速,具体参考http://ask.dcloud.net.cn/article/94

  2. 登陆注册体验
    很多wap站的用户登陆cookie有效期只有一周,一周后需要用户重新输入用户名密码,app可不会这么设计。如果用户在桌面安装了一个流应用,就不应该让他一周后重新输入用户名密码登陆。开发者可根据流应用引擎的ua(包括steamapp)判断,设置流应用的cookie有效期为永久。
    还有很多wap站在登陆时需要输入验证码,这都是比较糟糕的体验,同样也需要判断ua,去掉验证码。

    注册优化也是很重要的问题,对于技术人员而言,未必关心从app激活到注册之间的折损,但产品负责人和运营是非常关心这个数据的。
    流应用提供了优化注册折损的方案,通过plus.oauth,可以调用一键登入,如果wap站本身有单点登陆接口,尽量支持好流应用的一键登陆。
    尤其是用户注册基数不大或品牌不强的新app,如果用户体验产品或消费下单前有比较高的注册门槛,很容易折损流失。
    需要开发单点登陆的开发商,除了客户端调用plus.oauth外还需要服务器对接。请加入底部显示的流应用qq群,与管理员沟通,我们会单独提供服务器端对接的文档和api。

  3. back处理
    浏览器的back是非常难用的,它的顺序是用户访问页面的先后顺序,而不是app的逻辑顺序,流应用的back逻辑需要单独处理。
    Android的back按键需要通过plus.key来监听和处理,不能简单的走网页的前进后退,要按app的逻辑处理后退。
    比如,页面A跳转到B时发现需要登陆,进入了登陆页C,登陆后又进入了页面B,此时点back,要求回页面A,而不是后退到登陆页。
    再比如,从首页点了一个栏目1,back回首页,然后点了栏目2,再back回首页,此时按back,应该提醒是否退出app而不是后退到栏目1里。一般在首页里按back一定是提醒退出app而不是走浏览器的history back。
    另外注意有的列表页面滚动后,点一个列表项进入下一个页面,点back回到刚才的列表页面,但滚动条跑最顶部了,这种情况体验太差,要处理。
    流应用需要在首页监听back按键,设计退出逻辑,比如连续按2下back退出,或者按一下back弹出confirm框,询问用户是否退出。
    如果用户是push或wap导流来的,那么退出时,应提示用户下次可以从桌面直接启动,不然会有不少用户不知道桌面多了一个图标。
    除了页面切换的back,当页面中出现一个div选择层,此时点back应该是关闭选择层而不是整体后退。
    参考http://www.html5plus.org/doc/zh_cn/key.html

  4. 页面切换等待
    页面切换不能白屏,不能依赖浏览器的进度条,切换过程要有自己的模态进度指示如转雪花,避免在新页面切换完成前用户连续点击引发问题。
    参考http://www.html5plus.org/doc/zh_cn/nativeui.html#plus.nativeUI.Waiting
    由于wap网页的载入速度较慢,一般的体验优化做法是在首页注入的控制js里绘制一个原生的title,使用plus.nativeobj里的原生view绘制title,可以快速展现title出来,然后title下面加载wap页面。

  5. 去wap的展现形式
    有些wap页面底部有电脑版、手机版,还有版权或icp信息,还有原生app的下载banner,这都不是app感觉,都需要去掉;实现方案参考:如何在流应用环境下去wap化展现

  6. 原生定位
    如果业务涉及定位,把HTML5的定位改为plus的原生定位。
    HTML5的定位会弹框让用户选择是否允许某网页访问位置,体验太差,而且HTML5的定位速度、精度都不够。改调原生定位又快又准又不弹框。
    流应用提供的定位是高德定位的坐标系。
    在物流相关业务里,配送地址可以通过流应用的api查询到街道信息,可以自动填写到送货地址的输入框中,避免用户敲太多字。
    用户有可能未开启手机的gps或未给应用赋予定位权限,对于强定位需求的app,需要写代码调用流应用的api判断并提醒用户开启gps或相应权限,在弹出框跳转到系统设置里开启定位或赋权并返回后,应自动刷新重调定位api。
    参考:http://html5plus.org/doc/zh_cn/geolocation.html
    参考:http://ask.dcloud.net.cn/question/11890

  7. 原生支付
    流应用提供了原生的支付宝支付和微信支付能力,开发商可参考流应用提供的原生支付api,改进支付体验。
    目前支付宝和微信支付,都支持通过h5的schemes调起本机的原生app进行原生支付,体验比较好,wap站改造量也比较小。
    关于微信的h5支付,需要开发商向微信申请微信wap支付资格,有了该资格,可以在HTML5页面里直接调起微信的原生支付。
    微信wap支付其实就是微信公众号里的支付方式,可以放大到不止是在微信浏览器里可支付,在外部浏览器里也可以再调起微信来完成支付。
    目前大大小小很多开发商都申请到了wap支付资格,比如京东、唯品会、卖座电影、蛋糕叔叔…
    开发商之前的M站的支付宝支付都是wap支付,要输入较长的用户名、密码,体验差、折损高。
    目前看到的数据是用户点微信和支付宝的占比基本是55开,这两种支付方式都应该优化到位。

  8. 硬件加速
    如果是使用控制webview创建显示webview的方式做流应用,注意在显示webview创建时对webview开启硬件加速,以提升页面滚动流畅度。
    参考http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewStyle 里的hardwareAccelerated

  9. 网络异常处理
    网络异常导致页面打不开或ajax请求失败,需要单独控制。因为在浏览器里有工具栏和刷新按钮,用户可以自己刷新,但在流应用里没有刷新按钮。而且一旦进入404界面会很难看。
    推荐的体验是流应用的本地代码有网络监听判断,如果用户没有开启网络,则应该提醒用户开启,如果用户网络异常,应弹出提示框,让用户选择重试或退出。
    参考 http://www.html5plus.org/doc/zh_cn/device.html#plus.networkinfo
    参考 http://ask.dcloud.net.cn/question/1475

  10. Titile处理
    有些wap页面没有title或title不能固定,在全屏app界面里不应该出现这种情况,需要每个界面都有title、并且保持固定在顶部。除首页外每个界面的左上角都应该有返回按钮,不能仅依赖back按键来返回。

  11. 桌面快捷方式修复
    桌面快捷方式驻留是流应用留存率的基础。可以从桌面直接启动才能增加次日或7日留存。
    用户可能会误删除桌面上的某流应用的快捷方式。所以需要app在关于界面或其他合适位置放置快捷方式修复的按钮。
    体验参考 大众点评外卖流应用的右上角关于按钮。
    代码参考:http://ask.dcloud.net.cn/article/406

  12. 打点统计
    流应用是可以采集imei的,流应用的统计不是按uv统计,而是按imei的激活统计。
    流应用启动后,应像App一样给后台App统计系统报数打点。
    DCloud给所有流应用开发商提供了数据报表,因为流应用客户端包的下载和更新是在我们的服务器上,并且每个流应用每次启动时会自动检查更新,所以我们可以给开发商完善的报表数据,包括下载、激活、日活、留存、总设备数以及下载来源分析,比如是搜索下载、快码下载、分享下载、wap导量下载、push下载...。DCloud还有订单回传接口,开发商调用后还可在DCloud提供的报表系统里看到订单统计。
    大开发商一般要求自己的后台也需要报数统计,并m站的uv统计是现成的。但是uv不如imei准,有些开发商发现自己统计的uv多于DCloud报表里提供的日活,建议开发商把uv统计里的cookie id值设为imei,通过plus.device取imei,这样开发商的uv和DCloud报表里的激活能对上。
    如果想采集本机是否安装了本公司的其他app产品或竞品的安装情况,也是可以采集的。
    参考:http://www.html5plus.org/doc/zh_cn/device.html
    参考:http://ask.dcloud.net.cn/question/7604

  13. 快码和直通车
    快码和分享直通车是流应用的重要功能,对于拉新和二次传播作用明显,建议使用。
    快码无需开发,在HBuilder的菜单发行里申请即可。
    这里是快码的介绍和申请指南:http://ask.dcloud.net.cn/article/492

    直通车需要开发,但社交直购等分享直通车的功能价值很明显。
    体验参考 大众点评外卖流应用的右上角关于按钮里的快码和饭馆分享里的分享直通车。
    视频参考:http://v.qq.com/boke/gplay/c17d8789e7dd8a208cd6e6189ae90664_nst000001qufah3_r0171bswy6f.html
    代码参考 Hello H5+里的分享源代码。

  14. 其他细节
    如果涉及到照片选择上传、文件上传、摄像头麦克风控制,也请将HTML5的代码替换为HTML5+的代码,以得到更好的体验。
    参考:http://www.html5plus.org/doc/

关于一次开发多端发布

通过条件编译工具如glup,可以做到一套代码同时输出m站和流应用,避免多处维护业务逻辑变更的烦恼。
Mui框架本身是支持多端发布的,Hello mui是一个浏览器、流应用、Android app、iOS app一套代码多端均可使用的示例,可参考Hello mui的代码。

案例推荐

关于把M站改造为流应用,可以参考如下案例。

唯品会
唯品会是wap站改造流应用里做的体验较好的应用。
唯品会的业务特点决定了其页面里大量动态内容,其原生app里也有很多wap页面。
流应用版的唯品会和原生版的唯品会差异很小。
唯品会的快码
请使用360手助扫码体验

合作支持

对于有较大流量的wap站,可以发邮件到stream@dcloud.io,说明wap站地址和联系方式,我们可以提供电话咨询,协助快速完成转换。

继续阅读 »

在wap2app推出后,开发者根据wap2app即可快速完成app及流应用提交。
具体见http://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/13425

============以下内容已过期=================

背景和问题

流应用本身是可以达到原生app的体验的,从应用体验来讲,c/s方式比b/s方式体验更好:

  1. c/s的首页启动更快;
  2. c/s的页面转场更快;
  3. c/s具有脱线访问性。

所以如果开发新app,我们建议开发者使用mui框架,开发一次多端发布,流应用、wap、app都自动生成。
不过实际情况中大量开发商已经有了wap站和原生app,但仍需要制作流应用,那么此时他们需要一种在开发成本和用户体验之间取得平衡的一种方法。

如何基于m站快速改造出流应用,体验还不错,并维持版本的统一更新发布,这是本文讲解的内容。

前提准备

m站的体验本身要好,控件风格app化而不是浏览器化。
反面例子:有的m站的列表仍然是超链接方式,而不是list方式,体验就很差。举例:http://www.beijing.gov.cn/sjbsy/
正面例子:卖座电影
这些链接如果在pc上打开,请在浏览器控制台里调整为手机模式观看。
当然大多数m站的实际状态是处于2者之间的。

在改造方面,有两种大的思路。

  1. 修改m站源码,根据ua动态引用增强的js,发现ua包含html5plus或stream时,动态引入一些js,实现对HTML5+扩展能力的调用
  2. 不修改m站源码,利用wap2app框架进行wap站配置,完成增强体验,wap2app教程建议从《wap2app快速体验》开始入手。

因为wap2app相对成熟,有完整的教程,本文不做过多解释,重点讲解第一种思路,即:修改m站源码,实现流应用的发布。

改造工作

  1. 首页
    如果是直接改wap站源码,那么在首页引入一个streamapp.js的文件,然后在这个js里编写代码控制整个app的体验强化。
    同时注意在这个js要拦截所有页面切换请求,点击首页后的所有窗体切换均为新开webview,保证首页的webview一直存在,否则强化的js文件也会不见掉,导致无法再生效。

    我们需要在HBuilder里新建一个移动app项目,才能提交流应用。新建工程时注意调整manifest.json:
    a) 项目首页就是wap站地址
    b) 项目的manifest.json 加 popGesture":"close"
    c) 控制页create显示webview时,webview style设置popGesture为none
    不调整的话,在iOS上左滑屏幕返回时会露出空白的控制webview。
    d) 强制打开硬件加速,具体参考http://ask.dcloud.net.cn/article/94

  2. 登陆注册体验
    很多wap站的用户登陆cookie有效期只有一周,一周后需要用户重新输入用户名密码,app可不会这么设计。如果用户在桌面安装了一个流应用,就不应该让他一周后重新输入用户名密码登陆。开发者可根据流应用引擎的ua(包括steamapp)判断,设置流应用的cookie有效期为永久。
    还有很多wap站在登陆时需要输入验证码,这都是比较糟糕的体验,同样也需要判断ua,去掉验证码。

    注册优化也是很重要的问题,对于技术人员而言,未必关心从app激活到注册之间的折损,但产品负责人和运营是非常关心这个数据的。
    流应用提供了优化注册折损的方案,通过plus.oauth,可以调用一键登入,如果wap站本身有单点登陆接口,尽量支持好流应用的一键登陆。
    尤其是用户注册基数不大或品牌不强的新app,如果用户体验产品或消费下单前有比较高的注册门槛,很容易折损流失。
    需要开发单点登陆的开发商,除了客户端调用plus.oauth外还需要服务器对接。请加入底部显示的流应用qq群,与管理员沟通,我们会单独提供服务器端对接的文档和api。

  3. back处理
    浏览器的back是非常难用的,它的顺序是用户访问页面的先后顺序,而不是app的逻辑顺序,流应用的back逻辑需要单独处理。
    Android的back按键需要通过plus.key来监听和处理,不能简单的走网页的前进后退,要按app的逻辑处理后退。
    比如,页面A跳转到B时发现需要登陆,进入了登陆页C,登陆后又进入了页面B,此时点back,要求回页面A,而不是后退到登陆页。
    再比如,从首页点了一个栏目1,back回首页,然后点了栏目2,再back回首页,此时按back,应该提醒是否退出app而不是后退到栏目1里。一般在首页里按back一定是提醒退出app而不是走浏览器的history back。
    另外注意有的列表页面滚动后,点一个列表项进入下一个页面,点back回到刚才的列表页面,但滚动条跑最顶部了,这种情况体验太差,要处理。
    流应用需要在首页监听back按键,设计退出逻辑,比如连续按2下back退出,或者按一下back弹出confirm框,询问用户是否退出。
    如果用户是push或wap导流来的,那么退出时,应提示用户下次可以从桌面直接启动,不然会有不少用户不知道桌面多了一个图标。
    除了页面切换的back,当页面中出现一个div选择层,此时点back应该是关闭选择层而不是整体后退。
    参考http://www.html5plus.org/doc/zh_cn/key.html

  4. 页面切换等待
    页面切换不能白屏,不能依赖浏览器的进度条,切换过程要有自己的模态进度指示如转雪花,避免在新页面切换完成前用户连续点击引发问题。
    参考http://www.html5plus.org/doc/zh_cn/nativeui.html#plus.nativeUI.Waiting
    由于wap网页的载入速度较慢,一般的体验优化做法是在首页注入的控制js里绘制一个原生的title,使用plus.nativeobj里的原生view绘制title,可以快速展现title出来,然后title下面加载wap页面。

  5. 去wap的展现形式
    有些wap页面底部有电脑版、手机版,还有版权或icp信息,还有原生app的下载banner,这都不是app感觉,都需要去掉;实现方案参考:如何在流应用环境下去wap化展现

  6. 原生定位
    如果业务涉及定位,把HTML5的定位改为plus的原生定位。
    HTML5的定位会弹框让用户选择是否允许某网页访问位置,体验太差,而且HTML5的定位速度、精度都不够。改调原生定位又快又准又不弹框。
    流应用提供的定位是高德定位的坐标系。
    在物流相关业务里,配送地址可以通过流应用的api查询到街道信息,可以自动填写到送货地址的输入框中,避免用户敲太多字。
    用户有可能未开启手机的gps或未给应用赋予定位权限,对于强定位需求的app,需要写代码调用流应用的api判断并提醒用户开启gps或相应权限,在弹出框跳转到系统设置里开启定位或赋权并返回后,应自动刷新重调定位api。
    参考:http://html5plus.org/doc/zh_cn/geolocation.html
    参考:http://ask.dcloud.net.cn/question/11890

  7. 原生支付
    流应用提供了原生的支付宝支付和微信支付能力,开发商可参考流应用提供的原生支付api,改进支付体验。
    目前支付宝和微信支付,都支持通过h5的schemes调起本机的原生app进行原生支付,体验比较好,wap站改造量也比较小。
    关于微信的h5支付,需要开发商向微信申请微信wap支付资格,有了该资格,可以在HTML5页面里直接调起微信的原生支付。
    微信wap支付其实就是微信公众号里的支付方式,可以放大到不止是在微信浏览器里可支付,在外部浏览器里也可以再调起微信来完成支付。
    目前大大小小很多开发商都申请到了wap支付资格,比如京东、唯品会、卖座电影、蛋糕叔叔…
    开发商之前的M站的支付宝支付都是wap支付,要输入较长的用户名、密码,体验差、折损高。
    目前看到的数据是用户点微信和支付宝的占比基本是55开,这两种支付方式都应该优化到位。

  8. 硬件加速
    如果是使用控制webview创建显示webview的方式做流应用,注意在显示webview创建时对webview开启硬件加速,以提升页面滚动流畅度。
    参考http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewStyle 里的hardwareAccelerated

  9. 网络异常处理
    网络异常导致页面打不开或ajax请求失败,需要单独控制。因为在浏览器里有工具栏和刷新按钮,用户可以自己刷新,但在流应用里没有刷新按钮。而且一旦进入404界面会很难看。
    推荐的体验是流应用的本地代码有网络监听判断,如果用户没有开启网络,则应该提醒用户开启,如果用户网络异常,应弹出提示框,让用户选择重试或退出。
    参考 http://www.html5plus.org/doc/zh_cn/device.html#plus.networkinfo
    参考 http://ask.dcloud.net.cn/question/1475

  10. Titile处理
    有些wap页面没有title或title不能固定,在全屏app界面里不应该出现这种情况,需要每个界面都有title、并且保持固定在顶部。除首页外每个界面的左上角都应该有返回按钮,不能仅依赖back按键来返回。

  11. 桌面快捷方式修复
    桌面快捷方式驻留是流应用留存率的基础。可以从桌面直接启动才能增加次日或7日留存。
    用户可能会误删除桌面上的某流应用的快捷方式。所以需要app在关于界面或其他合适位置放置快捷方式修复的按钮。
    体验参考 大众点评外卖流应用的右上角关于按钮。
    代码参考:http://ask.dcloud.net.cn/article/406

  12. 打点统计
    流应用是可以采集imei的,流应用的统计不是按uv统计,而是按imei的激活统计。
    流应用启动后,应像App一样给后台App统计系统报数打点。
    DCloud给所有流应用开发商提供了数据报表,因为流应用客户端包的下载和更新是在我们的服务器上,并且每个流应用每次启动时会自动检查更新,所以我们可以给开发商完善的报表数据,包括下载、激活、日活、留存、总设备数以及下载来源分析,比如是搜索下载、快码下载、分享下载、wap导量下载、push下载...。DCloud还有订单回传接口,开发商调用后还可在DCloud提供的报表系统里看到订单统计。
    大开发商一般要求自己的后台也需要报数统计,并m站的uv统计是现成的。但是uv不如imei准,有些开发商发现自己统计的uv多于DCloud报表里提供的日活,建议开发商把uv统计里的cookie id值设为imei,通过plus.device取imei,这样开发商的uv和DCloud报表里的激活能对上。
    如果想采集本机是否安装了本公司的其他app产品或竞品的安装情况,也是可以采集的。
    参考:http://www.html5plus.org/doc/zh_cn/device.html
    参考:http://ask.dcloud.net.cn/question/7604

  13. 快码和直通车
    快码和分享直通车是流应用的重要功能,对于拉新和二次传播作用明显,建议使用。
    快码无需开发,在HBuilder的菜单发行里申请即可。
    这里是快码的介绍和申请指南:http://ask.dcloud.net.cn/article/492

    直通车需要开发,但社交直购等分享直通车的功能价值很明显。
    体验参考 大众点评外卖流应用的右上角关于按钮里的快码和饭馆分享里的分享直通车。
    视频参考:http://v.qq.com/boke/gplay/c17d8789e7dd8a208cd6e6189ae90664_nst000001qufah3_r0171bswy6f.html
    代码参考 Hello H5+里的分享源代码。

  14. 其他细节
    如果涉及到照片选择上传、文件上传、摄像头麦克风控制,也请将HTML5的代码替换为HTML5+的代码,以得到更好的体验。
    参考:http://www.html5plus.org/doc/

关于一次开发多端发布

通过条件编译工具如glup,可以做到一套代码同时输出m站和流应用,避免多处维护业务逻辑变更的烦恼。
Mui框架本身是支持多端发布的,Hello mui是一个浏览器、流应用、Android app、iOS app一套代码多端均可使用的示例,可参考Hello mui的代码。

案例推荐

关于把M站改造为流应用,可以参考如下案例。

唯品会
唯品会是wap站改造流应用里做的体验较好的应用。
唯品会的业务特点决定了其页面里大量动态内容,其原生app里也有很多wap页面。
流应用版的唯品会和原生版的唯品会差异很小。
唯品会的快码
请使用360手助扫码体验

合作支持

对于有较大流量的wap站,可以发邮件到stream@dcloud.io,说明wap站地址和联系方式,我们可以提供电话咨询,协助快速完成转换。

收起阅读 »

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;  
    }  
})

修复前:

修复后:

收起阅读 »