切换深色模式
THING.UE.UWebView API 文档 进阶
前言
在实际项目应用中会遇到要在场景中创建几百甚至上千个顶牌,且样式不同,如果每一个顶牌都创建一个THING.Webview会造成严重的性能消耗。 这是因为,在ThingUE中,每创建一个Webview就创建一个内置浏览器进程,进程数量多了会出现帧率下降等情况。当进程数达到一定数量时,甚至出现显存溢出而导致程序崩溃。 上图是创建了几个webview后,多出来的CEF进程。
这里提供一种创建大量顶牌的优化方案。
优化方案
这里采用类似图集资源(Atlas)的形式,图集(Atlas)也称作 Sprite Sheet,是游戏开发中常见的一种美术资源。图集是通过专门的工具将多张图片合并成一张大图。项目中采用雪碧图即可。
- 将所有的顶牌元素(图标/图标+文字)都绘制到一个html页面中,即制作一张雪碧图。
- 在雪碧图的页面创建JavaScript脚本,用来拆分小图
- 在ThingUE中创建一个THING.UE.WebView,用来渲染这张雪碧图。
- 在THING.UE.WebView直接调用JavaScript脚本,获取到拆分小图的结果
- 根据获取到的结果,创建THING.Marker,并设置每个Marker的fixedSize 按上述步骤,雪碧图页面完成对小图的拆分,利用WebView可直接调用页面js特性,直接获取到小图的锚点信息,整个过程做到性能消耗最低。 下图是WebView初始化及调用html页面js方法的流程
雪碧图拆分效果
雪碧图显示在单个Marker上 | 雪碧图拆分后显示在多个Marker上 |
---|---|
![]() | ![]() |
创建雪碧图
页面可以是静态或动态页面
创建js脚本,用来拆分页面小图
实例代码
javascript
//拆分小图的方法,这里的参数obj是ThingUE的Webview传过来的参数
function getHtmlElements(obj) {
//window.ue是ThingUE中的Webview对象,只要是用Webview访问页面,window.ue便会存在,且window.ue被创建是在Webview被创建并且打开页面之后。
if (window.ue && window.ue[obj]) {
//获取页面小图的大小和位置信息,准备发送给ThingUE使用
const icons = document.querySelectorAll('div.icon');
let rects = [];
icons.forEach(icon => {
let box = icon.getBoundingClientRect();
let rect = {
left: box.left,
right: box.right,
top: box.top,
bottom: box.bottom,
height: box.height,
width: box.width
}
rects.push(rect);
});
//访问到obj对象,并调用response方法将拆分完的数据传给webview,这将触发webView.executeJavascript函数的回调。
window.ue[obj].response(JSON.stringify(rects));
}
}
创建Webview
- 创建一个webview
- 在创建完成的回调里调用executeJavascript方法,获取到雪碧图中每个小图的位置、大小等数据
- 遍历小图数据,创建Marker,调用webview.setWindow方法指定每个Marker都显示这个webview。
- 设置Marker的fixedSize为获取到的小图的size;设置border为小图在大图中的锚点: [left,top,right,bottom]
示例代码如下,这里调用是上文示例代码中的getHtmlElements方法。executeJavascript方法有三个参数
- 参数一:要调用的页面的js方法,getHtmlElements方法里传的参数要和executeJavascript方法的第三个参数一致,且要小写。
- 参数二:页面的js方法执行完的回调,由参数三触发
- 参数三:html中的回调路由器对象,在页面中可通过window.ue访问,该对象提供了response方法,调用该方法,页面可以将json字符串传给webview。具体使用方法参见上文的html页面的js脚本示例。
javascript
//雪碧图的地址,这里是ThingUE的testcase里的一个示例页面
let url = path.join(__dirname, '../../Modules/WebView/htmlPage/views/webview/index.html');
const webView = new THING.UE.UWebView({
domWidth: 960,
domHeight: 480,
url,
complete: (url) => {
//executeJavascript方法是Webview调用页面里的js方法,回调里是页面方法返回来的值,该方法要在创建webview完成的回调里执行
//window.getHmlElements方法是页面端写的,用来获取到小图的rect信息
webView.executeJavascript(`
window.getHtmlElements(\'page1\');
`, (str) => {
let datas = JSON.parse(str);
for (let i = 0; i < datas.length; i++) {
const divRect = datas[i];
//每个小图的大小
let size = [divRect.width, divRect.height];
//每个小图在大图中的锚点信息,是一个数组,存储的是小图 [left,top,right,bottom]占大图的比例
let border2 = [divRect.left / webView.domWidth, divRect.top / webView.domHeight, divRect.right / webView.domWidth, divRect.bottom / webView.domHeight];
let marker = new THING.Marker({
name: "webviewmarker1",
position: [i % 6 * 10 - 50, 20, Math.floor(i / 6) * 10],
scale: [10, 10, 10],
pivot: [0, 0],
alwaysOnTop: true,
complete: function ({ object }) {
object.node.renderer.renderLayer = THING.UE.URenderLayer.WebView;
// 设置当前marker可以作为webview输入窗口
webView.setWindow(object);
// 设置webview纹理
object.node.style.setImage("Map", webView.resource);
// 设置Marker固定尺寸,设置成渲染div的尺寸
object.getBodyNode().fixedSize = size;
// 设置div在dom中的锚点 [left, top , right, bottom]
object.node.style.border = border2;
},
});
}
}, 'page1');
}
});