HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

NView数据绑定

NView模板 wap2app

除了标准字符串模式的文本、属性设置外,NView模板支持将NView实例数据绑定至NView控件上。

插值

NView模板的文本、属性插值方式相同,均使用大括号({})表示当前为Javascript表达式,不是直接字符串赋值,如下为一个简单示例:

<template>  
    <nviews cacheMaxAge="86400">  
        <nview id="nview1" style="position:static;top:200px;height:50px;">  
            <Font>{data.product_name}</Font>  
        </nview>  
    </nviews>  
</template>  
<script>  
    module.exports = {  
        data: {  
            product_name:'产品名称'  
        }  
    };  
</script>

NView模板中的Javascript表达式,要求必须是单个表达式或JSON对象,如下都是合法的:

<nview id="nview1" style={{  
    //这里是json对象  
    position:"static",  
    top:data.top  
}}>  
    <Font>{data.rem * 17}</Font>  
    <img id="img1" style={{  
            //三元表达式  
            width:data.full?"100%":"80%"  
        }}>  
</nview>

备注:两个大括号{{}}的含义,外层大括号{}表示接下来为Javascript运算符,内层大括号{}表示当前为一个JSON对象。

下面的例子则不生效,因为他们是语句,而不是表达式

<font>{data.rem = 10}</font>

数据源

NView模板可以绑定JavaScript动态计算的数据,数据的提供主要有两种方式:

  • 直接通过data属性提供默认值,这种方式适用于数据相对固定,跟具体业务无关的场景,比如设置界面、开发商等
  • 在init属性中,编写JavaScript代码,根据业务场景动态计算(请求)数据

data属性

默认数据可直接在data属性中提供,data支持Object、Function两种方式,例如:

<script>  
    module.exports = {  
        data: {  
            vendor:'DCloud',  
            city:'北京'  
        }  
    };  
</script>

下面是Function示例,返回值要求是Object类型;Function适合需要简单计算的场景,比如根据屏幕分辨率动态计算文字大小、宽高等场景:

<script>  
    module.exports = {  
        data: function() {  
            return {  
                fontSize:window.screen.width > 360 ? "17px" : "15px",//动态计算  
                vendor:'DCloud'  
            }  
        }  
    };  
</script>

init属性

跟业务相关的数据,可以在init中通过JavaScript编程实现,使用方式如下:

<script>  
    module.exports = {  
        data: {  
            //默认数据  
        },  
        init: function(url) {  
            //url为新开webview加载的地址,可以通过url分析出部分业务参数  
            //TODO 获取数据,存储为newData  
            var newData = {};  
            ...  
            //必需:重新设置data  
            this.setData(newData);  
        }  
    };  
</script>

动态计算NView数据,通常有三种场景:

  • 通过页面url地址,分析出所需业务参数,适合页面url和业务数据有明确对应关系的场景
  • 通过前页获取数据,比如列表页已经显示了商品的名称,则详情页可以直接复用列表页的商品名称数据
  • 通过ajax请求获取数据,这样可以在Document加载完成之前提前发起请求并渲染

如上三种方式可混合使用,每次调用setData()方法,都会覆盖之前的数据(merge覆盖,非完全替换),如下是示例:

<script>  
    module.exports = {  
        data: {  
            vendor:'DCloud',  
            author:'CHB',  
            product:{  
                name:'wap2app'  
            }  
        },  
        init: function(url) {  
            var newData = {  
                author:'FXY',  
                product:{  
                    description:'基于M站的强化方案'  
                }  
            };  
            //必需:重新设置data  
            this.setData(newData);  
        }  
    };  
</script>

如上代码运行后,最终的模板数据为:

{  
    vendor:'DCloud',//保留  
    author:'FXY',//替换  
    product:{  
        name:'wap2app',//保留  
        description:'基于M站的强化方案'//新增  
    }  
}

通过url分析业务数据

这种模式适合页面url和业务参数有明确对应关系的场景,比如页面地址为http://www.example.com/detail/%id%,该页面上图片轮播地址固定为:

http://www.example.com/images/%id%/1.png  
http://www.example.com/images/%id%/2.png  
http://www.example.com/images/%id%/3.png

我们可以通过分析页面url,解析出id参数,然后拼接轮播组件图片源地址,如下是一个示例代码:

<template>  
    <nviews cachemaxage="86400">  
        <nview id="nvew2" style="height:200px;">  
            <!--图片轮播-->  
            <imageslider images={data.imgList}></imageslider>  
        </nview>  
    </nviews>  
</template>  
<script>  
    module.exports = {  
        data: {  
            //默认数据  
        },  
        init: function(url) {  
            //页面url地址为http://www.example.com/detail/%id%  
            //分析页面id  
            var id = url.substring(url.lastIndexOf("/")+1)  
            var newData = {};  
            var list = new Array();  
            //循环,构建原生轮播图片源信息  
            for (var i = 1; i <= 3; i++) {  
                var item = {};  
                //图片源地址  
                item.src = "http://www.example.com/images/" + id + "/" + i +".png";  
                item.width = "100%";  
                list.push(item);  
            }  
            //设置轮播组件信息  
            newData.imgList = list;  
            //重新设置data  
            this.setData(newData);  
        }  
    };  
</script>

复用前页数据

下图是一个示例,从列表打开详情(列表页就是前页),详情页的部分数据和列表页相同(如商品图片、标题、价格等),此时就可以复用列表页的数据,提前渲染:

复用前页数据的思路:

  • 用户在前页点击时,将可复用信息存储到本地缓存中
  • 在新页面创建后,从本地缓存中读取数据并渲染到NView中

我们以列表打开详情页,详情页使用NView加速渲染为例,演示如何实现复用前页(列表页)数据。

前页存储本地缓存

用户点击时存储数据的代码,建议在M站编写,也可以在HBuilder客户端编写,然后通过appendJS的方式插入到原站。如下是一个示例代码:

假设前页列表HTML代码如下:

<!-- 列表开始 -->  
<div id="list">  
    <!-- 第一个列表项 -->  
    <div class="item">  
        <img src="http://www.example.com/img/1.png" alt="" />  
        <p class="title">Item 1</p>  
    </div>  
    <!-- 第二个列表项 -->  
    <div class="item">  
        <img src="http://www.example.com/img/2.png" alt="" />  
        <p class="title">Item 2</p>  
    </div>  
</div>  
<!-- 列表结束 -->

我们可以增加如下JS代码,当用户点击列表项时,将列表项数据缓存到plus.storage中,示例如下:

(function() {  
    //非5+引擎环境,退出  
    if(navigator.userAgent.indexOf("Html5Plus") == -1) {  
        return false;  
    }  

    //判断DOM是否加载完成,如果M站已封装了类似方法,可以直接使用,例如jQuery.ready()  
    var readyRE = /complete|loaded|interactive/;  
    if(readyRE.test(document.readyState)) {  
        domReady();  
    } else {  
        document.addEventListener('DOMContentLoaded', function() {  
            domReady();  
        }, false);  
    }  

    function domReady() {  
        var cacheId = "detail"; //缓存的ID,NView模板会通过该ID读取缓存数据  
        var container = document.querySelector("#list"); //列表容器,根据M站实现改造  
        var eventType = "click"; //点击事件,根据M站实现更改,比如tap  

        //容器添加点击事件监听  
        container && container.addEventListener(eventType, function(e) {  
            var target = e.target;  
            for(; target && target !== container; target = target.parentNode) {  
                if(target.classList && target.classList.contains("item")) { //列表项  
                    var data = {};  
                    //获取图片路径  
                    var imgElem = target.querySelector("img"); //获取当前列表项下图片对象  
                    if(imgElem) {  
                        data.imgPath = imgElem.getAttribute("src"); //获取图片资源路径  
                    }  
                    //获取标题  
                    var titleElem = target.querySelector(".title"); //获取当前列表项下的标题对象  
                    if(titleElem) {  
                        data.title = titleElem.innerHTML.trim(); //获取标题  
                    }  
                    //将当前数据存储到缓存中  
                    plus.storage.setItem(cacheId, JSON.stringify(data));  
                    return;  
                }  
            }  
        });  
    }  
})();

NView模板中读取缓存数据

NView模板封装了一个wap2app.getFromCache()方法,该方法有两个功能:

  • 从plus.storage中读取缓存数据并自动转成object对象
  • 读取缓存数据后,自动清除数据,防止下次打开同类页面时(本例为打开其它详情页),数据错乱

wap2app.getFromCache()使用方法如下:

wap2app.getFromCache(cacheId,function(data){  
    //data是plus.storage.getItem(cacheId)返回的数据,已自动转成object类型  
})

继续上如列表示例,详情页NView模板完整代码如下:

<template>  
    <nviews cachemaxage="86400">  
        <nview id="detailNview" style="height:225px;">  
            <canvas>  
                <!--缩略图-->  
                <img style="top: 0;width:100%;height:225px;" src={data.imgPath}/>  
                <!--标题-->  
                <font style="bottom: 10px;height: 20px;">{data.title}</font>  
            </canvas>  
        </nview>  
    </nviews>  
</template>  
<script>  
    module.exports = {  
        data:{//默认数据,可选  
            imgPath:'http://www.example.com/img/default.png',  
            title:''  
        },  
        init: function(url) {  
            var self = this;//this作用域在回调函数中会变化,复制给变量self  
            //从缓存中读取数据  
            //'detail'为前页存储数据时的key  
            wap2app.getFromCache('detail', function(data) {  
                if(data) {  
                    //读取缓存数据成功,更新数据,刷新NView  
                    self.setData(data);  
                }  
            });  
        }  
    };  
</script>

ajax获取服务端数据

NView模板也支持动态从服务端获取数据,wap2app封装了一个wap2app.getFromWebService()方法来实现AJAX请求,如下为示例代码:

<script>  
    module.exports = {  
        init: function(url) {  
            var self = this;//this作用域在回调函数中会变化,复制给变量self  
            //动态初始化数据  
            wap2app.getFromWebService({  
                url: 'your-server-url',  
                data: {},  
                type: 'post'  
            }, function(data) {  
                //TODO 如果服务端返回数据格式和模板需要的格式不同,则需要做一下转换  
                self.setData(data);  
            })  
        }  
    };  
</script>
继续阅读 »

除了标准字符串模式的文本、属性设置外,NView模板支持将NView实例数据绑定至NView控件上。

插值

NView模板的文本、属性插值方式相同,均使用大括号({})表示当前为Javascript表达式,不是直接字符串赋值,如下为一个简单示例:

<template>  
    <nviews cacheMaxAge="86400">  
        <nview id="nview1" style="position:static;top:200px;height:50px;">  
            <Font>{data.product_name}</Font>  
        </nview>  
    </nviews>  
</template>  
<script>  
    module.exports = {  
        data: {  
            product_name:'产品名称'  
        }  
    };  
</script>

NView模板中的Javascript表达式,要求必须是单个表达式或JSON对象,如下都是合法的:

<nview id="nview1" style={{  
    //这里是json对象  
    position:"static",  
    top:data.top  
}}>  
    <Font>{data.rem * 17}</Font>  
    <img id="img1" style={{  
            //三元表达式  
            width:data.full?"100%":"80%"  
        }}>  
</nview>

备注:两个大括号{{}}的含义,外层大括号{}表示接下来为Javascript运算符,内层大括号{}表示当前为一个JSON对象。

下面的例子则不生效,因为他们是语句,而不是表达式

<font>{data.rem = 10}</font>

数据源

NView模板可以绑定JavaScript动态计算的数据,数据的提供主要有两种方式:

  • 直接通过data属性提供默认值,这种方式适用于数据相对固定,跟具体业务无关的场景,比如设置界面、开发商等
  • 在init属性中,编写JavaScript代码,根据业务场景动态计算(请求)数据

data属性

默认数据可直接在data属性中提供,data支持Object、Function两种方式,例如:

<script>  
    module.exports = {  
        data: {  
            vendor:'DCloud',  
            city:'北京'  
        }  
    };  
</script>

下面是Function示例,返回值要求是Object类型;Function适合需要简单计算的场景,比如根据屏幕分辨率动态计算文字大小、宽高等场景:

<script>  
    module.exports = {  
        data: function() {  
            return {  
                fontSize:window.screen.width > 360 ? "17px" : "15px",//动态计算  
                vendor:'DCloud'  
            }  
        }  
    };  
</script>

init属性

跟业务相关的数据,可以在init中通过JavaScript编程实现,使用方式如下:

<script>  
    module.exports = {  
        data: {  
            //默认数据  
        },  
        init: function(url) {  
            //url为新开webview加载的地址,可以通过url分析出部分业务参数  
            //TODO 获取数据,存储为newData  
            var newData = {};  
            ...  
            //必需:重新设置data  
            this.setData(newData);  
        }  
    };  
</script>

动态计算NView数据,通常有三种场景:

  • 通过页面url地址,分析出所需业务参数,适合页面url和业务数据有明确对应关系的场景
  • 通过前页获取数据,比如列表页已经显示了商品的名称,则详情页可以直接复用列表页的商品名称数据
  • 通过ajax请求获取数据,这样可以在Document加载完成之前提前发起请求并渲染

如上三种方式可混合使用,每次调用setData()方法,都会覆盖之前的数据(merge覆盖,非完全替换),如下是示例:

<script>  
    module.exports = {  
        data: {  
            vendor:'DCloud',  
            author:'CHB',  
            product:{  
                name:'wap2app'  
            }  
        },  
        init: function(url) {  
            var newData = {  
                author:'FXY',  
                product:{  
                    description:'基于M站的强化方案'  
                }  
            };  
            //必需:重新设置data  
            this.setData(newData);  
        }  
    };  
</script>

如上代码运行后,最终的模板数据为:

{  
    vendor:'DCloud',//保留  
    author:'FXY',//替换  
    product:{  
        name:'wap2app',//保留  
        description:'基于M站的强化方案'//新增  
    }  
}

通过url分析业务数据

这种模式适合页面url和业务参数有明确对应关系的场景,比如页面地址为http://www.example.com/detail/%id%,该页面上图片轮播地址固定为:

http://www.example.com/images/%id%/1.png  
http://www.example.com/images/%id%/2.png  
http://www.example.com/images/%id%/3.png

我们可以通过分析页面url,解析出id参数,然后拼接轮播组件图片源地址,如下是一个示例代码:

<template>  
    <nviews cachemaxage="86400">  
        <nview id="nvew2" style="height:200px;">  
            <!--图片轮播-->  
            <imageslider images={data.imgList}></imageslider>  
        </nview>  
    </nviews>  
</template>  
<script>  
    module.exports = {  
        data: {  
            //默认数据  
        },  
        init: function(url) {  
            //页面url地址为http://www.example.com/detail/%id%  
            //分析页面id  
            var id = url.substring(url.lastIndexOf("/")+1)  
            var newData = {};  
            var list = new Array();  
            //循环,构建原生轮播图片源信息  
            for (var i = 1; i <= 3; i++) {  
                var item = {};  
                //图片源地址  
                item.src = "http://www.example.com/images/" + id + "/" + i +".png";  
                item.width = "100%";  
                list.push(item);  
            }  
            //设置轮播组件信息  
            newData.imgList = list;  
            //重新设置data  
            this.setData(newData);  
        }  
    };  
</script>

复用前页数据

下图是一个示例,从列表打开详情(列表页就是前页),详情页的部分数据和列表页相同(如商品图片、标题、价格等),此时就可以复用列表页的数据,提前渲染:

复用前页数据的思路:

  • 用户在前页点击时,将可复用信息存储到本地缓存中
  • 在新页面创建后,从本地缓存中读取数据并渲染到NView中

我们以列表打开详情页,详情页使用NView加速渲染为例,演示如何实现复用前页(列表页)数据。

前页存储本地缓存

用户点击时存储数据的代码,建议在M站编写,也可以在HBuilder客户端编写,然后通过appendJS的方式插入到原站。如下是一个示例代码:

假设前页列表HTML代码如下:

<!-- 列表开始 -->  
<div id="list">  
    <!-- 第一个列表项 -->  
    <div class="item">  
        <img src="http://www.example.com/img/1.png" alt="" />  
        <p class="title">Item 1</p>  
    </div>  
    <!-- 第二个列表项 -->  
    <div class="item">  
        <img src="http://www.example.com/img/2.png" alt="" />  
        <p class="title">Item 2</p>  
    </div>  
</div>  
<!-- 列表结束 -->

我们可以增加如下JS代码,当用户点击列表项时,将列表项数据缓存到plus.storage中,示例如下:

(function() {  
    //非5+引擎环境,退出  
    if(navigator.userAgent.indexOf("Html5Plus") == -1) {  
        return false;  
    }  

    //判断DOM是否加载完成,如果M站已封装了类似方法,可以直接使用,例如jQuery.ready()  
    var readyRE = /complete|loaded|interactive/;  
    if(readyRE.test(document.readyState)) {  
        domReady();  
    } else {  
        document.addEventListener('DOMContentLoaded', function() {  
            domReady();  
        }, false);  
    }  

    function domReady() {  
        var cacheId = "detail"; //缓存的ID,NView模板会通过该ID读取缓存数据  
        var container = document.querySelector("#list"); //列表容器,根据M站实现改造  
        var eventType = "click"; //点击事件,根据M站实现更改,比如tap  

        //容器添加点击事件监听  
        container && container.addEventListener(eventType, function(e) {  
            var target = e.target;  
            for(; target && target !== container; target = target.parentNode) {  
                if(target.classList && target.classList.contains("item")) { //列表项  
                    var data = {};  
                    //获取图片路径  
                    var imgElem = target.querySelector("img"); //获取当前列表项下图片对象  
                    if(imgElem) {  
                        data.imgPath = imgElem.getAttribute("src"); //获取图片资源路径  
                    }  
                    //获取标题  
                    var titleElem = target.querySelector(".title"); //获取当前列表项下的标题对象  
                    if(titleElem) {  
                        data.title = titleElem.innerHTML.trim(); //获取标题  
                    }  
                    //将当前数据存储到缓存中  
                    plus.storage.setItem(cacheId, JSON.stringify(data));  
                    return;  
                }  
            }  
        });  
    }  
})();

NView模板中读取缓存数据

NView模板封装了一个wap2app.getFromCache()方法,该方法有两个功能:

  • 从plus.storage中读取缓存数据并自动转成object对象
  • 读取缓存数据后,自动清除数据,防止下次打开同类页面时(本例为打开其它详情页),数据错乱

wap2app.getFromCache()使用方法如下:

wap2app.getFromCache(cacheId,function(data){  
    //data是plus.storage.getItem(cacheId)返回的数据,已自动转成object类型  
})

继续上如列表示例,详情页NView模板完整代码如下:

<template>  
    <nviews cachemaxage="86400">  
        <nview id="detailNview" style="height:225px;">  
            <canvas>  
                <!--缩略图-->  
                <img style="top: 0;width:100%;height:225px;" src={data.imgPath}/>  
                <!--标题-->  
                <font style="bottom: 10px;height: 20px;">{data.title}</font>  
            </canvas>  
        </nview>  
    </nviews>  
</template>  
<script>  
    module.exports = {  
        data:{//默认数据,可选  
            imgPath:'http://www.example.com/img/default.png',  
            title:''  
        },  
        init: function(url) {  
            var self = this;//this作用域在回调函数中会变化,复制给变量self  
            //从缓存中读取数据  
            //'detail'为前页存储数据时的key  
            wap2app.getFromCache('detail', function(data) {  
                if(data) {  
                    //读取缓存数据成功,更新数据,刷新NView  
                    self.setData(data);  
                }  
            });  
        }  
    };  
</script>

ajax获取服务端数据

NView模板也支持动态从服务端获取数据,wap2app封装了一个wap2app.getFromWebService()方法来实现AJAX请求,如下为示例代码:

<script>  
    module.exports = {  
        init: function(url) {  
            var self = this;//this作用域在回调函数中会变化,复制给变量self  
            //动态初始化数据  
            wap2app.getFromWebService({  
                url: 'your-server-url',  
                data: {},  
                type: 'post'  
            }, function(data) {  
                //TODO 如果服务端返回数据格式和模板需要的格式不同,则需要做一下转换  
                self.setData(data);  
            })  
        }  
    };  
</script>
收起阅读 »

模板标签 - NView模板 - wap2app教程

wap2app NView模板

在NView模板中,仅允许使用有限的标签(可以认为是HTML的子集),标签嵌套顺序及支持的属性,均有较为严格的限制。一个NView模板文件,固定结构如下:

<template>  
    <nviews cachemaxage="86400">  
        <!--nview控件-->  
    </nviews>  
</template>  
<script>  
    module.exports = {  
        //通过JS处理数据  
    };  
</script>   

template/nviews/script这些是表示特定结构的标签,并不生成UI元素;另外还有一些标签,如font/button等,则会生成相应的UI元素。

大多数标签都是可以通过属性设置的元素的样式,比如位置、边框等。我们讲大多数模板标签均具备的属性,称为标签通用属性,主要包括id/onclick/style三个属性,详细说明参考这里。本文在介绍模板标签时,除非该标签有特殊限制,否则不会介绍通用属性。

<a>

a标签在原生view上绘制一个超链接(底部带下划线的文本),目前<a>标签仅支持在<richtext>容器下使用。

属性

<a>位于流式布局容器richtext标签下时,支持id、style属性,不支持onclick属性;style中可以定义font样式,详细参考模板样式;不支持align、background、position样式。

richtext容器下的a标签,还支持href属性,但点击不会触发页面跳转。若需处理a标签的跳转,则需监听richtext容器的onclick事件,通过点击回调中获取点击目标对象的href属性,然后通过JS API实现窗口跳转。

子标签

<a>标签下不支持嵌套子标签。

<br>

br标签用于插入一个简单的换行符,类似于HTML5中的br标签,目前仅可以在richtext容器下使用。

br标签不支持任何属性及子标签。

<button>

<button>用于在原生View上绘制按钮,button标签内部仅支持放置文字,按钮文字上下、左右居中显示。

属性

<button>处于canvas和richtext容器下时,支持属性不同。

canvas

button位于绝对布局容器canvas标签下时,支持id、onclick、style通用属性;style中可以定义background、border、font、position样式,详细参考模板样式

richtext

暂不支持、即将支持。

子标签

button标签下不支持嵌套子标签。

<canvas>

<canvas>表示绝对布局容器,默认和父容器nview具备相同的宽高,子节点全部为绝对定位,关于绝对布局参考模板布局.

属性

canvas支持id、onclick、style通用属性,style属性中支持background、position样式定义,详细参考模板样式

子标签

canvas标签下允许使用a、button、font、img、input、hr标签;

<font>

<font>用于在原生View上绘制文本,

属性

font处于canvas和richtext容器下时,支持属性不同。

canvas

font位于绝对布局容器canvas标签下时,支持id、onclick、style通用属性;style中可以定义align、background、font、position样式,详细参考模板样式

richtext

font位于流式布局容器richtext标签下时,支持id、style属性,不支持onclick属性;style中可以定义align、font样式,详细参考模板样式;不支持background、position样式。

子标签

font标签下不支持嵌套子标签。

<hr>

hr标签在原生view上创建一条水平分割线,从而可以将展示内容分割成各个部分。

属性

hr标签支持id、style通用属性,不支持onclick属性;

hr标签的style属性可以定义align(水平对齐)、border、position中的宽高(width/height),width支持绝对像素值和百分比,百分比是根据父容器宽度自动计算。

另外,hr处于canvas容器下时,还支持position中的left/top等坐标位置设置;处于richtext容器下是流式布局,不支持left/top等坐标设置。

子标签

hr标签下不支持嵌套子标签。

<imageslider>

imageslider是原生渲染的图片轮播组件,不允许嵌套子标签。imageslider支持id、style通用属性,style属性中可以设置background、position样式,具体参考NView模板样式;另外,imageslider还支持images、loop、fullscreen属性,详细说明如下。

images

配置轮播组件的图片信息,具体信息包括:

  • src: 图片地址,支持本地地址(相对地址、绝对路径、RelativeURL、本地路径URL); 也支持网络地址(http://或https://);
  • align: 图片水平对齐方式,仅在图片显示的宽度与图片轮播控件宽度不一致时有效,可取值: "left" - 图片在轮播控件中水平居左对齐; "center" - 图片在轮播控件中水平居中对齐; "right" - 图片在轮播控件中水平居右对齐。 默认值为"center"。
  • height: 图片显示的高度,可取值: 像素值,如"100px"; 百分比,如"10%",现对于图片轮播控件的高度; 自动计算"auto",如果指定图片宽度(width),则按图片实际大小等比缩放图片高度值,如果没有指定宽度(width值为"auto")则自动缩放图片至可完整显示。
  • width: 图片显示的宽度,可取值: 像素值,如"100px"; 百分比,如"10%",相对于图片轮播控件的宽度; 自动计算"auto",如果指定图片高度(height),则按图片实际大小等比缩放图片宽度值,如果没有指定高度(height值为"auto")则自动缩放图片至可完整显示。 默认值为"auto"。
  • verticalAlign: 图片垂直对齐方式,仅在图片显示的高度与图片轮播控件宽度不一致时有效,可取值: "top" - 图片在轮播控件中垂直居顶对齐; "middle" - 图片在轮播控件中垂直居中对齐; "bottom" - 图片在轮播控件中垂直居底对齐。 默认值为"middle"。

因为配置信息较为复杂,这里需要使用NView模板的插值方式赋值,如下是一个示例:

<imageslider id="slider" style="height:100px;"  
    images={[  
        {src:"http://www.example.com/images/1.jpg",width:"100%",height:"100%"},  
        {src:"http://www.example.com/images/2.jpg",width:"100%",height:"100%"}  
    ]}>  
</imageslider>

如上images属性值中,外层{}表示当前为JavaScript表达式,内部的[]表示当前为一个Array数组,数组中的每个元素是{}包裹的json对象;

loop

设置轮播图片是否可循环播放,可取值:

  • true - 支持循环轮播;
  • false - 不支持循环轮播

默认值为false。

fullscreen

用户点击轮播图片时,是否全屏显示图片,可取值:

  • true - 全屏显示,用户点击轮播图片时全屏显示;
  • false - 不可全屏显示,用户点击轮播图片时无响应。

默认值为true。

子标签

imageslider不支持嵌套子标签。

<img>

<img>用于在原生View上绘制图片。

属性

除了通用标签属性,img还支持src属性,用于设置图片资源路径。

img处于canvas和richtext容器下时,支持的通用属性不同。

canvas

img位于绝对布局容器canvas标签下时,支持id、onclick、style通用属性;style中可以定义position样式,详细参考模板样式

richtext

img位于流式布局容器richtext标签下时,支持id、style属性,不支持onclick属性;style中仅支持position样式中的width、height属性,不支持left、top等坐标样式,详细参考模板样式

子标签

img标签下不支持嵌套子标签。

<input>

<input>标签可以在原生View上绘制输入框,输入文本内容在指定区域水平向左、垂直居中显示。

目前input标签仅支持在canvas容器下使用,richtext容器下无法使用。

属性

input标签支持id、style通用属性,style属性中支持设置font中的font-size样式、border边框样式;input标签不支持onclick属性;另外,input标签还支持type、placeholder、oncomplete属性。

type

type属性设置输入框类型,可取值:

  • email - 邮箱地址输入框;
  • number - 数字输入框;
  • search - 搜索文本输入框;
  • tel - 电话号码输入框;
  • text - 普通文本输入框;
  • url - URL地址输入框。

placeholder

设置输入框的提示文本,当用户未输入内容时显示在编辑框中(灰色文字)。

oncomplete

弹出软键盘完成输入后,点击软键盘上的“完成”、“前往”按钮时触发,如下为示例:

<template>  
    <nviews cacheMaxAge="86400">  
        <nview id="nview_canvas" style="height:150px;background-color: #efeff4;">  
            <canvas>  
                <input id="tel" type="tel" placeholder="输入手机号码" style="left:15px;top:15px;height:30px;right:15px;border-color:#007aff" oncomplete={this.handleInput}/>  
            </canvas>  
        </nview>  
    </nviews>  
</template>  
<script>  
    module.exports = {  
        methods: {  
            //inpu输入完成的回调  
            handleInput:function(){  
                plus.nativeUI.toast("input complete");  
            }  
        }  
    };  
</script>

子标签

input标签下不支持嵌套子标签。

<item>

item表示list组件下的列表项,参考NView模板绘制原生列表教程

<list>

list是NView模板封装的列表组件,参考NView模板绘制原生列表教程

<nviews>

nviews位于template节点下,一个NView模板文件有且仅有一个nviews节点;

属性

nviews仅支持cachemaxage一个属性。

cachemaxage

subNView缓存时间,单位为秒,默认为1天(86400秒);wap2app会将subNView的计算结果缓存起来,在缓存期内再次打开同一页面时,将直接使用缓存数据渲染subNView,而不会再次发起网络请求。

子节点

nviews节点下只允许嵌套使用nview一种标签,数量不限。

<nview>

nview表示一个布局容器,类似于HTML5中的div标签,但不支持nview标签的互相嵌套。

属性

nview支持id、onclick、style通用属性,style属性中支持background、position样式,详细参考模板样式

另外,nview标签还支持intercept、autoclose属性,详细定义参考下文描述。

intercept

nview事件拦截配置,详细参考事件监听 - NView模板文章中的事件拦截章节。

autoclose

nview是否自动关闭,默认为false,即不关闭;开发者可以通过配置autoclose="loaded"实现下层webview加载完毕后,自动关闭上层的nview控件。

Tips:subNView作为webview的子控件,在webview上层使用原生技术,提前渲染,在窗口动画期间就完成主要内容的渲染工作;若下层webview加载的HTML页面完全渲染结束,则subNView的主要工作已完成,是否继续存在则可以根据具体场景而定。

若subNView上部分元素需要响应用户的点击操作,则通常有三种方法:

  • 配置相应元素的onclick属性,编写对应的触发函数
  • 设置nview的intercept属性为false,将触屏事件透传给下层的webview,由dom元素响应事件,此种方案可能出现半屏遮罩的问题(webview的全屏div遮罩,但无法遮住上层的subNView控件)。
  • 配置nview的autoclose属性,在webview加载完毕后自动关闭subNView,则用户触屏时就直接触发dom元素的响应事件

子节点

<nview>节点下允许使用<imageslider>、<list>、<canvas>、<richtext>4个标签。

<richtext>

<richtext>表示流式布局容器,默认和父容器nview具备相同的宽高,子节点全部为流式布局。关于流式布局参考模板布局.

属性

richtext支持id、onclick、style通用属性,style属性中支持background、position样式定义,详细参考模板样式

//TODO richtext点击事件描述

子标签

richtext标签下允许使用font、img、a、br、hr标签;

<script>

script节点下可以进行数据计算,一个模板文件仅允许出现一个script节点,默认代码如下:

     <script>  
        module.exports = {  
            data: {  
                //默认数据  
            },  
            init: function(url) {  
                //动态初始化数据  
            },  
            methods: {  
                //方法  
            }  
        };  
    </script>

script标签不支持设置任何属性,也不允许嵌套子标签。

<template>

模板标签根节点,一个NView模板文件有且仅有一个template节点,不支持设置属性;

template节点下仅允许嵌套nviews标签,且仅允许嵌套一个nviews标签。

继续阅读 »

在NView模板中,仅允许使用有限的标签(可以认为是HTML的子集),标签嵌套顺序及支持的属性,均有较为严格的限制。一个NView模板文件,固定结构如下:

<template>  
    <nviews cachemaxage="86400">  
        <!--nview控件-->  
    </nviews>  
</template>  
<script>  
    module.exports = {  
        //通过JS处理数据  
    };  
</script>   

template/nviews/script这些是表示特定结构的标签,并不生成UI元素;另外还有一些标签,如font/button等,则会生成相应的UI元素。

大多数标签都是可以通过属性设置的元素的样式,比如位置、边框等。我们讲大多数模板标签均具备的属性,称为标签通用属性,主要包括id/onclick/style三个属性,详细说明参考这里。本文在介绍模板标签时,除非该标签有特殊限制,否则不会介绍通用属性。

<a>

a标签在原生view上绘制一个超链接(底部带下划线的文本),目前<a>标签仅支持在<richtext>容器下使用。

属性

<a>位于流式布局容器richtext标签下时,支持id、style属性,不支持onclick属性;style中可以定义font样式,详细参考模板样式;不支持align、background、position样式。

richtext容器下的a标签,还支持href属性,但点击不会触发页面跳转。若需处理a标签的跳转,则需监听richtext容器的onclick事件,通过点击回调中获取点击目标对象的href属性,然后通过JS API实现窗口跳转。

子标签

<a>标签下不支持嵌套子标签。

<br>

br标签用于插入一个简单的换行符,类似于HTML5中的br标签,目前仅可以在richtext容器下使用。

br标签不支持任何属性及子标签。

<button>

<button>用于在原生View上绘制按钮,button标签内部仅支持放置文字,按钮文字上下、左右居中显示。

属性

<button>处于canvas和richtext容器下时,支持属性不同。

canvas

button位于绝对布局容器canvas标签下时,支持id、onclick、style通用属性;style中可以定义background、border、font、position样式,详细参考模板样式

richtext

暂不支持、即将支持。

子标签

button标签下不支持嵌套子标签。

<canvas>

<canvas>表示绝对布局容器,默认和父容器nview具备相同的宽高,子节点全部为绝对定位,关于绝对布局参考模板布局.

属性

canvas支持id、onclick、style通用属性,style属性中支持background、position样式定义,详细参考模板样式

子标签

canvas标签下允许使用a、button、font、img、input、hr标签;

<font>

<font>用于在原生View上绘制文本,

属性

font处于canvas和richtext容器下时,支持属性不同。

canvas

font位于绝对布局容器canvas标签下时,支持id、onclick、style通用属性;style中可以定义align、background、font、position样式,详细参考模板样式

richtext

font位于流式布局容器richtext标签下时,支持id、style属性,不支持onclick属性;style中可以定义align、font样式,详细参考模板样式;不支持background、position样式。

子标签

font标签下不支持嵌套子标签。

<hr>

hr标签在原生view上创建一条水平分割线,从而可以将展示内容分割成各个部分。

属性

hr标签支持id、style通用属性,不支持onclick属性;

hr标签的style属性可以定义align(水平对齐)、border、position中的宽高(width/height),width支持绝对像素值和百分比,百分比是根据父容器宽度自动计算。

另外,hr处于canvas容器下时,还支持position中的left/top等坐标位置设置;处于richtext容器下是流式布局,不支持left/top等坐标设置。

子标签

hr标签下不支持嵌套子标签。

<imageslider>

imageslider是原生渲染的图片轮播组件,不允许嵌套子标签。imageslider支持id、style通用属性,style属性中可以设置background、position样式,具体参考NView模板样式;另外,imageslider还支持images、loop、fullscreen属性,详细说明如下。

images

配置轮播组件的图片信息,具体信息包括:

  • src: 图片地址,支持本地地址(相对地址、绝对路径、RelativeURL、本地路径URL); 也支持网络地址(http://或https://);
  • align: 图片水平对齐方式,仅在图片显示的宽度与图片轮播控件宽度不一致时有效,可取值: "left" - 图片在轮播控件中水平居左对齐; "center" - 图片在轮播控件中水平居中对齐; "right" - 图片在轮播控件中水平居右对齐。 默认值为"center"。
  • height: 图片显示的高度,可取值: 像素值,如"100px"; 百分比,如"10%",现对于图片轮播控件的高度; 自动计算"auto",如果指定图片宽度(width),则按图片实际大小等比缩放图片高度值,如果没有指定宽度(width值为"auto")则自动缩放图片至可完整显示。
  • width: 图片显示的宽度,可取值: 像素值,如"100px"; 百分比,如"10%",相对于图片轮播控件的宽度; 自动计算"auto",如果指定图片高度(height),则按图片实际大小等比缩放图片宽度值,如果没有指定高度(height值为"auto")则自动缩放图片至可完整显示。 默认值为"auto"。
  • verticalAlign: 图片垂直对齐方式,仅在图片显示的高度与图片轮播控件宽度不一致时有效,可取值: "top" - 图片在轮播控件中垂直居顶对齐; "middle" - 图片在轮播控件中垂直居中对齐; "bottom" - 图片在轮播控件中垂直居底对齐。 默认值为"middle"。

因为配置信息较为复杂,这里需要使用NView模板的插值方式赋值,如下是一个示例:

<imageslider id="slider" style="height:100px;"  
    images={[  
        {src:"http://www.example.com/images/1.jpg",width:"100%",height:"100%"},  
        {src:"http://www.example.com/images/2.jpg",width:"100%",height:"100%"}  
    ]}>  
</imageslider>

如上images属性值中,外层{}表示当前为JavaScript表达式,内部的[]表示当前为一个Array数组,数组中的每个元素是{}包裹的json对象;

loop

设置轮播图片是否可循环播放,可取值:

  • true - 支持循环轮播;
  • false - 不支持循环轮播

默认值为false。

fullscreen

用户点击轮播图片时,是否全屏显示图片,可取值:

  • true - 全屏显示,用户点击轮播图片时全屏显示;
  • false - 不可全屏显示,用户点击轮播图片时无响应。

默认值为true。

子标签

imageslider不支持嵌套子标签。

<img>

<img>用于在原生View上绘制图片。

属性

除了通用标签属性,img还支持src属性,用于设置图片资源路径。

img处于canvas和richtext容器下时,支持的通用属性不同。

canvas

img位于绝对布局容器canvas标签下时,支持id、onclick、style通用属性;style中可以定义position样式,详细参考模板样式

richtext

img位于流式布局容器richtext标签下时,支持id、style属性,不支持onclick属性;style中仅支持position样式中的width、height属性,不支持left、top等坐标样式,详细参考模板样式

子标签

img标签下不支持嵌套子标签。

<input>

<input>标签可以在原生View上绘制输入框,输入文本内容在指定区域水平向左、垂直居中显示。

目前input标签仅支持在canvas容器下使用,richtext容器下无法使用。

属性

input标签支持id、style通用属性,style属性中支持设置font中的font-size样式、border边框样式;input标签不支持onclick属性;另外,input标签还支持type、placeholder、oncomplete属性。

type

type属性设置输入框类型,可取值:

  • email - 邮箱地址输入框;
  • number - 数字输入框;
  • search - 搜索文本输入框;
  • tel - 电话号码输入框;
  • text - 普通文本输入框;
  • url - URL地址输入框。

placeholder

设置输入框的提示文本,当用户未输入内容时显示在编辑框中(灰色文字)。

oncomplete

弹出软键盘完成输入后,点击软键盘上的“完成”、“前往”按钮时触发,如下为示例:

<template>  
    <nviews cacheMaxAge="86400">  
        <nview id="nview_canvas" style="height:150px;background-color: #efeff4;">  
            <canvas>  
                <input id="tel" type="tel" placeholder="输入手机号码" style="left:15px;top:15px;height:30px;right:15px;border-color:#007aff" oncomplete={this.handleInput}/>  
            </canvas>  
        </nview>  
    </nviews>  
</template>  
<script>  
    module.exports = {  
        methods: {  
            //inpu输入完成的回调  
            handleInput:function(){  
                plus.nativeUI.toast("input complete");  
            }  
        }  
    };  
</script>

子标签

input标签下不支持嵌套子标签。

<item>

item表示list组件下的列表项,参考NView模板绘制原生列表教程

<list>

list是NView模板封装的列表组件,参考NView模板绘制原生列表教程

<nviews>

nviews位于template节点下,一个NView模板文件有且仅有一个nviews节点;

属性

nviews仅支持cachemaxage一个属性。

cachemaxage

subNView缓存时间,单位为秒,默认为1天(86400秒);wap2app会将subNView的计算结果缓存起来,在缓存期内再次打开同一页面时,将直接使用缓存数据渲染subNView,而不会再次发起网络请求。

子节点

nviews节点下只允许嵌套使用nview一种标签,数量不限。

<nview>

nview表示一个布局容器,类似于HTML5中的div标签,但不支持nview标签的互相嵌套。

属性

nview支持id、onclick、style通用属性,style属性中支持background、position样式,详细参考模板样式

另外,nview标签还支持intercept、autoclose属性,详细定义参考下文描述。

intercept

nview事件拦截配置,详细参考事件监听 - NView模板文章中的事件拦截章节。

autoclose

nview是否自动关闭,默认为false,即不关闭;开发者可以通过配置autoclose="loaded"实现下层webview加载完毕后,自动关闭上层的nview控件。

Tips:subNView作为webview的子控件,在webview上层使用原生技术,提前渲染,在窗口动画期间就完成主要内容的渲染工作;若下层webview加载的HTML页面完全渲染结束,则subNView的主要工作已完成,是否继续存在则可以根据具体场景而定。

若subNView上部分元素需要响应用户的点击操作,则通常有三种方法:

  • 配置相应元素的onclick属性,编写对应的触发函数
  • 设置nview的intercept属性为false,将触屏事件透传给下层的webview,由dom元素响应事件,此种方案可能出现半屏遮罩的问题(webview的全屏div遮罩,但无法遮住上层的subNView控件)。
  • 配置nview的autoclose属性,在webview加载完毕后自动关闭subNView,则用户触屏时就直接触发dom元素的响应事件

子节点

<nview>节点下允许使用<imageslider>、<list>、<canvas>、<richtext>4个标签。

<richtext>

<richtext>表示流式布局容器,默认和父容器nview具备相同的宽高,子节点全部为流式布局。关于流式布局参考模板布局.

属性

richtext支持id、onclick、style通用属性,style属性中支持background、position样式定义,详细参考模板样式

//TODO richtext点击事件描述

子标签

richtext标签下允许使用font、img、a、br、hr标签;

<script>

script节点下可以进行数据计算,一个模板文件仅允许出现一个script节点,默认代码如下:

     <script>  
        module.exports = {  
            data: {  
                //默认数据  
            },  
            init: function(url) {  
                //动态初始化数据  
            },  
            methods: {  
                //方法  
            }  
        };  
    </script>

script标签不支持设置任何属性,也不允许嵌套子标签。

<template>

模板标签根节点,一个NView模板文件有且仅有一个template节点,不支持设置属性;

template节点下仅允许嵌套nviews标签,且仅允许嵌套一个nviews标签。

收起阅读 »

NView模板概述 - wap2app教程

wap2app NView模板

什么是subNView

subNView,字面拆开理解就是sub native view,有两个核心点:

  • native:subNView是一种原生绘制的View,和HTML5的DOM无关
  • sub:subNView属于webview的一部分,并不替代完整Webview。和所属webview保持同样的生命周期,跟随webview的close、hide、zindex变化而变化。

subNView作为webview的子控件,一个webview可以包含多个subNView,一个subNView上可以绘制多个图片(包括图片轮播)、文字、区域、按钮等。

subNView希望解决什么问题

web页面加载渲染速度相比原生App,有较大的体验差距,以至于在移动设备上严重影响业务体验。这些体验差距是如何造成的呢?原因大致有如下几个:

  • 渲染时机:web app需要等待服务端Document下载完成后才可启动渲染工作,无法分区域渲染;而原生App作为C/S结构的应用,仅向服务端请求业务数据,其它布局、样式大多在本地,故可以在用户触发打开新窗口时,立即渲染新窗口部分区域布局,服务端响应数据后,再更新对应区域的内容;
  • 图片资源请求时机:web app需要先下载Document,然后再根据Document中的<img>标签的src属性去异步加载图片资源,故在web app中总是先看到文字,然后再逐渐看到图片;而原生App则无需任务等待,可以直接加载图片资源,故原生App的图片显示会早于web app中的图片显示;
  • 业务数据请求时机:web app的实现若是前后端分离,则需要先下载封装业务逻辑的js文件,下载完毕后,再由js发起ajax请求;而原生App,则大多将业务逻辑封装在本地,无需等待下载js文件,可以更早的发起HTTP业务请求

如何提升web页面的渲染速度,很多公司都在尝试,比如Google主导的AMP技术,AMP技术以阅读类网页加速为主,适用范围有限。

而subNView,则是一种更为通用、可增强任意web页面渲染体验的技术;subNView在保留HTML5优势的基础上,在webview中增加了一个原生view子控件,利用原生View发挥原生渲染优势;当用户触发时,webview按照原有逻辑,继续加载Document,渲染页面;但无需等待Document加载完成,可同时在原生View上完成如下工作:

  • 绘制固定内容区域,或可从前页获取数据的区域,例如固定地址图片、购物车按钮等,而无需等待Document下载完毕后再去请求加载图片
  • 直接发起业务数据ajax请求,ajax响应后直接在原生View上绘制数据,无需等待业务封装的JS下载

如下为一个使用subNView增强后的商品详情页示例:

从上图可看出:

  • webview按照原有逻辑,加载Document,渲染页面,刚开始内容未加载时还是白屏(中间空白区域)
  • webview同时创建了2个subNView作为webview的子控件
  • subNView 1展示商品详情轮播图及商品价格,是通过ajax动态获取的;轮播图片支持滑动、点击放大预览,用户可提前查看商品详情
  • subNView 2展示购物车相关功能,属于固定显示内容,可直接渲染
  • 购物车按钮点击后事件透传给Webview里的购物车按钮,HTML页面的所有逻辑,仍然复用。subNView只是简单的侵入动画渲染过程,不引发业务逻辑的重新编写。

如何使用subNView

开发者可以通过webview的subNViews属性创建或修改subNview控件,这里需要传入复杂的json对象;为简化开发,DCloud提供了NView模板技术。

NView模板

NView模板类似于vue的single-file components(单文件组件),HBuilder中新建NView模板文件,默认代码如下:

<template>  
    <nviews cachemaxage="86400">  

    </nviews>  
</template>  
<script>  
    module.exports = {  
        data: {  
            //默认数据  
        },  
        init: function(url) {  
            //动态初始化数据  
        },  
        methods: {  
            //方法  
        }  
    };  
</script>

需要注意的是,在<template>节点下仅可以使用受限制的NView HTML,详细参考后续章节介绍

FAQ

Q: 既然有了nview机制,为何不使用nview完成所有业务,而是作为HTML5的补充?
A:
其实这就是subNView前缀是sub的原因之一。
DCloud认为HTML5虽然有功能和性能问题,但面对问题进行强化即可,无需推翻HTML5重新来一套。
在HTML5生态中,有太多精彩的、现成的东西,开发者想要复用之前的HTML5,自然也应该使用subNView强化。
而完全使用nview将导致重写所有业务逻辑,后续也要维护多套版本。
总结一下:subNView的定位就是解决HTML5页面渲染慢的问题,做些简单的界面显示工作,在动画期间就给用户显示部分内容。而完整的业务逻辑处理,仍然在HTML页面里处理。

Q: 为何在wap2app里能使用nview模板,而5+app里不能使用?
A:
首先nview在5+里是一直存在的,wap2app是基于5+的上层框架,没有脱离5+范畴。参考plus.nativeObj.nview的api。
但通过5+的js api写titleNView很简单,但写复杂的subnview,开发体验不太好,于是我们在wap2app里对subnview引入了nview模板式写法,提升开发体验。
所以其实5+app也可以使用nview,只是暂时不能通过模板式写法来写,要写js api。
5+里引入nview模板写法,我们后续会补充,但这个工作优先级不高。
开发者可能误以为5+里也应该大量使用subNView提升体验,但其实不需要。
但nview在5+app里最常用的是title和tab,中间使用subnview的场景很少。
为啥5+app不太需要使用subnview呢?
因为如果你的代码写的不烂,本地的HTML页面加载是非常快的,在新窗体载入时,只是联网取ajax数据,和cs的原生应用一致。
这种情况下引入subnview,不会对内存、流畅度提供帮助,反而增加了工程的复杂度、降低了界面的灵活度(nview的排版灵活性比HTML还是差很多的)。
但在wap2app里,HTML不是本地的,在线加载HTML并渲染的速度太慢了,所以subnview的加持非常必要。
没仔细研究的人,肯定认为原生部分越多越好,其实事实并非如此,HTML5已经解决好的问题,引入原生多此一举。
所以在5+app里,nview更重要的用途是做标题栏和底部tab,减少双Webview的使用。

继续阅读 »

什么是subNView

subNView,字面拆开理解就是sub native view,有两个核心点:

  • native:subNView是一种原生绘制的View,和HTML5的DOM无关
  • sub:subNView属于webview的一部分,并不替代完整Webview。和所属webview保持同样的生命周期,跟随webview的close、hide、zindex变化而变化。

subNView作为webview的子控件,一个webview可以包含多个subNView,一个subNView上可以绘制多个图片(包括图片轮播)、文字、区域、按钮等。

subNView希望解决什么问题

web页面加载渲染速度相比原生App,有较大的体验差距,以至于在移动设备上严重影响业务体验。这些体验差距是如何造成的呢?原因大致有如下几个:

  • 渲染时机:web app需要等待服务端Document下载完成后才可启动渲染工作,无法分区域渲染;而原生App作为C/S结构的应用,仅向服务端请求业务数据,其它布局、样式大多在本地,故可以在用户触发打开新窗口时,立即渲染新窗口部分区域布局,服务端响应数据后,再更新对应区域的内容;
  • 图片资源请求时机:web app需要先下载Document,然后再根据Document中的<img>标签的src属性去异步加载图片资源,故在web app中总是先看到文字,然后再逐渐看到图片;而原生App则无需任务等待,可以直接加载图片资源,故原生App的图片显示会早于web app中的图片显示;
  • 业务数据请求时机:web app的实现若是前后端分离,则需要先下载封装业务逻辑的js文件,下载完毕后,再由js发起ajax请求;而原生App,则大多将业务逻辑封装在本地,无需等待下载js文件,可以更早的发起HTTP业务请求

如何提升web页面的渲染速度,很多公司都在尝试,比如Google主导的AMP技术,AMP技术以阅读类网页加速为主,适用范围有限。

而subNView,则是一种更为通用、可增强任意web页面渲染体验的技术;subNView在保留HTML5优势的基础上,在webview中增加了一个原生view子控件,利用原生View发挥原生渲染优势;当用户触发时,webview按照原有逻辑,继续加载Document,渲染页面;但无需等待Document加载完成,可同时在原生View上完成如下工作:

  • 绘制固定内容区域,或可从前页获取数据的区域,例如固定地址图片、购物车按钮等,而无需等待Document下载完毕后再去请求加载图片
  • 直接发起业务数据ajax请求,ajax响应后直接在原生View上绘制数据,无需等待业务封装的JS下载

如下为一个使用subNView增强后的商品详情页示例:

从上图可看出:

  • webview按照原有逻辑,加载Document,渲染页面,刚开始内容未加载时还是白屏(中间空白区域)
  • webview同时创建了2个subNView作为webview的子控件
  • subNView 1展示商品详情轮播图及商品价格,是通过ajax动态获取的;轮播图片支持滑动、点击放大预览,用户可提前查看商品详情
  • subNView 2展示购物车相关功能,属于固定显示内容,可直接渲染
  • 购物车按钮点击后事件透传给Webview里的购物车按钮,HTML页面的所有逻辑,仍然复用。subNView只是简单的侵入动画渲染过程,不引发业务逻辑的重新编写。

如何使用subNView

开发者可以通过webview的subNViews属性创建或修改subNview控件,这里需要传入复杂的json对象;为简化开发,DCloud提供了NView模板技术。

NView模板

NView模板类似于vue的single-file components(单文件组件),HBuilder中新建NView模板文件,默认代码如下:

<template>  
    <nviews cachemaxage="86400">  

    </nviews>  
</template>  
<script>  
    module.exports = {  
        data: {  
            //默认数据  
        },  
        init: function(url) {  
            //动态初始化数据  
        },  
        methods: {  
            //方法  
        }  
    };  
</script>

需要注意的是,在<template>节点下仅可以使用受限制的NView HTML,详细参考后续章节介绍

FAQ

Q: 既然有了nview机制,为何不使用nview完成所有业务,而是作为HTML5的补充?
A:
其实这就是subNView前缀是sub的原因之一。
DCloud认为HTML5虽然有功能和性能问题,但面对问题进行强化即可,无需推翻HTML5重新来一套。
在HTML5生态中,有太多精彩的、现成的东西,开发者想要复用之前的HTML5,自然也应该使用subNView强化。
而完全使用nview将导致重写所有业务逻辑,后续也要维护多套版本。
总结一下:subNView的定位就是解决HTML5页面渲染慢的问题,做些简单的界面显示工作,在动画期间就给用户显示部分内容。而完整的业务逻辑处理,仍然在HTML页面里处理。

Q: 为何在wap2app里能使用nview模板,而5+app里不能使用?
A:
首先nview在5+里是一直存在的,wap2app是基于5+的上层框架,没有脱离5+范畴。参考plus.nativeObj.nview的api。
但通过5+的js api写titleNView很简单,但写复杂的subnview,开发体验不太好,于是我们在wap2app里对subnview引入了nview模板式写法,提升开发体验。
所以其实5+app也可以使用nview,只是暂时不能通过模板式写法来写,要写js api。
5+里引入nview模板写法,我们后续会补充,但这个工作优先级不高。
开发者可能误以为5+里也应该大量使用subNView提升体验,但其实不需要。
但nview在5+app里最常用的是title和tab,中间使用subnview的场景很少。
为啥5+app不太需要使用subnview呢?
因为如果你的代码写的不烂,本地的HTML页面加载是非常快的,在新窗体载入时,只是联网取ajax数据,和cs的原生应用一致。
这种情况下引入subnview,不会对内存、流畅度提供帮助,反而增加了工程的复杂度、降低了界面的灵活度(nview的排版灵活性比HTML还是差很多的)。
但在wap2app里,HTML不是本地的,在线加载HTML并渲染的速度太慢了,所以subnview的加持非常必要。
没仔细研究的人,肯定认为原生部分越多越好,其实事实并非如此,HTML5已经解决好的问题,引入原生多此一举。
所以在5+app里,nview更重要的用途是做标题栏和底部tab,减少双Webview的使用。

收起阅读 »

去除M站DOM元素 - wap2app教程

wap2app

屏蔽元素类型

在wap2app项目中,M站需要根据运行环境,判断当前是5+引擎时,做一些调整。

Tips: wap2app项目不管是打包成ipa/apk,还是发布成流应用,都依赖HTML5 PLUS引擎,简称5+引擎。

M站需调整的元素,主要包括几个方面:

1、客户端已有增强实现,屏蔽M站原有元素

比如顶部标题栏,wap2app已启用了原生标题栏,M站就无需再显示DIV的标题栏,否则会出现双标题栏的情况。

2、屏蔽明显wap化的DOM元素

比如:ICP备案、PC/mobile切换等

3、屏蔽原生下载信息

wap2app发布成原生apk/ipa或流应用,在手机用户眼里就是App,在App中出现App的下载链接是不科学的。同时流应用中默认也不支持下载apk或跳转到Appstore。

屏蔽方案

在5+引擎下,屏蔽M站元素的方案大致有两种:

  • 服务端直接不生成对应DOM节点
  • 服务端通过css隐藏对应DOM节点

服务端不生成对应DOM节点

如果M站的DOM是服务端渲染的,则可以在判断是5+引擎的环境下,不输出HTML的dom结构,这样即可减少网络传输的html大小,还可以避免wap化的展现形式。

Tips: 判断5+引擎的依据:navigator.userAgent含有“Html5Plus”字符串

如下为一段php示例代码,仅在非5+引擎环境下,才生成web导航栏

<?php  
    $agent = $_SERVER['HTTP_USER_AGENT'];  
    if(strpos($agent,"Html5Plus") === false){//仅在非5+引擎环境下才显示导航栏  
?>  
    <header class="mui-bar mui-bar-nav">  
        <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>  
        <h1 class="mui-title">web导航栏</h1>  
    </header>  
<?php  
    }  
?>

服务端隐藏DOM节点

这里以原生下载引导为例,如果原生下载banner是客户端渲染的,则可以通过JS动态隐藏下载banner,如下为示例代码:

if(navigator.userAgent.indexOf("Html5Plus") > -1){  
    downloadEl.style.display = "none";//隐藏下载banner  
}

还有一种更为通用的方式:

  • 探测当前为5+引擎,则在body节点上增加一个"html5plus"的class
  • 将所有需要在5+引擎环境下隐藏的元素,均增加"html5plus-hide"的class

如下为示例代码,5+引擎环境下body节点上增加一个“ html5plus”的class

if(navigator.userAgent.indexOf("Html5Plus") > -1 ){  
    document.body.classList.add("html5plus");  
}

在通用css中增加增加一段代码:

.html5plus .html5plus-hide{  
    display:none  
}

这样,所有需要在5+引擎下需隐藏的元素,均在class中增加"html5plus-hide",既不影响普通浏览器环境的显示,在5+引擎环境下也会自动隐藏。如下是一个简单的HTML示例代码,将js、css全部放在HTML页面中了,真实项目时,迁移到通用的js、css文件即可

<!DOCTYPE html>  
<html>  
    <head>  
        <meta charset="UTF-8">  
        <style>  
            /*5+ 引擎环境下自动隐藏无关元素*/  
            .html5plus .html5plus-hide {  
                display: none  
            }  
        </style>  
    </head>  

    <body>  
        <script>  
            if(navigator.userAgent.indexOf("Html5Plus") > -1) {  
                document.body.classList.add("html5plus");  
            }  
        </script>  
        <!--页面标题,class增加html5plus-hide类-->  
        <header class="mui-bar mui-bar-nav html5plus-hide">  
            <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>  
            <h1 class="mui-title">web导航栏</h1>  
        </header>  
        <!--页面主题内容-->  
        <div class="mui-content"></div>  
        <!--下载引导,class增加html5plus-hide类-->  
        <footer class="mui-bar mui-bar-nav download html5plus-hide">  
            <div class="logo"><img src="" /></div>  
            <div class="text">即点即用、流式发行</div>  
            <div class="btn">点击下载</div>  
        </footer>  
    </body>  
</html>

Tips:有些M站可以通过url加一个参数实现不显示原生下载,此时推荐使用这种url

FAQ

Q:如何移除原生导航栏
A:http://ask.dcloud.net.cn/question/50018

继续阅读 »

屏蔽元素类型

在wap2app项目中,M站需要根据运行环境,判断当前是5+引擎时,做一些调整。

Tips: wap2app项目不管是打包成ipa/apk,还是发布成流应用,都依赖HTML5 PLUS引擎,简称5+引擎。

M站需调整的元素,主要包括几个方面:

1、客户端已有增强实现,屏蔽M站原有元素

比如顶部标题栏,wap2app已启用了原生标题栏,M站就无需再显示DIV的标题栏,否则会出现双标题栏的情况。

2、屏蔽明显wap化的DOM元素

比如:ICP备案、PC/mobile切换等

3、屏蔽原生下载信息

wap2app发布成原生apk/ipa或流应用,在手机用户眼里就是App,在App中出现App的下载链接是不科学的。同时流应用中默认也不支持下载apk或跳转到Appstore。

屏蔽方案

在5+引擎下,屏蔽M站元素的方案大致有两种:

  • 服务端直接不生成对应DOM节点
  • 服务端通过css隐藏对应DOM节点

服务端不生成对应DOM节点

如果M站的DOM是服务端渲染的,则可以在判断是5+引擎的环境下,不输出HTML的dom结构,这样即可减少网络传输的html大小,还可以避免wap化的展现形式。

Tips: 判断5+引擎的依据:navigator.userAgent含有“Html5Plus”字符串

如下为一段php示例代码,仅在非5+引擎环境下,才生成web导航栏

<?php  
    $agent = $_SERVER['HTTP_USER_AGENT'];  
    if(strpos($agent,"Html5Plus") === false){//仅在非5+引擎环境下才显示导航栏  
?>  
    <header class="mui-bar mui-bar-nav">  
        <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>  
        <h1 class="mui-title">web导航栏</h1>  
    </header>  
<?php  
    }  
?>

服务端隐藏DOM节点

这里以原生下载引导为例,如果原生下载banner是客户端渲染的,则可以通过JS动态隐藏下载banner,如下为示例代码:

if(navigator.userAgent.indexOf("Html5Plus") > -1){  
    downloadEl.style.display = "none";//隐藏下载banner  
}

还有一种更为通用的方式:

  • 探测当前为5+引擎,则在body节点上增加一个"html5plus"的class
  • 将所有需要在5+引擎环境下隐藏的元素,均增加"html5plus-hide"的class

如下为示例代码,5+引擎环境下body节点上增加一个“ html5plus”的class

if(navigator.userAgent.indexOf("Html5Plus") > -1 ){  
    document.body.classList.add("html5plus");  
}

在通用css中增加增加一段代码:

.html5plus .html5plus-hide{  
    display:none  
}

这样,所有需要在5+引擎下需隐藏的元素,均在class中增加"html5plus-hide",既不影响普通浏览器环境的显示,在5+引擎环境下也会自动隐藏。如下是一个简单的HTML示例代码,将js、css全部放在HTML页面中了,真实项目时,迁移到通用的js、css文件即可

<!DOCTYPE html>  
<html>  
    <head>  
        <meta charset="UTF-8">  
        <style>  
            /*5+ 引擎环境下自动隐藏无关元素*/  
            .html5plus .html5plus-hide {  
                display: none  
            }  
        </style>  
    </head>  

    <body>  
        <script>  
            if(navigator.userAgent.indexOf("Html5Plus") > -1) {  
                document.body.classList.add("html5plus");  
            }  
        </script>  
        <!--页面标题,class增加html5plus-hide类-->  
        <header class="mui-bar mui-bar-nav html5plus-hide">  
            <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>  
            <h1 class="mui-title">web导航栏</h1>  
        </header>  
        <!--页面主题内容-->  
        <div class="mui-content"></div>  
        <!--下载引导,class增加html5plus-hide类-->  
        <footer class="mui-bar mui-bar-nav download html5plus-hide">  
            <div class="logo"><img src="" /></div>  
            <div class="text">即点即用、流式发行</div>  
            <div class="btn">点击下载</div>  
        </footer>  
    </body>  
</html>

Tips:有些M站可以通过url加一个参数实现不显示原生下载,此时推荐使用这种url

FAQ

Q:如何移除原生导航栏
A:http://ask.dcloud.net.cn/question/50018

收起阅读 »

sitemap.json概述 - wap2app教程

教程 wap2app global

sitemap.json原理

sitemap.json 是 wap2app 项目中最重要的配置文件,M站的优化增强工作,大部分都在 sitemap.json 中完成。
在展开说明 sitemap.json 每个配置项的含义前,我们需要先了解 sitemap.json 的原理。

M站的每个页面在 wap2app 中都是运行在 webview 内的,开发者首先需要梳理下M站的所有 url,都配置到 sitemap.json 里。
当然某些页面 url 虽然不同,但实际上内容结构是一样的。比如一个新闻站的不同新闻详情,可以通过通配符或正则表达式来批量匹配 url。
在 sitemap.json 中的 pages 节点下面,需要把全站的 url 都配进去。

举例:
某M站有2级页面,首页是列表页,网址是 http://m.example.com,二级页是详情页,网址是在 detail 目录下的若干 html 文件。
那么开发者需要在 sitemap 中的pages下面,新建2个节点,把这2类 url 归纳到2个 page(也就是2个Webview里)。

{  
  "global": {   
  },   
  "pages": [  
    {  
      "webviewId": "__W2A__m.example.com",//首页  
      "matchUrls": [  
        {  
          "href": "http://m.example.com"  
        },  
        {  
          "href": "http://m.example.com/" //这里与上行的不同在于url末尾多了一个/。多个匹配规则是or关系  
        }  
      ]  
    },  
    {  
      "webviewId": "detail",//详情页  
      "matchUrls": [  
        {  
          "pathname": "WILDCARD:/detail/*.html" //这里使用了通配符写法,后续有专门章节介绍通配符。  
        }  
      ]  
    }  
  ]  
}

把url和webview的关系归纳好后,我们就可以对每个webview的显示做强化。
在每个page下面,除了webviewId、matchUrls,还有一个重要的属性就是webviewParameter。
开发者可以在webviewParameter里设置各种强大功能,设置原生title、调用原生渲染、通过注入css调整页面样式、注入js增强页面功能。
具体webviewParameter的配置说明另见http://ask.dcloud.net.cn/article/12749

小结一下,也就是说,sitempap.json的主要工作就是:

  1. 规整M站的URL,创建pages规则,并把各个url页面匹配到不同page中。
  2. 针对该webview需设置哪些增强属性。

sitemap.json配置

在 HBuilder 中新建 wap2app 项目后,默认 sitemap.json 内容如下:

{  
  "global": {  
    "webviewParameter": {  
      "titleNView": {//原生标题栏  
        "backgroundColor": "#f7f7f7",//导航栏背景色  
        "titleColor": "#000000",//标题颜色  
        "titleSize": "17px",//标题字体大小  
        "borderColor": "#cccccc"  
      }  
    },  
    "easyConfig": {}  
  },  
  "pages": [  
    {  
      "webviewId": "__W2A__m.example.com",//首页  
      "matchUrls": [  
        {  
          "href": "http://m.example.com"  
        }, {  
          "href": "http://m.example.com/"  
        }  
      ]  
    }  
  ]  
}

从代码中可以看出来,sitemap.json 文件中有两个节点:

  • global:App全局配置
  • pages:配置M站的具体页面,可在具体页面的配置中覆盖 global 中的全局配置

global

global 节点实现 App 全局配置,其下可设置两个节点:

  • webviewParameter:webview通用配置,比如通用原生标题栏颜色等;详细参考webviewParameter配置
  • easyConfig:为提升用户体验而提供的简化设置,比如后退处理等;详细参考easyConfig配置

wap2app 中每个页面默认使用 global 的配置,若相同的属性在特定页面中也有配置,则以对应页面的配置属性值为准;如下为一个示例,在 page1 页面,单独定义了原生导航栏的背景色和字体颜色。

{  
  "global": {//全局默认配置,每个页面可以单独定义覆盖  
    "webviewParameter": {  
      "titleNView": {  
        "backgroundColor": "#f7f7f7",//原生标题栏背景色  
        "titleColor": "#000000",//标题颜色  
        "titleSize": "17px",//标题字体大小  
        "borderColor": "#cccccc"  
      }  
    },  
    "easyConfig": {}  
  },  
  "pages": [  
    {  
      "webviewid": "page1",  
      "matchurls": [],  
      "webviewParameter": {  
        "titleNView": {//覆盖了global原生标题栏配置  
          "backgroundColor": "#ff0000",  //导航栏背景色为红色  
          "titleColor": "#ffffff"  
        }  
      }  
    }  
  ]  
}

pages

pages 为 Array 类型,包含M站所有需要增强的页面配置,格式如下:

"pages":[  
  {  
      //page1 配置  
  }, {  
      //page2 配置  
  }  
]

page

每个页面相关属性均配置在 page 节点下,page 节点包含四个属性:

  • webviewId:当前页面所属webview的id,类型为String,方便后续增强编程实现,比如在app.js中可使用plus.webview.getWebviewById()方法获取当前的webview对象
  • matchUrls:页面URL匹配规则,满足matchUrls匹配规则的页面,将使用当前页面配置规则打开,比如webview的id 固定为本页配置的"webviewId"属性,详细参考matchurls配置
  • webviewParameter:webview相关设置,比如原生导航条,详细参考webviewParameter配置
  • easyConfig:为提升用户体验而提供的简化实现,比如back按键时,优先关闭弹出层,详细参考easyConfig配置

示例如下:

{  
  "webviewId": "page1",  
    "matchUrls": [],//url匹配规则  
    "webviewParameter":{  
        //TODO webview属性设置  
    },  
    "easyConfig":{  
      //TODO 简化配置  
    }  
}

wap2app打开新页面的流程为:

  • 遍历 pages 节点下的每个 page 对象
  • 使用新页面的 url 地址和 page 对象中的 matchUrls 规则进行匹配;
  • 若匹配成功,则使用当前的 page 对象创建新的 webview(id为page对象的webviewId属性、webview属性为当前page对象配置的webviewParameter),然后使用新的 webview 加载新页面 url
  • 若匹配失败,则使用global属性创建新的 webview(webview的id随机),然后使用新的 webview 加载新页面url

同一类别的页面应该配置为一个 page 对象,比如详情页面,大多核心 DOM 结构、页面布局相同,这些详情页需配置的增强方案相同;

注意:首页的 webviewid 必须为W2A+首页域名,例如:W2Am.example.com,HBuilder 新建 wap2app 工程时会默认生成,不能修改。

了解 sitemap.json 的格式后,就可以继续顺序阅读matchUrls配置webviewParameter配置easyConfig配置等文章了,了解每个节点的详细配置项。

继续阅读 »

sitemap.json原理

sitemap.json 是 wap2app 项目中最重要的配置文件,M站的优化增强工作,大部分都在 sitemap.json 中完成。
在展开说明 sitemap.json 每个配置项的含义前,我们需要先了解 sitemap.json 的原理。

M站的每个页面在 wap2app 中都是运行在 webview 内的,开发者首先需要梳理下M站的所有 url,都配置到 sitemap.json 里。
当然某些页面 url 虽然不同,但实际上内容结构是一样的。比如一个新闻站的不同新闻详情,可以通过通配符或正则表达式来批量匹配 url。
在 sitemap.json 中的 pages 节点下面,需要把全站的 url 都配进去。

举例:
某M站有2级页面,首页是列表页,网址是 http://m.example.com,二级页是详情页,网址是在 detail 目录下的若干 html 文件。
那么开发者需要在 sitemap 中的pages下面,新建2个节点,把这2类 url 归纳到2个 page(也就是2个Webview里)。

{  
  "global": {   
  },   
  "pages": [  
    {  
      "webviewId": "__W2A__m.example.com",//首页  
      "matchUrls": [  
        {  
          "href": "http://m.example.com"  
        },  
        {  
          "href": "http://m.example.com/" //这里与上行的不同在于url末尾多了一个/。多个匹配规则是or关系  
        }  
      ]  
    },  
    {  
      "webviewId": "detail",//详情页  
      "matchUrls": [  
        {  
          "pathname": "WILDCARD:/detail/*.html" //这里使用了通配符写法,后续有专门章节介绍通配符。  
        }  
      ]  
    }  
  ]  
}

把url和webview的关系归纳好后,我们就可以对每个webview的显示做强化。
在每个page下面,除了webviewId、matchUrls,还有一个重要的属性就是webviewParameter。
开发者可以在webviewParameter里设置各种强大功能,设置原生title、调用原生渲染、通过注入css调整页面样式、注入js增强页面功能。
具体webviewParameter的配置说明另见http://ask.dcloud.net.cn/article/12749

小结一下,也就是说,sitempap.json的主要工作就是:

  1. 规整M站的URL,创建pages规则,并把各个url页面匹配到不同page中。
  2. 针对该webview需设置哪些增强属性。

sitemap.json配置

在 HBuilder 中新建 wap2app 项目后,默认 sitemap.json 内容如下:

{  
  "global": {  
    "webviewParameter": {  
      "titleNView": {//原生标题栏  
        "backgroundColor": "#f7f7f7",//导航栏背景色  
        "titleColor": "#000000",//标题颜色  
        "titleSize": "17px",//标题字体大小  
        "borderColor": "#cccccc"  
      }  
    },  
    "easyConfig": {}  
  },  
  "pages": [  
    {  
      "webviewId": "__W2A__m.example.com",//首页  
      "matchUrls": [  
        {  
          "href": "http://m.example.com"  
        }, {  
          "href": "http://m.example.com/"  
        }  
      ]  
    }  
  ]  
}

从代码中可以看出来,sitemap.json 文件中有两个节点:

  • global:App全局配置
  • pages:配置M站的具体页面,可在具体页面的配置中覆盖 global 中的全局配置

global

global 节点实现 App 全局配置,其下可设置两个节点:

  • webviewParameter:webview通用配置,比如通用原生标题栏颜色等;详细参考webviewParameter配置
  • easyConfig:为提升用户体验而提供的简化设置,比如后退处理等;详细参考easyConfig配置

wap2app 中每个页面默认使用 global 的配置,若相同的属性在特定页面中也有配置,则以对应页面的配置属性值为准;如下为一个示例,在 page1 页面,单独定义了原生导航栏的背景色和字体颜色。

{  
  "global": {//全局默认配置,每个页面可以单独定义覆盖  
    "webviewParameter": {  
      "titleNView": {  
        "backgroundColor": "#f7f7f7",//原生标题栏背景色  
        "titleColor": "#000000",//标题颜色  
        "titleSize": "17px",//标题字体大小  
        "borderColor": "#cccccc"  
      }  
    },  
    "easyConfig": {}  
  },  
  "pages": [  
    {  
      "webviewid": "page1",  
      "matchurls": [],  
      "webviewParameter": {  
        "titleNView": {//覆盖了global原生标题栏配置  
          "backgroundColor": "#ff0000",  //导航栏背景色为红色  
          "titleColor": "#ffffff"  
        }  
      }  
    }  
  ]  
}

pages

pages 为 Array 类型,包含M站所有需要增强的页面配置,格式如下:

"pages":[  
  {  
      //page1 配置  
  }, {  
      //page2 配置  
  }  
]

page

每个页面相关属性均配置在 page 节点下,page 节点包含四个属性:

  • webviewId:当前页面所属webview的id,类型为String,方便后续增强编程实现,比如在app.js中可使用plus.webview.getWebviewById()方法获取当前的webview对象
  • matchUrls:页面URL匹配规则,满足matchUrls匹配规则的页面,将使用当前页面配置规则打开,比如webview的id 固定为本页配置的"webviewId"属性,详细参考matchurls配置
  • webviewParameter:webview相关设置,比如原生导航条,详细参考webviewParameter配置
  • easyConfig:为提升用户体验而提供的简化实现,比如back按键时,优先关闭弹出层,详细参考easyConfig配置

示例如下:

{  
  "webviewId": "page1",  
    "matchUrls": [],//url匹配规则  
    "webviewParameter":{  
        //TODO webview属性设置  
    },  
    "easyConfig":{  
      //TODO 简化配置  
    }  
}

wap2app打开新页面的流程为:

  • 遍历 pages 节点下的每个 page 对象
  • 使用新页面的 url 地址和 page 对象中的 matchUrls 规则进行匹配;
  • 若匹配成功,则使用当前的 page 对象创建新的 webview(id为page对象的webviewId属性、webview属性为当前page对象配置的webviewParameter),然后使用新的 webview 加载新页面 url
  • 若匹配失败,则使用global属性创建新的 webview(webview的id随机),然后使用新的 webview 加载新页面url

同一类别的页面应该配置为一个 page 对象,比如详情页面,大多核心 DOM 结构、页面布局相同,这些详情页需配置的增强方案相同;

注意:首页的 webviewid 必须为W2A+首页域名,例如:W2Am.example.com,HBuilder 新建 wap2app 工程时会默认生成,不能修改。

了解 sitemap.json 的格式后,就可以继续顺序阅读matchUrls配置webviewParameter配置easyConfig配置等文章了,了解每个节点的详细配置项。

收起阅读 »

app内区域截图利用html2Canvals保存到手机

截屏

app内区域截图利用html2Canvals保存到手机

app内有时候需要区域内的截图保存dom为图像,我们可以使用html2Canvas将dom转换成base64图像字符串,然后再利用5+api保存至app
,通用代码如下:

function saveDomImage (html2Canvas, dom, fileName) {  //使用之前要引入 html2Canvas.js  
        if(mui.os.plus){  
            if (typeof html2Canvas == null)  
                throw Error("html2Canvas is not defined");  
            if (dom == null)  
                throw Error("saveDomImage param : dom is null");  
            if (fileName == null || fileName == "")  
                fileName = "untitled.png";  

            var getPixelRatio = function(context) {  
                var backingStore = context.backingStorePixelRatio ||  
                    context.webkitBackingStorePixelRatio || 1;  
                return (window.devicePixelRatio || 1) / backingStore;  
            };  

            var _canvas = document.createElement('canvas');  

            var ctx = _canvas.getContext('2d');  
            var ratio = getPixelRatio(ctx);  
            ctx.scale(ratio,ratio);  

            var w = dom.offsetWidth;  
            var h = dom.offsetHeight;  

            _canvas.width = w;  
            _canvas.height = h;  
            _canvas.style.width = w * ratio + 'px';  
            _canvas.style.height = h * ratio + "px";  

            html2Canvas(dom, {  
                allowTaint:true,  
                logging: false,  
                profile: true,  
                useCROS: true,  
                canvas : _canvas,  
                onrendered: function (canvas) {  
                    var dataUrl = canvas.toDataURL();  
                    var b = new plus.nativeObj.Bitmap('bitblmap');  

                    b.loadBase64Data(dataUrl, function () {  
                        /*这里一定要是_doc目录*/  
                        b.save("_doc/" + fileName, {overwrite: true}, function (object) {  
                            //保存到相册  
                            plus.gallery.save("_doc/" + fileName, function () {  
                                mui.toast("图片已保存到相册");  
                            }, function () {  
                                mui.toast("图片保存失败");  
                            });  
                        }, function () {  
                            mui.toast("图片保存失败");  
                        });  
                    }, function () {  
                        mui.toast("图片保存失败");  
                    });  
                }  
            });  
        }  
    }

至于为什么要是_doc目录,本人未查实原因,hbuilder测试包可以用 _www ,但是打出来的正式包只能用 _doc。
有好心人知晓请告诉本人。

这里html2Canvas使用版本是:0.5.0-beta3。

说明:
1 ,dom元素最好是文档流定位的,用absolute 和 fixed 截取出来的有偏移, 如果想解决这个问题,可以把这个dom复制到新的无偏移(top:0 ;left:0)的dom里面,再对新dom执行保存操作。
2,保存的图片肯定是没有原图清晰的,勉强也能接受,如果图上有二维码识别, 尽量把二维码做的识别度高点。
3,本功能适合保存dom合成的图片。屏幕全截屏,保存远端img图片,mui提供更简单的方式, 请参考其他文档。

html2Canvas: http://html2canvas.hertzen.com

继续阅读 »

app内区域截图利用html2Canvals保存到手机

app内有时候需要区域内的截图保存dom为图像,我们可以使用html2Canvas将dom转换成base64图像字符串,然后再利用5+api保存至app
,通用代码如下:

function saveDomImage (html2Canvas, dom, fileName) {  //使用之前要引入 html2Canvas.js  
        if(mui.os.plus){  
            if (typeof html2Canvas == null)  
                throw Error("html2Canvas is not defined");  
            if (dom == null)  
                throw Error("saveDomImage param : dom is null");  
            if (fileName == null || fileName == "")  
                fileName = "untitled.png";  

            var getPixelRatio = function(context) {  
                var backingStore = context.backingStorePixelRatio ||  
                    context.webkitBackingStorePixelRatio || 1;  
                return (window.devicePixelRatio || 1) / backingStore;  
            };  

            var _canvas = document.createElement('canvas');  

            var ctx = _canvas.getContext('2d');  
            var ratio = getPixelRatio(ctx);  
            ctx.scale(ratio,ratio);  

            var w = dom.offsetWidth;  
            var h = dom.offsetHeight;  

            _canvas.width = w;  
            _canvas.height = h;  
            _canvas.style.width = w * ratio + 'px';  
            _canvas.style.height = h * ratio + "px";  

            html2Canvas(dom, {  
                allowTaint:true,  
                logging: false,  
                profile: true,  
                useCROS: true,  
                canvas : _canvas,  
                onrendered: function (canvas) {  
                    var dataUrl = canvas.toDataURL();  
                    var b = new plus.nativeObj.Bitmap('bitblmap');  

                    b.loadBase64Data(dataUrl, function () {  
                        /*这里一定要是_doc目录*/  
                        b.save("_doc/" + fileName, {overwrite: true}, function (object) {  
                            //保存到相册  
                            plus.gallery.save("_doc/" + fileName, function () {  
                                mui.toast("图片已保存到相册");  
                            }, function () {  
                                mui.toast("图片保存失败");  
                            });  
                        }, function () {  
                            mui.toast("图片保存失败");  
                        });  
                    }, function () {  
                        mui.toast("图片保存失败");  
                    });  
                }  
            });  
        }  
    }

至于为什么要是_doc目录,本人未查实原因,hbuilder测试包可以用 _www ,但是打出来的正式包只能用 _doc。
有好心人知晓请告诉本人。

这里html2Canvas使用版本是:0.5.0-beta3。

说明:
1 ,dom元素最好是文档流定位的,用absolute 和 fixed 截取出来的有偏移, 如果想解决这个问题,可以把这个dom复制到新的无偏移(top:0 ;left:0)的dom里面,再对新dom执行保存操作。
2,保存的图片肯定是没有原图清晰的,勉强也能接受,如果图上有二维码识别, 尽量把二维码做的识别度高点。
3,本功能适合保存dom合成的图片。屏幕全截屏,保存远端img图片,mui提供更简单的方式, 请参考其他文档。

html2Canvas: http://html2canvas.hertzen.com

收起阅读 »

app打开应用市场

Appstore Native.JS

有时候应用内需要让用户跳转到app应用市场来评分, ios跳转到appstore , 安卓跳转到对应的应用市场
分享一段代码 ios和 安卓通用

  function  jumpToAppMarket (code) {  
        if (plus.os.name == "iOS") {  
            plus.runtime.openURL("itms-apps://" + 'itunes.apple.com/cn/app/wechat/id414478124?mt=8');  
        } else if (plus.os.name == "Android") {  
            var Uri = plus.android.importClass("android.net.Uri");  
            var uri = Uri.parse("market://details?id=" + 'com.tencent.mm' );  
            var Intent = plus.android.importClass('android.content.Intent');  
            var intent = new Intent(Intent.ACTION_VIEW, uri);  
            var main = plus.android.runtimeMainActivity();  
            main.startActivity(intent);  
        }  
    }

(这里都用微信示例,实际项目需要替换自己的iOS包地址和Android包名)
安卓 如果又多个应用市场,会弹出列表提供选择
ios 则直接进入appstore

继续阅读 »

有时候应用内需要让用户跳转到app应用市场来评分, ios跳转到appstore , 安卓跳转到对应的应用市场
分享一段代码 ios和 安卓通用

  function  jumpToAppMarket (code) {  
        if (plus.os.name == "iOS") {  
            plus.runtime.openURL("itms-apps://" + 'itunes.apple.com/cn/app/wechat/id414478124?mt=8');  
        } else if (plus.os.name == "Android") {  
            var Uri = plus.android.importClass("android.net.Uri");  
            var uri = Uri.parse("market://details?id=" + 'com.tencent.mm' );  
            var Intent = plus.android.importClass('android.content.Intent');  
            var intent = new Intent(Intent.ACTION_VIEW, uri);  
            var main = plus.android.runtimeMainActivity();  
            main.startActivity(intent);  
        }  
    }

(这里都用微信示例,实际项目需要替换自己的iOS包地址和Android包名)
安卓 如果又多个应用市场,会弹出列表提供选择
ios 则直接进入appstore

收起阅读 »

自己有个网站,使用mui做了移动端h5界面,供各位参考

mui

具体截图如下:











网站地址:http://www.pinhuba.com,移动端可以扫码体验:

继续阅读 »

具体截图如下:











网站地址:http://www.pinhuba.com,移动端可以扫码体验:

收起阅读 »

plus.zip.compressImage在IOS下“文件不存在”的解决方法

plus.zip.compressImage在IOS下“文件不存在“主要是由于plus.zip.compressImage的src、 dst文件目录错误引起的,将src、dst 参数前面加上:"file://"即可解决。

                     plus.io.resolveLocalFileSystemURL(p,function(entry){  
                        plus.zip.compressImage({  
                            src:"file://"+entry.fullPath,  
                            dst:"file://"+entry.fullPath,  
                            width:"800px",  //缩小到原来的一半  
                            quality:90,  
                            overwrite:true //覆盖文件  
                        },function(){  
                            plus.nativeUI.toast("照片压缩成功");  
                        },function(error) {  
                            plus.nativeUI.toast("照片压缩失败");  
                        });       
                    });
继续阅读 »

plus.zip.compressImage在IOS下“文件不存在“主要是由于plus.zip.compressImage的src、 dst文件目录错误引起的,将src、dst 参数前面加上:"file://"即可解决。

                     plus.io.resolveLocalFileSystemURL(p,function(entry){  
                        plus.zip.compressImage({  
                            src:"file://"+entry.fullPath,  
                            dst:"file://"+entry.fullPath,  
                            width:"800px",  //缩小到原来的一半  
                            quality:90,  
                            overwrite:true //覆盖文件  
                        },function(){  
                            plus.nativeUI.toast("照片压缩成功");  
                        },function(error) {  
                            plus.nativeUI.toast("照片压缩失败");  
                        });       
                    });
收起阅读 »

easyConfig配置 - wap2app教程

easyConfig wap2app

综述

sitemap中的webviewParameter配置其实是HTML5Plus规范中的Webview的参数设置。
除了配置Webview的参数外,开发者还会有其他业务需求。
在wap2app的设计中,复杂的扩展需求是通过app.js自行编程实现的。
但实际开发中,有很多较为通用的处理工作,为了减少开发者的重复工作量,官方在wap2app的sitemap下面增加了easyConfig节点,封装了一些常用操作,通过简单的配置,就可以完成原来需要很多编码才能完成的工作。

下面是目前支持的easyConfig配置。

back

用户按下back按键或点击顶部标题栏的返回箭头时,将触发wap2app的后退逻辑。
常规情况下,back按钮是关闭当前Webview并显示上一个Webview。
但我们有时需定制back的逻辑。
关于后退的定制,在back节点下进行配置。
目前back节点下有before和history这2个配置。

before

若页面有弹出层时,此时用户按下back按键,其实不应该把这个Webview关闭。
理想的效果是按下back时关闭弹出的浮层,当浮层关闭后再按back键,才是关闭Webview。
wap2app会智能处理弹出层的关闭,当用户点击back按键时,先探测当前页面是否存在弹出层,若存在则关闭弹出层,否则关闭当前页面。
但前端写法过于灵活,wap2app目前无法处理所有的弹出层情况。在实际业务中,弹出层的显示通常有两种模式:

  • 全屏弹出层(比如modal组件),通常会提供按钮关闭弹出层,比如取消按钮或关闭图标
  • 非全屏弹出层,通常也会有取消按钮,另外大多还会有半透明遮罩层,用户点击遮罩层,也可以关闭弹出层;

鉴于这些常见的弹出层关闭逻辑,wap2app提供了一种简化配置,可以配置弹出层选择器、取消按钮(或遮罩层)选择器、取消按钮(或遮罩层)点击事件,示例如下:

    "easyConfig":{  
        "back":{  
            "before":[  
                {  
                    "popupSelector":".popup", //弹出层选择器  
                    "closeSelector":".mask", //取消按钮选择器或遮罩层选择器  
                    "eventType":"click" //事件类型,默认为"click"  
                }  
            ]  
        }  
    }

如上示例,在用户点击back按键时,wap2app执行如下逻辑:

  • 若document.querySelector(".popup")元素存在且处于屏幕可视区域,则触发document.querySelector(".mask")元素的click事件,之后不再执行webview的后退逻辑
  • 若document.querySelector(".popup")元素不存在或在屏幕可视区域不可见,则继续执行webview的后退逻辑

before节点为Array类型,若当前页面有多个弹出层,则配置多个节点即可,例如:

    "easyConfig":{  
        "back":{  
            "before":[  
                {//第一个弹出层  
                    "popupSelector":".popup", //弹出层选择器  
                    "closeSelector":".mask", //取消按钮选择器或遮罩层选择器  
                    "eventType":"click" //事件类型,默认为"click"  
                },  
                {//第二个弹出层  
                    "popupSelector":".modal", //弹出层选择器  
                    "closeSelector":"#cancel_btn", //取消按钮选择器  
                    "eventType":"touchstart" //事件类型  
                }  
            ]  
        }  
    }

history

wap2app默认窗体逻辑是点击打开新Webview,点back关闭该Webview并漏出上一个Webview。但如果是同一组页面在一个Webview里跳转,此时不开新窗体,点back会走history.back。
但有时我们需要面对其他情况。比如
用户从首页点击链接,打开a.html,然后在a.html链接中通过相似推荐再次点击打开b.html

a和b都是一组页面,Webview配置也相同,matchUrls规则匹配的页面,会在同一个webview中打开,如下:

    {  
        "webviewId":"detail",  
        "matchUrls":[  
            {  
                "pathname":"a.html"  
            },  
            {  
                "pathname":"b.html"  
            }  
        ]  
    }

在wap2app中,相应执行逻辑如下:

  • 打开a.html时,匹配到webviewId为detail的页面配置,则创建id为detail的webview(简称为detailWebview),并加载a.html
  • 打开b.html时,再次匹配到webviewId为detail的页面配置,此时发现id为detail的webview已存在,即detailWebview,则不再创建新webview,而在detailWebview内执行location.href = b.html的逻辑,webview内部跳转到b.html

若此时用户按下back按键,则会在detailWebview内执行history.back(),返回到a.html,并不会直接关闭当前webview,返回到首页。

如果此时,希望用户按下back时,不执行history.back(),而是直接关闭webview,返回到上一层webview,则可以通过easyConfig的back下的设置history配置实现。

    {  
        "webviewId":"detail",  
        "matchUrls":[  
            {  
                "pathname":"a.html"  
            },  
            {  
                "pathname":"b.html"  
            }  
        ],  
        "easyConfig":{  
            "back":{  
                "history":false //不允许执行history.back  
            }  
        }  
    }

按以上代码配置,点back时,会关闭detail Webview,回到首页,即便是页面跳转到了b.html。

open

为了更好的窗体切换体验,wap2app实现了大量的封装;其中,webview自身相关的属性在webviewParameter节点中配置,打开新窗口的其它优化则在easyConfig->open节点下配置。

animation

wap2app在打开新窗口时,新窗口默认使用从右向左的移动动画;开发者也可以通过open->animation属性配置窗口动画类型及动画执行时间,代码示例如下:

{  
    "webviewId": "page1",  
    "matchUrls": [  
        //url匹配规则  
    ],  
    "easyConfig":{  
        "open":{  
            "animation":{//窗口切换动画配置  
                "type":"slide-in-right",//窗口动画类型  
                "duration":300//窗口动画执行时间  
            }  
        }  
    }  
}

目前支持的动画类型包括:

  • "none": 无动画效果,立即显示页面,无任何动画效果,此效果忽略动画时间参数。
  • "slide-in-right": 页面从屏幕右侧外向内横向滑动显示
  • "slide-in-left": 页面从屏幕左侧向右横向滑动显示
  • "slide-in-top": 页面从屏幕上侧向下竖向滑动显示
  • "slide-in-bottom": 页面从屏幕下侧向上竖向滑动显示
  • "fade-in": 页面从完全透明到不透明逐渐显示
  • "zoom-out": 页面在屏幕中间从小到大逐渐放大显示
  • "zoom-fade-out": 页面在屏幕中间从小到大逐渐放大并且从透明到不透明逐渐显示
  • "pop-in": 页面从屏幕右侧滑入显示,同时上一个页面带阴影效果从屏幕左侧滑出隐藏

waiting

wap2app在打开新窗口时,默认会显示waiting等待框,新webview的titleUpdate事件触发后,自动关闭waiting等待框。(titleUpdate是页面title节点解析触发的事件,详见HTML5Plus Webview的event)

等待框默认使用5+引擎的默认waiting框效果,开发者可以通过参数配置自定义效果,可配置参数包括:

  • title:可选,类型为String,等待对话框上显示的提示标题内容
  • options:可选,类型为Object,等待对话框的显示参数,设置等待框的宽、高、边距、背景等样式等;完整参数参考5+原生等待框参数

如下是一个示例,配置等待框为粉色背景、白色文字,等待提示语为“加载中”:

{  
    "webviewId": "page1",  
    "matchUrls": [  
        //url匹配规则  
    ],  
    "easyConfig":{  
        "open":{  
            "waiting":{  
                "title":"加载中...",  
                "options":{  
                    "background":"#EF5FA7",//粉色背景  
                    "color":"#ffffff"//白色文字  
                }  
            }  
        }  

    }  
}

运行结果如下:

如果M站页面响应较快,不需要显示waiting框,则可以通过配置waiting:false来禁用waiting等待框,例如:

{  
    "webviewId": "page1",  
    "matchUrls": [  
        //url匹配规则  
    ],  
    "easyConfig":{  
        "open":{  
            "waiting":false  // 禁用waiting,打开page1页面时,不显示waiting等待框  
        }  
    }  
}

Tips:
waiting常见于内容渲染慢的场景。如果内容渲染快,那么waiting圈反而碍事。
如果使用了NView模板,建议禁用waiting等待框。

quit

用户在应用首页按下back按键,会触发wap2app的退出逻辑,应用退出的相关配置在global->easyConfig->quit节点下配置。

Tips:quit节点仅支持在global下配置,不支持页面继承。

wap2app退出时,默认会弹出toast消息框,提示用户“再按一次返回键退出”,同时在toast信息中给出“反馈意见”的链接,效果图如下:

在toast消息显示时,用户可以点击“反馈意见”链接,反馈App的使用问题;开发者可以登录DCloud开发者中心查看用户反馈的问题,解决并持续改进。

wap2app可以通过配置,在应用退出的toast消息中不显示“反馈意见”的链接,方式如下:

"global": {  
    "webviewParameter": {  
        //webview相关通用配置  
    },  
    "easyConfig": {  
        "quit": {  
            "toast": {  
                "showFeedback": false //不显示“反馈意见”链接,默认为true  
            }  
        }  
    }  
}

FAQ

Q:退出时候的反馈如何去掉
A:参考上面文档中的说明,调整首页 easyConfig -> quit 的配置即可。

继续阅读 »

综述

sitemap中的webviewParameter配置其实是HTML5Plus规范中的Webview的参数设置。
除了配置Webview的参数外,开发者还会有其他业务需求。
在wap2app的设计中,复杂的扩展需求是通过app.js自行编程实现的。
但实际开发中,有很多较为通用的处理工作,为了减少开发者的重复工作量,官方在wap2app的sitemap下面增加了easyConfig节点,封装了一些常用操作,通过简单的配置,就可以完成原来需要很多编码才能完成的工作。

下面是目前支持的easyConfig配置。

back

用户按下back按键或点击顶部标题栏的返回箭头时,将触发wap2app的后退逻辑。
常规情况下,back按钮是关闭当前Webview并显示上一个Webview。
但我们有时需定制back的逻辑。
关于后退的定制,在back节点下进行配置。
目前back节点下有before和history这2个配置。

before

若页面有弹出层时,此时用户按下back按键,其实不应该把这个Webview关闭。
理想的效果是按下back时关闭弹出的浮层,当浮层关闭后再按back键,才是关闭Webview。
wap2app会智能处理弹出层的关闭,当用户点击back按键时,先探测当前页面是否存在弹出层,若存在则关闭弹出层,否则关闭当前页面。
但前端写法过于灵活,wap2app目前无法处理所有的弹出层情况。在实际业务中,弹出层的显示通常有两种模式:

  • 全屏弹出层(比如modal组件),通常会提供按钮关闭弹出层,比如取消按钮或关闭图标
  • 非全屏弹出层,通常也会有取消按钮,另外大多还会有半透明遮罩层,用户点击遮罩层,也可以关闭弹出层;

鉴于这些常见的弹出层关闭逻辑,wap2app提供了一种简化配置,可以配置弹出层选择器、取消按钮(或遮罩层)选择器、取消按钮(或遮罩层)点击事件,示例如下:

    "easyConfig":{  
        "back":{  
            "before":[  
                {  
                    "popupSelector":".popup", //弹出层选择器  
                    "closeSelector":".mask", //取消按钮选择器或遮罩层选择器  
                    "eventType":"click" //事件类型,默认为"click"  
                }  
            ]  
        }  
    }

如上示例,在用户点击back按键时,wap2app执行如下逻辑:

  • 若document.querySelector(".popup")元素存在且处于屏幕可视区域,则触发document.querySelector(".mask")元素的click事件,之后不再执行webview的后退逻辑
  • 若document.querySelector(".popup")元素不存在或在屏幕可视区域不可见,则继续执行webview的后退逻辑

before节点为Array类型,若当前页面有多个弹出层,则配置多个节点即可,例如:

    "easyConfig":{  
        "back":{  
            "before":[  
                {//第一个弹出层  
                    "popupSelector":".popup", //弹出层选择器  
                    "closeSelector":".mask", //取消按钮选择器或遮罩层选择器  
                    "eventType":"click" //事件类型,默认为"click"  
                },  
                {//第二个弹出层  
                    "popupSelector":".modal", //弹出层选择器  
                    "closeSelector":"#cancel_btn", //取消按钮选择器  
                    "eventType":"touchstart" //事件类型  
                }  
            ]  
        }  
    }

history

wap2app默认窗体逻辑是点击打开新Webview,点back关闭该Webview并漏出上一个Webview。但如果是同一组页面在一个Webview里跳转,此时不开新窗体,点back会走history.back。
但有时我们需要面对其他情况。比如
用户从首页点击链接,打开a.html,然后在a.html链接中通过相似推荐再次点击打开b.html

a和b都是一组页面,Webview配置也相同,matchUrls规则匹配的页面,会在同一个webview中打开,如下:

    {  
        "webviewId":"detail",  
        "matchUrls":[  
            {  
                "pathname":"a.html"  
            },  
            {  
                "pathname":"b.html"  
            }  
        ]  
    }

在wap2app中,相应执行逻辑如下:

  • 打开a.html时,匹配到webviewId为detail的页面配置,则创建id为detail的webview(简称为detailWebview),并加载a.html
  • 打开b.html时,再次匹配到webviewId为detail的页面配置,此时发现id为detail的webview已存在,即detailWebview,则不再创建新webview,而在detailWebview内执行location.href = b.html的逻辑,webview内部跳转到b.html

若此时用户按下back按键,则会在detailWebview内执行history.back(),返回到a.html,并不会直接关闭当前webview,返回到首页。

如果此时,希望用户按下back时,不执行history.back(),而是直接关闭webview,返回到上一层webview,则可以通过easyConfig的back下的设置history配置实现。

    {  
        "webviewId":"detail",  
        "matchUrls":[  
            {  
                "pathname":"a.html"  
            },  
            {  
                "pathname":"b.html"  
            }  
        ],  
        "easyConfig":{  
            "back":{  
                "history":false //不允许执行history.back  
            }  
        }  
    }

按以上代码配置,点back时,会关闭detail Webview,回到首页,即便是页面跳转到了b.html。

open

为了更好的窗体切换体验,wap2app实现了大量的封装;其中,webview自身相关的属性在webviewParameter节点中配置,打开新窗口的其它优化则在easyConfig->open节点下配置。

animation

wap2app在打开新窗口时,新窗口默认使用从右向左的移动动画;开发者也可以通过open->animation属性配置窗口动画类型及动画执行时间,代码示例如下:

{  
    "webviewId": "page1",  
    "matchUrls": [  
        //url匹配规则  
    ],  
    "easyConfig":{  
        "open":{  
            "animation":{//窗口切换动画配置  
                "type":"slide-in-right",//窗口动画类型  
                "duration":300//窗口动画执行时间  
            }  
        }  
    }  
}

目前支持的动画类型包括:

  • "none": 无动画效果,立即显示页面,无任何动画效果,此效果忽略动画时间参数。
  • "slide-in-right": 页面从屏幕右侧外向内横向滑动显示
  • "slide-in-left": 页面从屏幕左侧向右横向滑动显示
  • "slide-in-top": 页面从屏幕上侧向下竖向滑动显示
  • "slide-in-bottom": 页面从屏幕下侧向上竖向滑动显示
  • "fade-in": 页面从完全透明到不透明逐渐显示
  • "zoom-out": 页面在屏幕中间从小到大逐渐放大显示
  • "zoom-fade-out": 页面在屏幕中间从小到大逐渐放大并且从透明到不透明逐渐显示
  • "pop-in": 页面从屏幕右侧滑入显示,同时上一个页面带阴影效果从屏幕左侧滑出隐藏

waiting

wap2app在打开新窗口时,默认会显示waiting等待框,新webview的titleUpdate事件触发后,自动关闭waiting等待框。(titleUpdate是页面title节点解析触发的事件,详见HTML5Plus Webview的event)

等待框默认使用5+引擎的默认waiting框效果,开发者可以通过参数配置自定义效果,可配置参数包括:

  • title:可选,类型为String,等待对话框上显示的提示标题内容
  • options:可选,类型为Object,等待对话框的显示参数,设置等待框的宽、高、边距、背景等样式等;完整参数参考5+原生等待框参数

如下是一个示例,配置等待框为粉色背景、白色文字,等待提示语为“加载中”:

{  
    "webviewId": "page1",  
    "matchUrls": [  
        //url匹配规则  
    ],  
    "easyConfig":{  
        "open":{  
            "waiting":{  
                "title":"加载中...",  
                "options":{  
                    "background":"#EF5FA7",//粉色背景  
                    "color":"#ffffff"//白色文字  
                }  
            }  
        }  

    }  
}

运行结果如下:

如果M站页面响应较快,不需要显示waiting框,则可以通过配置waiting:false来禁用waiting等待框,例如:

{  
    "webviewId": "page1",  
    "matchUrls": [  
        //url匹配规则  
    ],  
    "easyConfig":{  
        "open":{  
            "waiting":false  // 禁用waiting,打开page1页面时,不显示waiting等待框  
        }  
    }  
}

Tips:
waiting常见于内容渲染慢的场景。如果内容渲染快,那么waiting圈反而碍事。
如果使用了NView模板,建议禁用waiting等待框。

quit

用户在应用首页按下back按键,会触发wap2app的退出逻辑,应用退出的相关配置在global->easyConfig->quit节点下配置。

Tips:quit节点仅支持在global下配置,不支持页面继承。

wap2app退出时,默认会弹出toast消息框,提示用户“再按一次返回键退出”,同时在toast信息中给出“反馈意见”的链接,效果图如下:

在toast消息显示时,用户可以点击“反馈意见”链接,反馈App的使用问题;开发者可以登录DCloud开发者中心查看用户反馈的问题,解决并持续改进。

wap2app可以通过配置,在应用退出的toast消息中不显示“反馈意见”的链接,方式如下:

"global": {  
    "webviewParameter": {  
        //webview相关通用配置  
    },  
    "easyConfig": {  
        "quit": {  
            "toast": {  
                "showFeedback": false //不显示“反馈意见”链接,默认为true  
            }  
        }  
    }  
}

FAQ

Q:退出时候的反馈如何去掉
A:参考上面文档中的说明,调整首页 easyConfig -> quit 的配置即可。

收起阅读 »

webviewParameter配置 - wap2app教程

教程 webviewParameter wap2app

综述

wap2app使用webview打开每个页面链接,而每个webview相关的属性设置,在对应页面的webviewParameter节点下配置,如下TODO位置:

    {  
        "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            //TODO webview相关属性在这里配置  
        },  
        "easyConfig":{}  
    }

webviewParameter节点下可配置如下子节点:

  • titleNView:原生标题栏样式配置
  • statusbar:系统状态栏样式配置
  • subNViews:NView模板配置
  • pullToRefresh:下拉刷新配置
  • appendCss:向服务端页面插入的css代码
  • appendJs:向服务端页面插入的JavaScript代码
  • tabBar:选项卡切换效果优化,目前仅支持首页底部选项卡

接下来对每个节点进行详细介绍。

titleNView

titleNView用于设置原生标题栏样式, 顾名思义,它是一个原生的NView,并且用途是顶部title。
titleNView是由原生渲染引擎渲染,而不是Webview渲染的。在窗体动画切换时可以瞬间出现,不会让页面整屏白屏。

titleNView的具体教程参考titleNView配置
如果你是第一次学习,阅读到此处时,直接点击上述链接继续学习。完毕后回到本文继续。

statusbar

系统状态栏位于手机屏幕顶端,如下图所示:

通过statusbar可以配置系统状态栏的样式,可配置的参数包括:

  • style:状态栏前景色(文字颜色)
  • background:状态栏背景色,默认应该和原生导航条背景色一致;

style

状态栏的前景色,仅支持浅色、深色两种选项,可取值如下:

  • dark:深色前景色样式(即状态栏前景文字为黑色)
  • light:浅色前景色样式(即状态栏前景文字为白色)

关于两种前景色的效果对比,参考下图所示:

注意:系统状态栏的前景色目前是App全局配置,仅可在global节点中配置,不支持在不同webview中进行覆盖。

background

若webview使用了原生导航条,则系统状态栏默认使用和原生导航条一样的背景色,此时无需再单独配置background参数;换言之,仅需在未使用原生导航条的webview中,配置background参数。

在wap2app项目中,除首页外,其它页面默认均启用了原生导航条;因此,首页需要配置background,其它页面,均无需配置。

对于首页而言,也分两种情况:

  • 首页未启用原生导航(默认):必需配置background参数,同时建议将background配置为global->webviewParameter->titleNView->backgroundColor颜色值,保持App整体风格一致;
  • 首页启用原生导航:无需配置,同时建议将statusbar节点配置为false

首页未启用原生导航条的配置示例:

{  
    "webviewId": "__W2A__m.example.com",//首页  
    "matchUrls": [  
        //url配置规则  
    ],  
    "webviewParameter": {  
        "titleNView": false,//首页默认不使用原生导航  
        "statusbar": {  
            //状态条背景色,  
            //首页不使用原生导航条,颜色值建议和global->webviewParameter->titleNView->backgroundColor颜色值保持一致  
            "background": "#f7f7f7"  
        }  
    }  
}

首页启用原生导航条配置示例:

{  
    "webviewId": "__W2A__m.example.com",//首页  
    "matchUrls": [  
        //url配置规则  
    ],  
    "webviewParameter": {  
        "titleNView": {//首页启用原生导航条  
            "backgroundColor": "#FF00FF",//导航栏背景色  
            "titleColor": "#00ffff",//标题颜色为白色  
            "titleText": "wap2app首页"  
        },  
        //若首页启用了原生导航条,则建议将首页的statusbar配置为false(或直接删除statusbar节点),这样状态条可以和原生导航条背景色保持一致;  
        "statusbar": false   

    }  
}

注意:非首页的其它页面(默认使用原生导航条),如果禁用了原生导航条,则也需要在对应页面的webviewParameter节点下配置statusbar->background,配置方式同首页逻辑。

subNViews

subNView也是原生渲染区域,它位于titleNView下方,从属于webview。
类似的技术有点像flash,内嵌在网页中,但实际是由原生引擎渲染的。
但subNView的加载速度快多了,在窗体切换动画时,subNView可以瞬间出现,而Webview则仍在慢慢经历:联网下载页面代码、构建Dom、渲染Dom等过程。因此subNView是加快web页面渲染的一大利器。如下为一个使用subNView增强后的商品详情页示例:

这样页面在一个Webview里创建了2个subNView,在页面加载动画时,subNView可以直接渲染出来,而后wap页面才慢慢渲染完毕。

DCloud为NView提供了一种前端式模板写法,可在sitemap.json中配置NView模板文件路径,编写一个模板。如下为一个示例:

    {  
        "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "subNViews": "page1.nview" //NView模板路径  
        }  
    }

关于subNView及NView模板更详细的介绍,参考:NView模板教程
NView略复杂,它不像sitemap仅仅是配置,它涉及真正编程。
不使用subNView也可以完成一个wap2app项目的基础版。
你可以一口气学完NView,也可以先做一个wap2app的基础版,然后再引入NView进一步强化体验。

appendCss

wap2app需要M站进行少量改造,比如因为使用了原生标题栏titleNView,就不再需要DIV标题栏,M站服务端应根据navigator.userAgent判断是流应用环境下,不生成(或隐藏)原来的DIV标题栏,教程参考去除M站DOM元素

这部分改造工作,建议由服务端改造,这样可以保证css尽早生效;如果服务端不方便修改,wap2app还支持通过appendCss节点向M站页面插入css代码,从而实现类似的效果。
也就是通过appendCss,可以在wap2app中直接影响wap站的渲染样式。这些css由wap2app引擎在运行时动态插入到原wap站的页面dom中,和在wap页面里写同样的css效果类似。

wap2app支持两种方式配置appendCss节点:

  • 直接编写css代码
  • 配置css文件路径

wap2app框架会智能识别配置的是代码还是文件路径,然后将对应的css代码,插入到对应的M站页面中。

直接配置css代码

如果要插入的css代码比较简单,则可以直接在sitemap.json文件中appendCss节点后编写css代码,如下:

     {  

       "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "appendCss":"#header{display:none}" //插入css代码  
        },  
        "easyConfig":{}  
    }

配置css文件路径

如果要插入的css代码比较复杂,则在sitemap.json的字符串中编写就不太方便(比如:缺少css语法提示),此时建议新建一个css文件编写需插入的css代码,然后将css文件相对路径配置到appendCss节点下即可,例如:

     {  

       "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "appendCss":"page1.append.css" //需插入的css文件路径  
        },  
        "easyConfig":{}  
    }

建议将需插入的css文件放在项目根目录下,然后遵循%webviewId%.append.css这样的命名格式;如此命名的话,无需在sitemap.json中配置appendCss节点,wap2app框架会自动扫描该文件;如上示例中css文件名为“page1.append.css”,遵循我们建议的命名格式,因此可简化配置为:

     {  

       "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            //无需配置appendCss节点,wap2app会自动扫描"page1.append.css"文件并插入  
        },  
        "easyConfig":{}  
    }

当然,开发者也可以按照自己的习惯,自定义css文件名,此时记得配置appendCss节点即可,例如:

     {  

       "webviewId":"page2",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "appendCss":"pages/page2/append.css" //自定义的css文件路径  
        },  
        "easyConfig":{}  
    }

首页css插入

因wap2app启动机制限制,目前仅支持通过css文件的方式向M站首页插入css代码;又因M站首页的webviewId就是当前应用的appid,故在HBuilder中新建wap2app项目时,会自动新建一个%appid%.append.css的文件,且名字不可修改。
开发者在%appid%.append.css里编写的样式,会直接插入到wap站首页里运行,从而影响首页的渲染效果。

appendJs

wap2app项目中,M站也会涉及部分JavaScript逻辑的改造,比如在wap2app环境下,将wap分享替换为原生分享,可以分享给微信好友、朋友圈,或者调起系统分享组件,分享到短信、邮件等。这部分增强逻辑改造,尽量由M站改造完成。如果不方便修改M站,wap2app还支持通过appendJs节点向M站页面插入JavaScript代码,从而实现类似的效果,如下为一个示例:

     {  

       "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "appendJs":"page1.append.js" //需插入的JavaScript文件路径  
        },  
        "easyConfig":{}  
    }

类似appendCss插入文件的命名机制,插入的js文件建议遵循%webviewId%.append.js规范,wap2app默认会扫描项目根目录下名字为%webviewId%.append.js的文件;若覆盖该命名规范,则无需配置appendJs节点;如上示例中js文件名为“page1.append.js”,遵循我们建议的命名格式,因此可简化配置为:

     {  

       "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            //无需配置appendJs节点,wap2app会自动扫描"page1.append.js"文件并插入  
        },  
        "easyConfig":{}  
    }

当然,开发者也可以按照自己的习惯,自定义js文件名,此时记得配置appendJs节点即可,例如:

     {  

       "webviewId":"page2",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "appendJs":"pages/page2/append.js" //自定义的js文件路径  
        },  
        "easyConfig":{}  
    }

注意:通过appendJs节点配置的JavaScript代码,虽然是在HBuilder客户端编写,但最终会运行在M站的页面中,可以操作M站的DOM结构、执行M站的业务逻辑。

appendJs插入的js,运行时机是晚于原页面的其他js的,所以开发者应尽量在原wap页面中直接修改js,减少appendJs的使用。

pullToRefresh

我们知道页面里基于div方式的下拉刷新是不流畅的,wap2app框架提供了原生的下拉刷新。
配置pullToRefresh -> support 节点就可以启用原生下拉刷新,如下:

    "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "pullToRefresh":{  
                "support":true //启用下拉刷新  
            }  
        },  
        "easyConfig":{}  
    }

当然这种下拉刷新本质是刷新一个网页,效果是一个圆圈从titleNView位置被拉下来,拉到一定程度会自动刷新页面。
一般用于list页面的配置。
如果开发者想要下拉刷新用于更新list的dom而不是刷新网页,需要在app.js中进行强化编程。

tabBar

tabBar可以对首页底部选项卡进行优化,实现选项卡切换时,仅变化内容区,选项卡区域不变。详细配置参考选项卡切换优化教程

继续阅读 »

综述

wap2app使用webview打开每个页面链接,而每个webview相关的属性设置,在对应页面的webviewParameter节点下配置,如下TODO位置:

    {  
        "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            //TODO webview相关属性在这里配置  
        },  
        "easyConfig":{}  
    }

webviewParameter节点下可配置如下子节点:

  • titleNView:原生标题栏样式配置
  • statusbar:系统状态栏样式配置
  • subNViews:NView模板配置
  • pullToRefresh:下拉刷新配置
  • appendCss:向服务端页面插入的css代码
  • appendJs:向服务端页面插入的JavaScript代码
  • tabBar:选项卡切换效果优化,目前仅支持首页底部选项卡

接下来对每个节点进行详细介绍。

titleNView

titleNView用于设置原生标题栏样式, 顾名思义,它是一个原生的NView,并且用途是顶部title。
titleNView是由原生渲染引擎渲染,而不是Webview渲染的。在窗体动画切换时可以瞬间出现,不会让页面整屏白屏。

titleNView的具体教程参考titleNView配置
如果你是第一次学习,阅读到此处时,直接点击上述链接继续学习。完毕后回到本文继续。

statusbar

系统状态栏位于手机屏幕顶端,如下图所示:

通过statusbar可以配置系统状态栏的样式,可配置的参数包括:

  • style:状态栏前景色(文字颜色)
  • background:状态栏背景色,默认应该和原生导航条背景色一致;

style

状态栏的前景色,仅支持浅色、深色两种选项,可取值如下:

  • dark:深色前景色样式(即状态栏前景文字为黑色)
  • light:浅色前景色样式(即状态栏前景文字为白色)

关于两种前景色的效果对比,参考下图所示:

注意:系统状态栏的前景色目前是App全局配置,仅可在global节点中配置,不支持在不同webview中进行覆盖。

background

若webview使用了原生导航条,则系统状态栏默认使用和原生导航条一样的背景色,此时无需再单独配置background参数;换言之,仅需在未使用原生导航条的webview中,配置background参数。

在wap2app项目中,除首页外,其它页面默认均启用了原生导航条;因此,首页需要配置background,其它页面,均无需配置。

对于首页而言,也分两种情况:

  • 首页未启用原生导航(默认):必需配置background参数,同时建议将background配置为global->webviewParameter->titleNView->backgroundColor颜色值,保持App整体风格一致;
  • 首页启用原生导航:无需配置,同时建议将statusbar节点配置为false

首页未启用原生导航条的配置示例:

{  
    "webviewId": "__W2A__m.example.com",//首页  
    "matchUrls": [  
        //url配置规则  
    ],  
    "webviewParameter": {  
        "titleNView": false,//首页默认不使用原生导航  
        "statusbar": {  
            //状态条背景色,  
            //首页不使用原生导航条,颜色值建议和global->webviewParameter->titleNView->backgroundColor颜色值保持一致  
            "background": "#f7f7f7"  
        }  
    }  
}

首页启用原生导航条配置示例:

{  
    "webviewId": "__W2A__m.example.com",//首页  
    "matchUrls": [  
        //url配置规则  
    ],  
    "webviewParameter": {  
        "titleNView": {//首页启用原生导航条  
            "backgroundColor": "#FF00FF",//导航栏背景色  
            "titleColor": "#00ffff",//标题颜色为白色  
            "titleText": "wap2app首页"  
        },  
        //若首页启用了原生导航条,则建议将首页的statusbar配置为false(或直接删除statusbar节点),这样状态条可以和原生导航条背景色保持一致;  
        "statusbar": false   

    }  
}

注意:非首页的其它页面(默认使用原生导航条),如果禁用了原生导航条,则也需要在对应页面的webviewParameter节点下配置statusbar->background,配置方式同首页逻辑。

subNViews

subNView也是原生渲染区域,它位于titleNView下方,从属于webview。
类似的技术有点像flash,内嵌在网页中,但实际是由原生引擎渲染的。
但subNView的加载速度快多了,在窗体切换动画时,subNView可以瞬间出现,而Webview则仍在慢慢经历:联网下载页面代码、构建Dom、渲染Dom等过程。因此subNView是加快web页面渲染的一大利器。如下为一个使用subNView增强后的商品详情页示例:

这样页面在一个Webview里创建了2个subNView,在页面加载动画时,subNView可以直接渲染出来,而后wap页面才慢慢渲染完毕。

DCloud为NView提供了一种前端式模板写法,可在sitemap.json中配置NView模板文件路径,编写一个模板。如下为一个示例:

    {  
        "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "subNViews": "page1.nview" //NView模板路径  
        }  
    }

关于subNView及NView模板更详细的介绍,参考:NView模板教程
NView略复杂,它不像sitemap仅仅是配置,它涉及真正编程。
不使用subNView也可以完成一个wap2app项目的基础版。
你可以一口气学完NView,也可以先做一个wap2app的基础版,然后再引入NView进一步强化体验。

appendCss

wap2app需要M站进行少量改造,比如因为使用了原生标题栏titleNView,就不再需要DIV标题栏,M站服务端应根据navigator.userAgent判断是流应用环境下,不生成(或隐藏)原来的DIV标题栏,教程参考去除M站DOM元素

这部分改造工作,建议由服务端改造,这样可以保证css尽早生效;如果服务端不方便修改,wap2app还支持通过appendCss节点向M站页面插入css代码,从而实现类似的效果。
也就是通过appendCss,可以在wap2app中直接影响wap站的渲染样式。这些css由wap2app引擎在运行时动态插入到原wap站的页面dom中,和在wap页面里写同样的css效果类似。

wap2app支持两种方式配置appendCss节点:

  • 直接编写css代码
  • 配置css文件路径

wap2app框架会智能识别配置的是代码还是文件路径,然后将对应的css代码,插入到对应的M站页面中。

直接配置css代码

如果要插入的css代码比较简单,则可以直接在sitemap.json文件中appendCss节点后编写css代码,如下:

     {  

       "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "appendCss":"#header{display:none}" //插入css代码  
        },  
        "easyConfig":{}  
    }

配置css文件路径

如果要插入的css代码比较复杂,则在sitemap.json的字符串中编写就不太方便(比如:缺少css语法提示),此时建议新建一个css文件编写需插入的css代码,然后将css文件相对路径配置到appendCss节点下即可,例如:

     {  

       "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "appendCss":"page1.append.css" //需插入的css文件路径  
        },  
        "easyConfig":{}  
    }

建议将需插入的css文件放在项目根目录下,然后遵循%webviewId%.append.css这样的命名格式;如此命名的话,无需在sitemap.json中配置appendCss节点,wap2app框架会自动扫描该文件;如上示例中css文件名为“page1.append.css”,遵循我们建议的命名格式,因此可简化配置为:

     {  

       "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            //无需配置appendCss节点,wap2app会自动扫描"page1.append.css"文件并插入  
        },  
        "easyConfig":{}  
    }

当然,开发者也可以按照自己的习惯,自定义css文件名,此时记得配置appendCss节点即可,例如:

     {  

       "webviewId":"page2",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "appendCss":"pages/page2/append.css" //自定义的css文件路径  
        },  
        "easyConfig":{}  
    }

首页css插入

因wap2app启动机制限制,目前仅支持通过css文件的方式向M站首页插入css代码;又因M站首页的webviewId就是当前应用的appid,故在HBuilder中新建wap2app项目时,会自动新建一个%appid%.append.css的文件,且名字不可修改。
开发者在%appid%.append.css里编写的样式,会直接插入到wap站首页里运行,从而影响首页的渲染效果。

appendJs

wap2app项目中,M站也会涉及部分JavaScript逻辑的改造,比如在wap2app环境下,将wap分享替换为原生分享,可以分享给微信好友、朋友圈,或者调起系统分享组件,分享到短信、邮件等。这部分增强逻辑改造,尽量由M站改造完成。如果不方便修改M站,wap2app还支持通过appendJs节点向M站页面插入JavaScript代码,从而实现类似的效果,如下为一个示例:

     {  

       "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "appendJs":"page1.append.js" //需插入的JavaScript文件路径  
        },  
        "easyConfig":{}  
    }

类似appendCss插入文件的命名机制,插入的js文件建议遵循%webviewId%.append.js规范,wap2app默认会扫描项目根目录下名字为%webviewId%.append.js的文件;若覆盖该命名规范,则无需配置appendJs节点;如上示例中js文件名为“page1.append.js”,遵循我们建议的命名格式,因此可简化配置为:

     {  

       "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            //无需配置appendJs节点,wap2app会自动扫描"page1.append.js"文件并插入  
        },  
        "easyConfig":{}  
    }

当然,开发者也可以按照自己的习惯,自定义js文件名,此时记得配置appendJs节点即可,例如:

     {  

       "webviewId":"page2",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "appendJs":"pages/page2/append.js" //自定义的js文件路径  
        },  
        "easyConfig":{}  
    }

注意:通过appendJs节点配置的JavaScript代码,虽然是在HBuilder客户端编写,但最终会运行在M站的页面中,可以操作M站的DOM结构、执行M站的业务逻辑。

appendJs插入的js,运行时机是晚于原页面的其他js的,所以开发者应尽量在原wap页面中直接修改js,减少appendJs的使用。

pullToRefresh

我们知道页面里基于div方式的下拉刷新是不流畅的,wap2app框架提供了原生的下拉刷新。
配置pullToRefresh -> support 节点就可以启用原生下拉刷新,如下:

    "webviewId":"page1",  
        "matchUrls": [  
            //url 匹配规则  
        ],  
        "webviewParameter": {  
            "pullToRefresh":{  
                "support":true //启用下拉刷新  
            }  
        },  
        "easyConfig":{}  
    }

当然这种下拉刷新本质是刷新一个网页,效果是一个圆圈从titleNView位置被拉下来,拉到一定程度会自动刷新页面。
一般用于list页面的配置。
如果开发者想要下拉刷新用于更新list的dom而不是刷新网页,需要在app.js中进行强化编程。

tabBar

tabBar可以对首页底部选项卡进行优化,实现选项卡切换时,仅变化内容区,选项卡区域不变。详细配置参考选项卡切换优化教程

收起阅读 »

【交流分享】局域网ipad应用解决方案-APP部分

技术分享

最近在做一个现场订货的项目,分享交流下,需求是这样的:
秀台现场预订明年新款,为防止资料泄漏,会场无法访问外网,均使用ipad连接自建服务器预订商品,超过600台客户端同时连接,实时推送消息、自动切换至台上model展示商品,实时查看各种订货数据报表图表,包含4-5种不同权限角色操作。

硬件设备这里暂时不说,有专业的局域网搭建解决方案,来说APP如何保证所有客户端能保证流畅即时的使用。

由于是局域网,所以推送肯定就不能使用个推之类的外网推送,那就只有websocket(目前使用ASP .NET SignalR),登录后创建连接,实时推送通告。
自动切换也是如此,websocket连接所有客户端(包括主讲人),主讲人切换商品传给服务器,其他ipad获取到当前商品id及主题自动打开指定商品详情。

同时连接了600+ ipad那数据的响应就成了大问题,大量的商品图片已经是相当大的数据量,所以图片采用本地化机制,APP中接口返回的所有图片地址初始均为相对路径,而修改过的图片则由服务端记录统一返回绝对路径访问线上图片。(第一次访问线上图片下载至本地,告知服务端,后续继续访问本地图片)
copy服务器图片文件夹至APP,这样APP的大小就达到了500M以上。然后使用企业证书离线打包APP,自建本地服务器应用托管平台,这样APP的下载安装就变成了局域网传输,只受限于服务器的吞吐量,经测试单ipad下载安装APP不到一分钟可以安装完成(中间包括了苹果检测安装)。

做了上面这些,基本就腾出了足够的带宽来处理其他接口数据。接下来就是些常规的大数据分页分段处理,后台服务器缓存等等,目前仍在继续优化性能中。。。

各位大神如有类似的优化方案,欢迎交流分享。另附上成品小test视频...

继续阅读 »

最近在做一个现场订货的项目,分享交流下,需求是这样的:
秀台现场预订明年新款,为防止资料泄漏,会场无法访问外网,均使用ipad连接自建服务器预订商品,超过600台客户端同时连接,实时推送消息、自动切换至台上model展示商品,实时查看各种订货数据报表图表,包含4-5种不同权限角色操作。

硬件设备这里暂时不说,有专业的局域网搭建解决方案,来说APP如何保证所有客户端能保证流畅即时的使用。

由于是局域网,所以推送肯定就不能使用个推之类的外网推送,那就只有websocket(目前使用ASP .NET SignalR),登录后创建连接,实时推送通告。
自动切换也是如此,websocket连接所有客户端(包括主讲人),主讲人切换商品传给服务器,其他ipad获取到当前商品id及主题自动打开指定商品详情。

同时连接了600+ ipad那数据的响应就成了大问题,大量的商品图片已经是相当大的数据量,所以图片采用本地化机制,APP中接口返回的所有图片地址初始均为相对路径,而修改过的图片则由服务端记录统一返回绝对路径访问线上图片。(第一次访问线上图片下载至本地,告知服务端,后续继续访问本地图片)
copy服务器图片文件夹至APP,这样APP的大小就达到了500M以上。然后使用企业证书离线打包APP,自建本地服务器应用托管平台,这样APP的下载安装就变成了局域网传输,只受限于服务器的吞吐量,经测试单ipad下载安装APP不到一分钟可以安装完成(中间包括了苹果检测安装)。

做了上面这些,基本就腾出了足够的带宽来处理其他接口数据。接下来就是些常规的大数据分页分段处理,后台服务器缓存等等,目前仍在继续优化性能中。。。

各位大神如有类似的优化方案,欢迎交流分享。另附上成品小test视频...

收起阅读 »