運作模式
可以使用函式傳入樣板字面值,並且會依照參數來區隔開字串與變數
1 2 3 4 5
| function showConsole(strings, ...arg) { console.log(strings, arg); }; const myName = '小明'; const sentence = showConsole`您好 ${myName} ,餐點已經準備好了!`;
|
加入標籤
1 2 3 4 5 6
| const myName = '小明'; const highlight = (strings, ...arg) => strings.map((str, i) => `${ str }${ arg[i] ? `<span>${arg[i]}</span>` : '' }`).join(''); const sentence = highlight`您好 ${myName} ,餐點已經準備好了!`; const sentence_2 = `您好 <span>${myName}</span> ,餐點已經準備好了!`; console.log('sentence =>', sentence); console.log('sentence_2 =>', sentence_2);
|
上述這個例子雖然可以直接寫成 sentence_2
形式,但一旦字串中需要插入的變數很多,並且都要套用相同方法
的時候,就可以考慮寫成 標籤樣板字面值
的形式
XSS 阻擋
傳入的變數
有寫入 html 的時候(innerHTML)
,就要小心是否會傳入非正常變數內容
,像是塞入惡意程式、call 外部 API 等。
1 2 3 4 5
| const messageName = '小明'; document.querySelector('#message').innerHTML = `<p>${ messageName } 傳來一則訊息</p>`;
const xss_messageName = '<img onload="fetch(\'https://randomuser.me/api\')" src="https://images.unsplash.com/photo-1593642702749-b7d2a804fbcf?ixid=MXwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80"></img>'; document.querySelector('#message').innerHTML = `<p>${ xss_messageName } 傳來一則訊息</p>`;
|
解決方法也很好理解,只需將傳入的變數都先轉成字串
再輸出即可
1 2 3 4 5 6 7 8 9 10
| function convertHTML(strings, ...keys) { return strings.map((str, i) => `${str}${keys[i] ? `${keys[i] .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>')}` : ''}` ).join(''); } const xss_messageName = '<img onload="fetch(\'https://randomuser.me/api\')" src="https://images.unsplash.com/photo-1593642702749-b7d2a804fbcf?ixid=MXwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80"></img>'; document.querySelector('#message').innerHTML = convertHTML`<p>${ xss_messageName } 傳來一則訊息</p>`;
|
如此一來,就可以避免有 XSS 惡意攻擊行為。
參考資料
六角學院 - JavaScript 核心篇