前端开发学习之——利用模板实现涉及url问题时的bug分析及解决(chrome源码)
例如我们要实现如下页面,其中历史页面列表想来自底层返回的数据,此处用testData代替:
最初我写的实现代码如下:
html文件:
<!doctype html> <html class="starting-up" i18n-values="dir:textdirection; lang:language"> <head> <meta charset="utf-8"> <title i18n-content="title"></title> <link rel="stylesheet" type="text/css" href="last_tabs_list.css"> <link rel="stylesheet" href="cdosbrowser://resources/css/tree.css"> <link rel="stylesheet" href="cdosbrowser://resources/css/widgets.css"> <script src="cdosbrowser://resources/js/cr.js"></script> <script src="cdosbrowser://resources/js/cr/ui.js"></script> <script src="cdosbrowser://resources/js/cr/ui/tree.js"></script> <script src="cdosbrowser://resources/js/util.js"></script> <script src="cdosbrowser://resources/js/icon.js"></script> </head> <body> <div class="container"> <div class="nav_container"> <div class="top_nav"> <p>上次未关闭的页面</p> </div> </div> <div class="content"> <div class="content_top"> <div class="select_all_container"> <input type="checkbox" id="check_all"></input> <span class="select_all">全选</span> </div> <div class="open_selected_tabs"> <button class="open_all_selected" id="open_all_selected">打开选中页面</button> </div> </div> <div id="tabs_list" class="tabs_list"> <div class="tab_container" id="tab_{{index}}"> <input type="checkbox" class="check" id="check_{{index}}"></input> <div class="favicon" style="background-image: {{bgimage}};"></div> <!--<div class="favicon" style='background-image: {{bgimage}};'></div>--> <div class="title"> <a href="{{url}}" target="_blank" title="{{title}}" focus-type="title" tabindex="0">{{title}}</a> </div> </div> </div> </div> </div> <script src="last_tabs_list.js"></script
js文件:
var testData = [ { title: "历史记录", url: "cdosbrowser://history-frame/#range=3&offset=3" }, { title: "cdosbrowser://help", url: "cdosbrowser://help/" }, { title: "百度一下,你就知道", url: "https://www.baidu.com/" }, { title: "爱奇艺-全球领先的在线视频网站-海量正版高清视频在线观看", url: "http://www.iqiyi.com/" } ] function checkAll(){ console.log("checkEl.length="+checkEl.length); if(checkAllEl.checked){ for(var i=0; i<checkEl.length; i++){ checkEl[i].checked = true; console.log(checkEl.length); console.log(checkEl[i].checked); } }else{ for(var i=0; i<checkEl.length; i++){ checkEl[i].checked = false; $("open_all_selected").disabled = true; } } updateButtonStatus(); } function tabsListDOM(data){ var tabsListTemplate = $("tabs_list").innerHTML; var wrap=[]; for(var i=0; i<data.length; i++){ var backgroundImage = cr.icon.getFavicon(data[i].url); var _tabsListTemplate = tabsListTemplate.replace(/{{index}}/g,i) .replace(/{{url}}/,data[i].url) .replace(/{{bgimage}}/,backgroundImage) .replace(/{{title}}/g,data[i].title); wrap.push(_tabsListTemplate); } $("tabs_list").innerHTML = wrap.join(''); //console.log("wrap.join('')="+wrap.join('')); //console.log("$('tabs_list').innerHTML="+$("tabs_list").innerHTML); checkEl = $("tabs_list").querySelectorAll(".check"); checkAllEl = $("check_all"); checkAllEl.checked =true; checkAll(); } tabsListDOM(testData); function updateButtonStatus(){ var anyChecked = document.querySelectorAll('#tabs_list input:checked') .length!= 0; $('open_all_selected').disabled = !anyChecked; console.log("anyChecked="+anyChecked); } function checkOne(){ var flag = true; for(var i=0; i<checkEl.length; i++){ if(!checkEl[i].checked){ flag = false; } } if(flag){ checkAllEl.checked = true; }else{ checkAllEl.checked = false; } updateButtonStatus(); } function openAllSelected(){ var selectedUrl=[]; for(var i=0; i<checkEl.length; i++){ if(checkEl[i].checked){ selectedUrl.push(testData[i].url); console.log(testData[i].url); } } } checkAllEl.addEventListener("click", checkAll); for(var i=0; i<checkEl.length; i++){ checkEl[i].addEventListener("click", checkOne); } if((!$('open_all_selected').disabled)){ $("open_all_selected").addEventListener("click", openAllSelected); }
打印结果如下:
其中cr.icon.getFavicon(data[i].url)返回的数据是url("cdosbrowser://favicon/http://www.iqiyi.com/")
wrap.join('')= <div class="tab_container" id="tab_0"> <input type="checkbox" class="check" id="check_0"> <div class="favicon" style="background-image: url("cdosbrowser://favicon/cdosbrowser://history-frame/#range=3&offset=3");"></div> <div class="title"> <a href="cdosbrowser://history-frame/#range=3&offset=3" target="_blank" title="历史记录" focus-type="title" tabindex="0">历史记录</a> </div> </div> <div class="tab_container" id="tab_1"> <input type="checkbox" class="check" id="check_1"> <div class="favicon" style="background-image: url("cdosbrowser://favicon/cdosbrowser://help/");"></div> <div class="title"> <a href="cdosbrowser://help/" target="_blank" title="cdosbrowser://help" focus-type="title" tabindex="0">cdosbrowser://help</a> </div> </div> <div class="tab_container" id="tab_2"> <input type="checkbox" class="check" id="check_2"> <div class="favicon" style="background-image: url("cdosbrowser://favicon/https://www.baidu.com/");"></div> <div class="title"> <a href="https://www.baidu.com/" target="_blank" title="百度一下,你就知道" focus-type="title" tabindex="0">百度一下,你就知道</a> </div> </div> <div class="tab_container" id="tab_3"> <input type="checkbox" class="check" id="check_3"> <div class="favicon" style="background-image: url("cdosbrowser://favicon/http://www.iqiyi.com/");"></div> <div class="title"> <a href="http://www.iqiyi.com/" target="_blank" title="爱奇艺-全球领先的在线视频网站-海量正版高清视频在线观看" focus-type="title" tabindex="0">爱奇艺-全球领先的在线视频网站-海量正版高清视频在线观看</a> </div> </div>
$('tabs_list').innerHTML= <div class="tab_container" id="tab_0"> <input type="checkbox" class="check" id="check_0"> <div class="favicon" style="background-image: url(" cdosbrowser:="" favicon="" history-frame="" #range="3&offset=3");""></div> <div class="title"> <a href="cdosbrowser://history-frame/#range=3&offset=3" target="_blank" title="历史记录" focus-type="title" tabindex="0">历史记录</a> </div> </div> <div class="tab_container" id="tab_1"> <input type="checkbox" class="check" id="check_1"> <div class="favicon" style="background-image: url(" cdosbrowser:="" favicon="" help="" ");"=""></div> <div class="title"> <a href="cdosbrowser://help/" target="_blank" title="cdosbrowser://help" focus-type="title" tabindex="0">cdosbrowser://help</a> </div> </div> <div class="tab_container" id="tab_2"> <input type="checkbox" class="check" id="check_2"> <div class="favicon" style="background-image: url(" cdosbrowser:="" favicon="" https:="" www.baidu.com="" ");"=""></div> <div class="title"> <a href="https://www.baidu.com/" target="_blank" title="百度一下,你就知道" focus-type="title" tabindex="0">百度一下,你就知道</a> </div> </div> <div class="tab_container" id="tab_3"> <input type="checkbox" class="check" id="check_3"> <div class="favicon" style="background-image: url(" cdosbrowser:="" favicon="" http:="" www.iqiyi.com="" ");"=""></div> <div class="title"> <a href="http://www.iqiyi.com/" target="_blank" title="爱奇艺-全球领先的在线视频网站-海量正版高清视频在线观看" focus-type="title" tabindex="0">爱奇艺-全球领先的在线视频网站-海量正版高清视频在线观看</a> </div> </div>
由上可见background-image的赋值产生了问题,而且神奇的是wrap.join('')打印的结果竟然和$('tabs_list').innerHTML不一样,而且前者看上去好像还是对的,后者已然是乱码。
这是为什么呢?
实际上wrap.join('')将模板拼接的时候还只是进行的字符串的运算,只是把我们组合的内容按部就班的展示给我们,但是赋值给innerHTML的时候就存在一个解析的过程了。
而且其实在wrap.join('')打印的时候就能看出问题所在了,双引号包裹双引号产生的冲突,导致浏览器没办法正常解析。而且即使把外层的双引号改成单引号,打印结果仍然是双引号,不知道是否跟chrome内部有关。
<div class="favicon" style="background-image: {{bgimage}};"></div>
<!--<div class="favicon" style='background-image: {{bgimage}};'></div>-->
解决办法:
法一:将除background-image之外的其他DOM结构构建好,再动态设置其background-image。
法二:将整个模板直接作为变量,实现如下:
<!doctype html> <html class="starting-up" i18n-values="dir:textdirection; lang:language"> <head> <meta charset="utf-8"> <title i18n-content="title"></title> <link rel="stylesheet" type="text/css" href="last_tabs_list.css"> <link rel="stylesheet" href="cdosbrowser://resources/css/tree.css"> <link rel="stylesheet" href="cdosbrowser://resources/css/widgets.css"> <script src="cdosbrowser://resources/js/cr.js"></script> <script src="cdosbrowser://resources/js/cr/ui.js"></script> <script src="cdosbrowser://resources/js/cr/ui/tree.js"></script> <script src="cdosbrowser://resources/js/util.js"></script> <script src="cdosbrowser://resources/js/icon.js"></script> </head> <body> <div class="container"> <div class="nav_container"> <div class="top_nav"> <p>上次未关闭的页面</p> </div> </div> <div class="content"> <div class="content_top"> <div class="select_all_container"> <input type="checkbox" id="check_all"></input> <span class="select_all">全选</span> </div> <div class="open_selected_tabs"> <button class="open_all_selected" id="open_all_selected">打开选中页面</button> </div> </div> <div id="tabs_list" class="tabs_list"> </div> </div> </div> <!-- <script src="http://libs.baidu.com/jquery/1.9.1/jquery.js"></script> --> <script src="last_tabs_list.js"></script> </body> </html>
js代码如下:
//cr.define('last_tabs_list', function(){ // 'use strict' var testData = [ { title: "历史记录", url: "cdosbrowser://history-frame/#range=3&offset=3" }, { title: "cdosbrowser://help", url: "cdosbrowser://help/" }, { title: "百度一下,你就知道", url: "https://www.baidu.com/" }, { title: "爱奇艺-全球领先的在线视频网站-海量正版高清视频在线观看", url: "http://www.iqiyi.com/" } ] function checkAll(){ console.log("checkEl.length="+checkEl.length); if(checkAllEl.checked){ for(var i=0; i<checkEl.length; i++){ checkEl[i].checked = true; console.log(checkEl.length); console.log(checkEl[i].checked); } }else{ for(var i=0; i<checkEl.length; i++){ checkEl[i].checked = false; $("open_all_selected").disabled = true; } } updateButtonStatus(); } function tabsListDOM(data){ var tabsListTemplate = '<div class="tab_container" id="tab_{{index}}">' + '<input type="checkbox" class="check" id="check_{{index}}"></input>'+ "<div class='favicon' style='background-image: {{bgimage}};'></div>" + '<div class="title">' + '<a href="{{url}}" target="_blank" title="{{title}}" focus-type="title" tabindex="0">{{title}}</a>'+ '</div>' + '</div>'; var wrap=[]; for(var i=0; i<data.length; i++){ var backgroundImage = cr.icon.getFavicon(data[i].url); var _tabsListTemplate = tabsListTemplate.replace(/{{index}}/g,i) .replace(/{{url}}/,data[i].url) .replace(/{{bgimage}}/,backgroundImage) .replace(/{{title}}/g,data[i].title); wrap.push(_tabsListTemplate); } $("tabs_list").innerHTML = wrap.join(''); console.log("wrap.join('')="+wrap.join('')); console.log("$('tabs_list').innerHTML="+$("tabs_list").innerHTML); checkEl = $("tabs_list").querySelectorAll(".check"); checkAllEl = $("check_all"); checkAllEl.checked =true; checkAll(); } tabsListDOM(testData); function updateButtonStatus(){ var anyChecked = document.querySelectorAll('#tabs_list input:checked') .length!= 0; $('open_all_selected').disabled = !anyChecked; console.log("anyChecked="+anyChecked); } function checkOne(){ var flag = true; for(var i=0; i<checkEl.length; i++){ if(!checkEl[i].checked){ flag = false; } } if(flag){ checkAllEl.checked = true; }else{ checkAllEl.checked = false; } updateButtonStatus(); } function openAllSelected(){ var selectedUrl=[]; for(var i=0; i<checkEl.length; i++){ if(checkEl[i].checked){ selectedUrl.push(testData[i].url); console.log(testData[i].url); } } } checkAllEl.addEventListener("click", checkAll); for(var i=0; i<checkEl.length; i++){ checkEl[i].addEventListener("click", checkOne); } if((!$('open_all_selected').disabled)){ $("open_all_selected").addEventListener("click", openAllSelected); } //}); //document.addEventListener('DOMContentLoaded', last_tabs_list.onLoad);