今天來試一下Shadow DOM。
上次說到HTML imports的CSS和Javascript會影響到原本的DOM Tree。這次我要用Shadow DOM來隔離這個影響。Shadow DOM有點像是沙盒(SandBox),在裏面做的東西和外面分開。不過在開始嘗試之前,需要先把之前兩份HTML改成下面的樣子:
hello.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>for test</title>
<link rel="import" href="./my-header.html">
</head>
<body>
<div id="myheader"></div>
<h1>Hello World For Test</h1>
</body>
<script>
var my_header = document.querySelector("#myheader");
var my_import = document.querySelector('link[rel="import"]').import
my_import = my_import.querySelector("#mytemplate");
</script>
</html>
my-header.html
<template id="mytemplate">
<h1>This is Header</h1>
<style>
h1{
color:red;
}
</style>
</template>
關於第一個hello.html,要注意的是第方有: div#myheader
是之後要插入的位置,並在Script裡已經先把一些元素取得。可以先試試看my_header.innerHTML = my_import.innerHTML
效果如何,應該會連同原本的文字一起變色。
然後my-header.html,裏面原本所有內容用<template></template>
標籤包裝起來,並且給與ID比較好取得。
關於template,可以參考MDN說明。簡單說template的內容,包含HTML、CSS和Javascript都不會被執行。透過這點,就可以將內容真的只最爲內容,甚至不會被顯示出來(顯示出來表示HTML被執行了)。
過去貌似在Chrome可以用createShadowRoot建立Shadow DOM,不過這個方法已經被棄用,儘管Chrome好像還支援,但還是來使用新方法吧--attachShadow。
// 建立Shadow DOM
var my_shadow = my_header.attachShadow({mode:"open"})
// 將預計import的內容寫入Shadow DOM
my_shadow.innerHTML = my_import.innerHTML
加入上面script以後,可以發現受到template裡的CSS影響的,也只有Shadow DOM裡的h1
。
mode給與的值可以是:"open"
或是"closed"
按照說明是能不能取得外部(也就是hello.html)的內容,不過我試了一下好像沒什麼差別......可能是對Javascript有影響?
** 完整的hello.html **
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>for test</title>
<link rel="import" href="./my-header.html">
</head>
<body>
<div id="myheader"></div>
<h1>Hello World For Test</h1>
</body>
<script>
var my_header = document.querySelector("#myheader");
var my_import = document.querySelector('link[rel="import"]').import
my_import = my_import.querySelector("#mytemplate");
var my_shadow = my_header.attachShadow({mode:"open"})
my_shadow.innerHTML = my_import.innerHTML
</script>
</html>