之前基于Jquery mobile做了一个Chrome app,就在要给客户做showcase的时候,chrome强制升级manifest_version到2(http://developer.chrome.com/extensions/manifestVersion.html),而这个version基于安全考虑做了一些限制,导致我的chrome app无法运行,具体限制可见:http://developer.chrome.com/extensions/contentSecurityPolicy.html。对于我的app主要有以下两个影响点:
限制dom元素上直接onclick 限制new Function这两点对于我来说比较棘手。
1)去onclick
由于之前写js不规范,为了传参数方便,也由于存在动态创建dom的需求,所以就直接onclick,整个app有多达十几个onclick,比如:
var item = ""+data.data+"";
$(item).insertAfter($("#projectListTitle"));
这里给我出的难题是这些dom是在某种场景下创建出来的dom,很难在统一的做事件侦听,再比如:
Assign CR这里的难题是这段代码是模版里的,参数是在模版渲染时才能确定的,很难在js事件侦听里传参。并且以上问题在原有代码里存在很多,需要有个一劳永逸的方法来解决。
幸好,jquery很强大,一方面它提供了很好的selector,能让我很方便的一处监听所有需要处理的dom,另一方面,它有一个delegate的机制,也就是说除了能直接在dom上进行监听外,还能让这个dom监视它的子dom,能实现当子dom创建时再监听事件的功能,具体可见jquery.on api(http://api.jquery.com/on/)。于是,我给出了一个一劳永逸的方法:
$(document).ready(function() {
$("div[data-role='page']").on("click", "a", function(event) {
if($(this).attr("cf")){
var funName = $(this).attr("cf");
if(funName.indexOf(".") == -1){
window[funName]($(this).attr('cp1'),$(this).attr('cp2'));
}else{
var funNames = funName.split(".");
window[funNames[0]][funNames[1]]($(this).attr('cp1'),$(this).attr('cp2'));
}
}
});
});
然后,改写所有用到onclick的点,比如:
Assign CR
其中,cf,cp1和cp2分别对应着onclick监听处理函数名和参数名,是自定义属性,只是为了传参,当然也有更优雅的方式,不过这不是这里的重点。
2)去new Function
如果只是简单的使用new Function还好办,不过我这里不是直接使用了new Function,而是引用的jquery template里面用到了new Function,并且这是做模版的核心(通过动态function来渲染模版),具体用到的地方如下所示:
// Generate a reusable function that will serve to render a template against data
function buildTmplFn( markup ) {
return new Function("jQuery","$item",
......
)}解决这个问题要么是换模版方案,要么就是使用chrome提供的sandbox特性,由于应用模版的地方较多,换模版的成本太大,所以只好看看这个sandbox能否解决我的问题。使用方法可见:http://developer.chrome.com/trunk/apps/manifest.html#sandbox
于是乎,我照葫芦画瓢通过sandbox来改写使用了模版的地方。
1. 首先新建sandbox.html,把模版挪过来
2. 在sandbox.html,添加模版渲染的请求侦听:
其中$( "#"+tmpl ).tmpl( data ).wrap('').parent().html()是由于$( "#"+tmpl ).tmpl( data )返回的是jquery的dom,sandbox是基于HTML5 web worker来做的,它并不是同享内存,所以不能传递dom,这里只好先把dom转为html,然后在主页面里通过html创建dom。
3. 在主页面里添加隐藏的iframe来向sandbox发请求
var message = {'data':data,'tmpl':'crFilterTemplate'};
document.getElementById('theFrame').contentWindow.postMessage(message, '*'); 4. 在主页面监听message,取得模版渲染后html,并创建dom
window.addEventListener('message', function(event) {
var data = event.data.result.data;
var dataRendered = event.data.result.dataRendered;
var tmpl = event.data.result.tmpl;
window[tmpl+'Render'](data, dataRendered);
});
function crDetailTemplateRender(data, dataRendered) {
$(dataRendered).appendTo(document.body);
$("#crDetailPage").attr( "data-" + $.mobile.ns + "external-page", true ).one( 'pagecreate', $.mobile._bindPageRemove );
$.mobile.changePage( "#crDetailPage", { transition: "flip"} );
}
升级manifest_version本来没在工作计划之内,是突然冒出的拦路虎,不过也给自己提了个醒,一旦基于某个平台上做事情,一定得多关注这个平台的游戏规则,不然陷阱重重啊 |
|