NView数据绑定
除了标准字符串模式的文本、属性设置外,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教程
在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教程
什么是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项目中,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教程
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的主要工作就是:
- 规整M站的URL,创建pages规则,并把各个url页面匹配到不同page中。
- 针对该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的主要工作就是:
- 规整M站的URL,创建pages规则,并把各个url页面匹配到不同page中。
- 针对该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打开应用市场
有时候应用内需要让用户跳转到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
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教程
综述
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教程
综述
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视频...
收起阅读 »















