论egret的坑
栏目: JavaScript · 发布时间: 6年前
内容简介:功能:实现点击播放动画,播放动画后跳转到新标签页面这样是会被认为不是用户手动触发的,是会被浏览器默认拦截的,不要写在扩展,像这类需要用户手动触发的,不要写在事件分发里边,比如
1. Tween
坑
功能:实现点击播放动画,播放动画后跳转到新标签页面
this.addEventListener(egret.TouchEvent.TOUCH,()=>{ var tw = egret.Tween.get(... tw.to({...},150) .call(()=>{ window.open("http://www.xx/xxx.html", '_blank'); }); } , this);
这样是会被认为不是用户手动触发的,是会被浏览器默认拦截的,不要写在 call
里边,但是可以写在 settimeout
里边
setTimeout(function () { window.open("http://www.xx/xxx.html", '_blank'); })
扩展,像这类需要用户手动触发的,不要写在事件分发里边,比如
let handler: egret.EventDispatcher = new egret.EventDispatcher(); handler.addEventListener(type,()=>{ ... }, this);
同样,声音播放也是需要用户手动触发的,如果是游戏的话,可以加一个开始按钮,然用户点击开始按钮再加入游戏,其他情况也一样,可以搞个什么弹窗或者提示之类的诱导用户点击,然后在点击事件里边加上声音播放
2. default.res.json
坑
比如要实现多语言功能,可以实现配置多个 res
文件,然后根据不同的语言选择导入不同的res文件。
看上去很正常,可是如果要实现语言动态切换,那效果真的是相当的不理想。
比如:
多语言的图片,代码如下:
var parant = this.parent; await RES.loadGroup("loading"); const loadingView = new LoadingUI(); parant.stage.addChild(loadingView); this.removeSelf(); RES.destroyRes(ResMap[oldLan], true); RES.destroyRes("ui_t_bin", true); RES.destroyRes("btn_lang_json", true); await RES.loadConfig(ResMap[language], "resource/"); await RES.loadGroup("lang_text", 0, loadingView); //初始化多语言文本 var game = initGame(); parant && parant.addChild(game); loadingView.parent && loadingView.parent.removeChild(loadingView); RES.destroyRes("loading");
本地测试加载还好,能够正常使用,可是在线的情况并不怎么好用,切换一次还行,再切换就不行了
解决方法:
第一种:暴力解决,直接刷新页面,同时加上多语言参数
这种方法不推荐,也就不多讲了
第二种:秒切换,但是费时费力
首先:所有资源共用一个资源配置文件: default.res.json
,但这时候存在相同键值对就会有警告,其实不碍事
其次,界面配置多状态:
多状态
可以根据不同语言定制不同界面,但是这种方法比较费时费力,扩展相对不易,但是呈现的效果确是最好的
同时,之前一些禁忌的东西就要使用了,代码如下:
<e:Button name="btn_1" label="" x="105" y="14" includeIn="en"> <e:skinName> <e:Skin states="up,down,disabled"> <e:Image width="100%" height="100%" source="btn_en_json.btn_1_png" source.down="btn_en_json.btn_1_png" source.disabled="btn_en_json.btn_1_png" /> <e:Label id="labelDisplay" horizontalCenter="0" verticalCenter="0" /> </e:Skin> </e:skinName> </e:Button>
这里加了 btn_en_json
前缀,这是精灵图片的方式,开发的时候最好不要用这种方式,但是有时候确是比较好的方式, includeIn
可以保证不同状态下显示不同的按钮
由于不同界面的按钮不能够共用,这时候就会涉及到多个 id
的问题,由于 id
不能重复,所以只能用 name
。
获取组件的方式:
this.btn_1 = <eui.Button>this.grp_1.getChildByName("btn_1");
可以看出来,必须在button外边包一层 group
,这也是比较坑的地方
扩展:其实多状态还有很多用途,涉及到不同条件需要展示不同效果的,都可以用多状态来实现
3. 多状态的坑
多状态界面设计本省就很坑了,比如某些不熟悉的人,喜欢这样定义状态:
··· states="[zh],[en],[zh-Hant]">
那么坑就很明显了,如 [zh].visible="true"
是会有问题的
还有设计的时候所有状态下最好所有组件都到位,不然容易出现什么时候界面上的某个东东就不见了的诡异情况
但是,但是这样就是坑吗?
最最最坑的是:
与 eui.ItemRenderer
的重用的情况:
export class Screen extends eui.ItemRenderer { ... public constructor(skinName?: string) { super(); this.skinName = skinName; } protected dataChanged(): void {} ... }
看上去,代码好好的。。。可是可是!!!!
鼠标点击之后会还原到默认状态!!!!坑!!!
这时候只能在外面再嵌套一层,也就是写两个界面,其中多状态的那个界面以控件的方式引入到第二个界面,同时 eui.ItemRenderer
也由第二个界面继承,这个坑让我心情糟透了,就不在这里举例代码了
4. http
重连坑
服务器用的 golang
,可是每次请求都会发送两篇,实在是坑爹至极,可是这个问题居然没有能够解决,失落。。。
为了弥补小小的失落,还是决定自己写一套吧(代码放在最底部),下面的就是摘自网上的,然后又 js
改成的 ts
版 ajax
:
//使用 ajax({ url: url, method: "GET", type: "text", async: true, timeout: 1000, onSuccess: function (data) { //请求成功 }, onError: function (_error) {} }).getText();
有点是比egret稳定,脱离egret环境也可以使用哦
5. removeChild
坑
提供的 DisplayObject 必须是调用者的子级
看了这句话,其实内心是崩溃的。。。因为很多时候,你根本不知道哪里错了,这时候还得一个个去查找用了 removeChild
的地方
解决方法:
/** * 移除自身 */ public removeSelf() { this.parent && this.parent.removeChild(this); }
这样貌似就可以了。。。但是最好不要写在方法的局部函数里边,这样很容易出问题,比如异步执行、事件调用这些,即使你用了parent可能也防不住错误,然后只能让崩溃来得更加猛烈些了。。。
6. exml
坑
复制粘贴: id
自增不算坑,但是带字符串的控件复制粘贴组件后字符串里边的 \n
就没了
list
:由于 list
所有项都是等宽高的,所以如果需要设置不同高度的列表,就需要用 DataGroup
点击事件被拦截:设置 group
的 touchThrough
为 true
如果希望 group
超出部分被遮挡,就应该设置 scrollEnable
为 true
最坑的是,自定义控件设置宽高为 100%
,编译后可能报错,这时候应该用 left="0" right="0" top=0" bottom="0"
替代
自定义控件属性警告,虽然能成功但是很不爽:
[warning] EXML解析错误 ScreenSkin: 节点上不存在名为'preview'的属性,或者该属性没有初始值:... [warning] EXML解析错误 ScreenSkin: 无法将'string'类型的值赋给属性:'preview:undefined'
在 exml
是这样写的:
<e:Skin class="ScreenSkin" xmlns:e="http://ns.egret.com/eui" xmlns:w="http://ns.egret.com/wing" xmlns:game="ex.*"> <ex:BaseScreen preview="true" /> </e:Skin>
在 BaseScreen
中如下定义:
export class BaseScreen{ private preview:boolean = false; }
结束
以下是 Ajax.ts
的代码:
namespace http { const doc = window.document; const OBJ: string = "OBJ"; const STR: string = "string"; class AjaxError { private name: string; private msg: string | null; public constructor(msg: string | null) { this.name = "Ajax错误"; this.msg = msg; } public getName(): string { return this.name; } public getMsg(): string | null { return this.msg; } } export class Ajax { private option; private request; private to: any[]; public constructor(option) { this.option = { url: option.url || "",//数据源地址 method: option.method || "GET",//请求方法[POST、HEAD...] data: option.data || null,//要发送给服务器的数据 async: option.async || true,//是否是异步请求 type: option.type || "text",//返回数据后,将数据转换为指定的类型.(text,js,xml,html) timeout: option.timeout || 10000,//请求超时,默认为十秒 cache: option.cache || false,//是否从缓存中取数据(如果浏览器已缓存) onSuccess: option.onSuccess || function (result) { },//请求成功后执行的函数(处理返回结果) onError: option.onError || function () { },//请求出错调用的函数 onComplete: option.onComplete || function () { },//请求完成后(无论成功与否)都执行的函数 showStatus: option.showStatus || function () { }//显示请求状态 }; this.to = []; this.request = this.create(); this.fix(this.option); } private create() { return new XMLHttpRequest(); } private parseToQueryString(obj) {//将数组或对象序列化 if (typeof obj === STR) return obj; var s: Array<any> = []; if (obj instanceof Array) {//假定为数组 let arr: Array<any> = <Array<any>>obj; for (var i = 0; i < obj.length; i++) s.push(arr[i].name || i + "=" + arr[i]); } else { for (var j in obj) s.push(j + "=" + obj[j]); } return s.join("&"); }; private parseToObject(str: string) {//将查询字符串转化成对象 if (typeof str == OBJ) return str; var set = {}; var strArr: string[] = str.split("&"); var item: string[]; for (var i = 0; i < strArr.length; i++) { if (strArr[i].indexOf("=") > 0) { item = strArr[i].split("="); set[item[0]] = item[1]; } } return set; }; private append(url: string, param: string): string { if (url.indexOf("?") < 0) { return url + "?" + param; } else { if (/\?$/.test(url)) { return url + param; } else { return url + "&" + param; } } } private fix(p) { if (p.data) { p.data = this.parseToQueryString(p.data); } if (p.method.toUpperCase() == "GET" && p.data) { p.url = this.append(p.url, p.data); } if (!p.cache) { p.url = this.append(p.url, "abkjfjk=" + (new Date().getTime()) + "jrejhjdd"); } } private isOK(r) { try { return !r.status && location.protocol == "file:" || (r.status >= 200 && r.status < 300) || r.status == 304 || navigator.userAgent.indexOf("Safari") >= 0 && r.status == undefined; } catch (e) { } return false; } private httpData(r, type: string) { var res = type; if (!res) { var ct = r.getResponseHeader("Content-Type"); if (/xml/i.test(ct)) res = "xml"; else if (/JavaScript/i.test(ct)) res = "js"; else res = ""; } switch (res) { case "xml": return r.responseXML.documentElement; case "js": return eval("(" + r.responseText + ")"); default: return r.responseText; } } private getObj(id) { return typeof id === OBJ ? id : doc.getElementById(id); } public appendTo(target) {//将返回的结果加到指定的目标[id或DOM对象] if (!this.to) this.to = []; this.to.push({ "target": this.getObj(target), "type": this.option.type }); return this; } public open() { try { this.request["open"](this.option.method, this.option.url, this.option.async); if (/POST/i.test(this.option.method)) { this.request["setRequestHeader"]("Content-Type", "application/x-www-form-urlencoded"); if (this.request["overrideMimeType"]) this.request["setRequestHeader"]("Connection", "close"); } } catch (e) { throw new AjaxError(e.message) } return this; } public send() { try { this.request["send"](this.option.data); } catch (e) { throw new AjaxError(e.message); } return this; } public stop() { try { this.request["abort"](); } catch (e) { throw new AjaxError(e.message) } return this; } public getText(fn?) { return this.exe({ "onSuccess": fn, "type": "text" }); }//fn可选 public getXML(fn?) { return this.exe({ "onSuccess": fn, "type": "xml" }); } public getScript(fn?) { return this.exe({ "onSuccess": fn, "type": "js" }); } public getHTML(fn?) { return this.exe({ "onSuccess": fn, "type": "html" }); } public exe(options) { if (options.onSuccess) this.option.onSuccess = options.onSuccess; if (options.onError) this.option.onError = options.onError; if (options.onComplete) this.option.onComplete = options.onComplete; if (options.showStatus) this.option.showStatus = options.showStatus; if (options.type) this.option.type = options.type; try { var isTimeout = false, cur = this.open(); var timer = setTimeout(function () { isTimeout = true; cur.stop(); cur.option.onError(new AjaxError("请求超时")); }, cur.option.timeout); var self = this; this.request["onreadystatechange"] = function () { cur.option.showStatus(cur.request["readyState"]); if (cur.request["readyState"] == 4 && !isTimeout) { try { if (self.isOK(cur.request)) {//成功完成 var t = self.httpData(cur.request, cur.option.type); if (cur.to && cur.to.length > 0) { for (var i = 0; i < cur.to.length; i++) { if (cur.to[i].type && cur.to[i].type == "html") cur.to[i].target.innerHTML += t; else cur.to[i].target.appendChild(doc.createTextNode(t)); } } cur.option.onSuccess(t); } else { cur.option.onError(new AjaxError("请求未成功完成")); } } catch (et) { cur.option.onError(new AjaxError(et.message)); } finally { cur.option.onComplete(); // cur.request = null; clearTimeout(timer); } } }; this.send(); } catch (e) { console.error(e); this.option.onError(new AjaxError(e.message)); } finally { return this; } } } } function ajax(option) { return new http.Ajax(option); }
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTML5移动Web开发指南
唐俊开 / 电子工业出版社 / 2012-3-1 / 59.00元
HTML5移动Web开发指南,ISBN:9787121160837,作者:唐俊开 著一起来看看 《HTML5移动Web开发指南》 这本书的介绍吧!
CSS 压缩/解压工具
在线压缩/解压 CSS 代码
UNIX 时间戳转换
UNIX 时间戳转换