經常寫video,audio等html元素在帶的控制條或者模塊,但是這這些模塊哪裏來的用什麼實現的
發現步驟
進入setttins, 在elements裏勾選
如此打開新世界的大門
隱藏有點深刻,難以發現。
那什麼是影子DOM
- 影子dom這個東西的存在,主要解決dom樹建立時能夠實現維護自身邊界的問題。這麼說有點像vue的scope保證自身不會被外來修飾入侵或者污染。
- 影子dom將對應的dom信息隱藏起來依然能在html文檔裏渲染出來。但不能通過普通的js方法獲取到dom信息
- 影子dom事件捕獲遵從常規dom事件,在影子dom內部依然傳遞,同時也遵從事件冒泡,向整個文檔的dom上傳遞事件。
影子樹和文檔
創建影子樹
通過createShadowRoot創建影子樹root節點
<!DOCTYPE html>
<html>
<head>
<title>影子dom</title>
<link rel="dns-prefetch" href="//dfhs.tanx.com">
<style>
.box {
height: 80px;
width: 80px;
background-color: red;
}
</style>
</head>
<body>
<div id="box" class="box"></div>
</body>
<script>
var $box = document.getElementById('box');
var shadowRoot = $box.createShadowRoot(); // 獲得root
//var showRoot = $box.webkitGetShadowRoot() // webkit 支持
var children = document.createElement('div');
children.setAttribute('style', 'height: 40px; width: 40px; background-color: blue');
shadowRoot.appendChild(children);
</script>
</html>
效果圖
再給影子樹節點添加css時不能用過class或者元素選擇來添加,否則無效果
<!DOCTYPE html>
<html>
<head>
<title>影子dom</title>
<link rel="dns-prefetch" href="//dfhs.tanx.com">
<style>
.box {
height: 80px;
width: 80px;
background-color: red;
}
.children {
height: 40px;
width: 40px;
background-color: blue;
}
div {
height: 40px;
width: 40px;
background-color: blue;
}
</style>
</head>
<body>
<video src="test.mp4" height="200px" controls></video>
<audio src="mp3.mp3" controls></audio>
<canvas></canvas>
<div id="box" class="box"></div>
</body>
<script>
var $box = document.getElementById('box');
var shadowRoot = $box.createShadowRoot(); // 獲得root
//var showRoot = $box.webkitGetShadowRoot() // webkit 支持
var children = document.createElement('div');
children.setAttribute('class', 'children');
shadowRoot.appendChild(children);
</script>
</html>
通過class選擇dom時需要將style也放入影子節點裏
<script>
var $box = document.getElementById('box');
var shadowRoot = $box.createShadowRoot(); // 獲得root
//var showRoot = $box.webkitGetShadowRoot() // webkit 支持
var children = document.createElement('div');
children.setAttribute('class', 'children')
shadowRoot.innerHTML += '<style>.children { height: 40px; width: 40px; background-color: blue;}</style>';
shadowRoot.appendChild(children);
</script>
不能直接獲得影子DOM
通過js常規方法不能直接獲取到dom節點
var $box = document.getElementById('box');
var shadowRoot = $box.createShadowRoot(); // 獲得root
//var showRoot = $box.webkitGetShadowRoot() // webkit 支持
var children = document.createElement('div');
children.setAttribute('class', 'children');
children.setAttribute('id', 'children');
shadowRoot.appendChild(children);
// 獲得影子dom
// 通過id
var getShadowRootById = document.getElementById('children');
console.log(getShadowRootById)
// 通過節點選擇
console.log('---------------')
var getShadowRootByDomBox = document.body.firstChild.nextSibling; // 獲得到box
//var getShadowRootByDom = getShadowRootByDomBox.firstChild
var getShadowRootByDom = getShadowRootByDomBox.firstElementChild;
console.log(getShadowRootByDom)
影子dom事件綁定
在createElement時拿到的元素,添加addEventListener事件
var $box = document.getElementById('box');
var shadowRoot = $box.createShadowRoot(); // 獲得root
//var showRoot = $box.webkitGetShadowRoot() // webkit 支持
var children = document.createElement('div');
children.setAttribute('class', 'children')
shadowRoot.innerHTML += '<style>.children { height: 40px; width: 40px; background-color: blue;}</style>';
shadowRoot.appendChild(children);
children.addEventListener('click', function(e) {
console.log(e)
})
通過template完整的操縱影子dom
template也是documentfragment
<!DOCTYPE html>
<html>
<head>
<title>影子dom</title>
<link rel="dns-prefetch" href="//dfhs.tanx.com">
<style>
.box {
height: 80px;
width: 80px;
background-color: red;
}
.children {
height: 40px;
width: 40px;
background-color: blue;
}
</style>
</head>
<body>
<div id="box" class="box"></div>
<div class="box-test"></div>
<template class="root-tlp">
<style>
.test-ctn {
color: white;
}
</style>
<div>
<div class="test-ctn" id="test">測試</dt>
</div>
<script>
document.addEventListener('click', function(e) {
console.log(e)
})
</script>
</template>
</body>
<script>
var $box = document.getElementById('box');
var shadowRoot = $box.createShadowRoot(); // 獲得root
var children = document.createElement('div');
children.setAttribute('class', 'children')
shadowRoot.innerHTML += '<style>.children { height: 40px; width: 40px; background-color: blue;}</style>';
var template = document.querySelector('.root-tlp');
shadowRoot.appendChild(template.content);
</script>
</html>
當然綁定事件同樣有輸出
利用content元素select屬性將目標內容匹配到template中指定位置,並且目標內容只能在影子元素裏
<!DOCTYPE html>
<html>
<head>
<title>影子dom</title>
<link rel="dns-prefetch" href="//dfhs.tanx.com">
<style>
.box {
height: 160px;
width: 160px;
background-color: red;
}
.children {
height: 80px;
width: 80px;
background-color: blue;
}
.test-content {
background-color: yellow;
}
</style>
</head>
<body>
<div id="box" class="box">
<div class="test-content">我接着測試</div>
</div>
<template class="root-tlp">
<style>
.test-ctn {
color: white;
}
</style>
<div>
<div class="test-ctn" id="test">測試</dt>
</div>
<content select=".test-content"></content>
</template>
</body>
<script>
var $box = document.getElementById('box');
var shadowRoot = $box.createShadowRoot(); // 獲得root
var children = document.createElement('div');
var template = document.querySelector('.root-tlp');
shadowRoot.appendChild(document.importNode(template.content, true));
document.addEventListener('click', function() {
console.log('test-content')
})
</script>
</html>
這種方式改變文檔流順序還能直接獲得dom節點和綁定事件
CSS 選擇器:
:host, :host(), :host-context()
:host
<template class="root-tlp">
<style>
.test-ctn {
color: white;
}
:host {
font-weight: bold;
}
</style>
<div>
<div class="test-ctn" id="test">測試</dt>
</div>
<content select=".test-content"></content>
</template>
:host()選擇器,選擇影子dom宿主元素
<body>
<div id="box" class="box">
<div class="test-content">我接着測試</div>
</div>
<template class="root-tlp">
<style>
.test-ctn {
color: white;
}
:host {
font-weight: bold;
}
:host(.box) {
color: blue;
}
</style>
<div>
<div class="test-ctn" id="test">測試</dt>
</div>
<content select=".test-content"></content>
</template>
</body>
:host-context()與後代選擇器表達式一起使用,以僅選擇特定祖先內部的自定義元素的實例
<!DOCTYPE html>
<html>
<head>
<title>影子dom</title>
<link rel="dns-prefetch" href="//dfhs.tanx.com">
<style>
.box {
height: 160px;
width: 160px;
}
.children {
height: 80px;
width: 80px;
}
</style>
</head>
<body>
<div id="box" class="test">
<div class="box-content" id="box-content">
<div class="box-ctn">213</div>
</div>
</div>
<template class="root-tlp">
<style>
.test-ctn {
color: white;
}
:host {
font-weight: bold;
}
:host(.box-content) {
color: blue;
background-color:red;
}
:host-context(.test) {
height: 300px;
background-color: blueviolet
}
</style>
<div>
<div class="test-ctn" id="test">測試</dt>
</div>
<content select=".box-ctn"></content>
</template>
</body>
<script>
var $box = document.getElementById('box-content');
var shadowRoot = $box.createShadowRoot(); // 獲得root
var children = document.createElement('div');
var template = document.querySelector('.root-tlp');
shadowRoot.appendChild(document.importNode(template.content, true));
</script>
</html>