拼接html字符串时引号的转义

项目中自己挖的一个坑。调api获取导航菜单项,for循环获取每一项的相关值拼接html:

html +=
    '<li>\
        <a onclick="iframe_new(\''+arr[i].filename+'\',\''+arr[i].name+'\')">'+'<span>'+arr[i].name+'</span></a>\
    </li>'

显然,当filename或name包含单引号时(filename还不太可能出现,name就很可能了,比如英文的 ‘s)点击这个a标签就会出错,因为实际解析成html之后iframe_new这个函数的调用语句成了:

<a onclick="iframe_new('user_members_list.php','User's Members')">
    <span>User's Members</span>
</a>

在chrome元素面板里看是这样的:
rendered-1

User's中的单引号和U前面的单引号配对,导致iframe_new这个函数的括号没有闭合,浏览器报语法错误:
Uncaught SyntaxError: missing ) after argument list

如果包含的是双引号:

<a onclick="iframe_new('user_members_list.php','User"s Members')">
    <span>User's Members</span>
</a>

在chrome元素面板里就崩坏了:
rendered-2

浏览器报错:Uncaught SyntaxError: Invalid or unexpected token

我还经常在元素标签内加各种dataset属性,用于传递参数给绑定的事件handler,比如:

html += '<tr data-cid="'+arr[i].contactid+'" data-cname="'+arr[i].contactname+'" class="gotocontact">'

页面初始化时会有相应的事件委托,点击这个tr元素会根据data-cid打开新页面,data-cname作为页面标签的名称。类似地,当contactname包含引号时也会出现问题,区别在于前者是直接导致js语句截断,js执行报错,页面元素渲染没问题后者是导致页面元素渲染出错,以及传给js的参数不完整,但执行不会报错:新页面能打开,但标签名称不完整。

其实这种时候,正确的做法是使用document.createElement,然后给新元素的属性赋值:

var li = document.createElement('li');
var a = document.createElement('a');
var span = document.createElement('span');
a.onclick = function() {
    iframe_new(arr[i].filename, arr[i].name)
}
span.innerHTML = arr[i].name;
li.append(a);
a.append(span);
document.querySelector('#list').append(li);

但是坑太多了,懒得一个个改。。。于是想办法修补。

最后的做法:

  • 处理onclick内的引号时,双引号需要html转义,即替换成&quotes;。单引号需要js转义,即前面加反斜杠。
function escapeQuotes(raw) {
    return raw
        .replace(/"/g, "&quotes;")
        .replace(/'/g, "\\'");
}
  • 处理data-* 等不涉及js逻辑的属性值内的引号时,只需要把双引号html转义,因为包围属性值的引号是双引号,单引号不会配对。
html += '<tr data-cid="'+arr[i].contactid+'" data-cname="'+(arr[i].contactname).replace(/"/g, "&quotes;")+'" class="gotocontact">'

发表评论

您的电子邮箱地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据