之前基于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主要有以下两个影响点:
这两点对于我来说比较棘手。
1)去onclick
由于之前写js不规范,为了传参数方便,也由于存在动态创建dom的需求,所以就直接onclick,整个app有多达十几个onclick,比如:
var item = "<li data-theme=\"c\"><a data-transition=\"slide\" onclick=\"loadViewList('"+data.data[i]+"')\">"+data.data[i]+"</a></li>"; $(item).insertAfter($("#projectListTitle"));
<li><a id='loadAssignToButton' onclick='loadAssignTo(${id})'>Assign CR</a></li>这里的难题是这段代码是模版里的,参数是在模版渲染时才能确定的,很难在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')); } } }); });
<li><a id='loadAssignToButton' cf='loadAssignTo' cp1='${id}'>Assign CR</a></li>
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,添加模版渲染的请求侦听:
<script> // Set up message event handler: window.addEventListener('message', function(event) { var data = event.data.data; var tmpl = event.data.tmpl; var dataRendered = $( "#"+tmpl ).tmpl( data ).wrap('<div>').parent().html(); var result = {'data':data,'dataRendered':dataRendered,'tmpl':tmpl}; event.source.postMessage({'result': result}, event.origin); }); </script>
3. 在主页面里添加隐藏的iframe来向sandbox发请求
<iframe id="theFrame" src="sandbox.html" style="display: none;"></iframe> 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"} ); }