Shadow DOM — Encapsulation & the Shadow Tree

DEX475 - Work with the DOM

📄 第 182 页 🎬 视频课程

课程章节介绍

同学们,我们这节课来聊聊 Web 组件里的一个核心概念,叫影子 DOM。听名字可能有点神秘,其实它就是一套封装机制,就像给组件穿上了一层隐形的外壳,保护里面的东西不被外面随便打扰。 简单来说,当你创建一个 Web 组件,它的内部结构会形成一个独立的 DOM 树,叫做影子树。这个树挂载在宿主元素上,但跟外面的主 DOM 是隔离开的。你用浏览器的开发者工具就能看到,组件内部代码开头有个 #shadow-root 的标识,这就是隔离的边界线。 这个隔离到底影响了哪些方面呢?主要有四点,你记住就能理解影子 DOM 的精髓了。 第一,样式隔离。你在父组件里写的 CSS 样式,是穿透不了这个影子边界的。也就是说,外面的样式不会意外地把你组件内部的按钮或文字给改坏了。当然,你也会发现,里面也很难直接受外面控制,这保护了组件的样式独立性。 第二,事件重定向。如果组件内部发生了一个事件,比如点击按钮,这个事件会冒泡穿过影子边界,但是它把自己原来的目标对象重新包装了一下。这样,外面收到的 event.target 就不是你内部的真实元素了,而是宿主组件本身。这就隐藏了内部细节,只暴露一个干净的接口。 第三,DOM 查询无法穿透。你在组件外部使用 document.querySelector 这类方法,是搜不到影子树里面的任何元素的。那如果组件自己内部想查呢?就得用 this.template.querySelector 这个专用方法,注意,一定是 template 这个属性上调用,它指向的就是影子树里的内容。 第四,插槽元素特殊。组件里用 slot 传递进来的那些内容,它们实际上并不属于影子树。它们还归父组件管,所以你要在组件里查询这些插槽进来的元素时,不能用 this.template.querySelector,而应该用 this.querySelector,这样才能找到那些由外部注入进来的孩子。 最后,有个特别有用的信息。在 Lightning Experience 里,为了确保这些行为在所有浏览器里表现一致,LWC 用了一种叫做合成影子 polyfill 的技术。也就是说,不管浏览器本身支不支持原生影子 DOM,你的组件都能享受到刚才说的这些封装保护,行为统一可靠。 好了,现在你理解影子 DOM 的妙处了吧?它就是让组件内部世界保持干净、不受干扰,同时又保留必要的通信渠道。后续我们会慢慢体会到这种封装带来的好处。

关键词

LWC Lightning Web Components Salesforce