We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ShadowDOM是一个HTML的规范,作用是将主文档的DOM独立开来,保持分离。在shadowDOM内部的css和dom节点都是独立的,这意味着外部的css不会影响到shadowDOM里的UI树。
在gm-printer或者其他带有独立UI视图的库中,需要将业务css代码和通用的组件与其隔离。库本身是独立的,业务代码的css样式不应该影响到库,两者是解耦的。
<p id='app'></p> var p = document.querySelector('#app') var shadow = p.attachShadow({mode: 'open'});
这里要注意的是:p是影子宿主,shadow是影子树。
// 从影子宿主获得影子树 p.shadowRoot === shadow // 从影子树获得影子宿主 shadow.host === p
关乎shadowDOM的时间模型比较特殊,在shadowDOM里触发的事件会传播出去的事件有:
聚焦事件:blur、focus、focusin、focusout
blur
focus
focusin
focusout
鼠标事件:click、dblclick、mousedown、mouseenter、mousemove,等等
click
dblclick
mousedown
mouseenter
mousemove
滚轮事件:wheel
wheel
输入事件:beforeinput、input
beforeinput
input
键盘事件:keydown、keyup
keydown
keyup
组合事件:compositionstart、compositionupdate、compositionend
compositionstart
compositionupdate
compositionend
拖放事件:dragstart、drag、dragend、drop,等等
dragstart
drag
dragend
drop
其他事件不会冒泡到shadowDOM外部。
关键的是:这些可以传播出去的事件,在外部监听到的事件起源目标(event.target)是影子宿主。这意味着没添加shadowDOM时,在document上注册的事件处理函数中如果使用到了event.target,会引发错误。
解决方案:将window.document挂载的事件都迁移到shadow层。
window.document.addEventListner('click', this.handleClick) // 如果this.handleClick中使用到了event.target可能引发错误
window.shadowRoot.addEventListener('click', handleClick) ✅
ShadowDOM:独立的网络组件
const style = window.document.createElement('style') style.type = 'text/css' style.appendChild(document.createTextNode(cssString)) shadowRoot.appendChild(style)
其中cssString是css样式的字符串形式。
迁移css样式时注意:shadowDOM中默认没有body和html这两个标签(当然你可以添加),所以在css样式中body和html的样式会失效。
可继承样式(background、color、font 以及 line-height 等)可在 shadow DOM 中继续继承。 也就是说,默认情况下它们会突破 shadow DOM 边界。 如果您想从头开始,可在它们超出影子边界时,使用 all: initial; 将可继承样式重置为初始值。
background
color
font
line-height
all: initial;
componentDidMount() { ReactDOM.render(<App />, shadowRoot) }
需要注意的是需要在componentWillUnmount这个生命周期下卸载<App />渲染。
<App />
componentWillUnmount () { ReactDOM.unmountComponentAtNode(window.shadowRoot) ✅ }
首先使用shadowDOM一般是库,库是给项目使用的,如果忘记unmountComponentAtNode库的vdom,再次渲染的时候会出现卡死等比较严重的问题,很可能是之前存在的vdom(或者其他react内部的状态)影响了新的渲染。
chrome53以上支持shadowDOM,可以看到兼容性一般,如果强调兼容的话可以考虑iframe来做隔离,但是使用了iframe主页面的数据传递也阻隔了。这就需要库的调用方做取舍了。
babel帮我们做了很多将es6的一些语法转换成es5,但是babel也有不能转换的,转译出来的结果在默认情况下并不包括 ES6 对运行时的扩展,例如,builtins(内建,包括 Promise、Set、Map 等)、内建类型上的原型扩展(如 ES6 对 Array、Object、String 等内建类型原型上的扩展)以及Regenerator(用于generators / yield)等都不包括在内。
这时就需要polyfill来填补这个对运行时的扩展了,现所有的polyfill都需要依赖开源库core-js,他提供es6、7、8的新特性。
由于之前无意的使用到一个ES10的新特性flat,导致低版本浏览器运行错误,解决方案是升级babel-polyfill到7.4.4(babel-polyfill基于core-js再封装),可支持更多的es新特性。但最好的做法是使用core-js@3,然后自定义打包一个满足业务需求的polyfill。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
shadowDOM是什么?
ShadowDOM是一个HTML的规范,作用是将主文档的DOM独立开来,保持分离。在shadowDOM内部的css和dom节点都是独立的,这意味着外部的css不会影响到shadowDOM里的UI树。
为什么需要shadowDOM?
在gm-printer或者其他带有独立UI视图的库中,需要将业务css代码和通用的组件与其隔离。库本身是独立的,业务代码的css样式不应该影响到库,两者是解耦的。
shadowDOM的创建和要注意的点
创建一个shadowDOM
这里要注意的是:p是影子宿主,shadow是影子树。
shadowDOM的事件模型
关乎shadowDOM的时间模型比较特殊,在shadowDOM里触发的事件会传播出去的事件有:
聚焦事件:
blur
、focus
、focusin
、focusout
鼠标事件:
click
、dblclick
、mousedown
、mouseenter
、mousemove
,等等滚轮事件:
wheel
输入事件:
beforeinput
、input
键盘事件:
keydown
、keyup
组合事件:
compositionstart
、compositionupdate
、compositionend
拖放事件:
dragstart
、drag
、dragend
、drop
,等等其他事件不会冒泡到shadowDOM外部。
关键的是:这些可以传播出去的事件,在外部监听到的事件起源目标(event.target)是影子宿主。这意味着没添加shadowDOM时,在document上注册的事件处理函数中如果使用到了event.target,会引发错误。
解决方案:将window.document挂载的事件都迁移到shadow层。
ShadowDOM:独立的网络组件
给shadowDOM添加样式
其中cssString是css样式的字符串形式。
迁移css样式时注意:shadowDOM中默认没有body和html这两个标签(当然你可以添加),所以在css样式中body和html的样式会失效。
重置可继承样式
在React中使用shadowDOM
需要注意的是需要在componentWillUnmount这个生命周期下卸载
<App />
渲染。首先使用shadowDOM一般是库,库是给项目使用的,如果忘记unmountComponentAtNode库的vdom,再次渲染的时候会出现卡死等比较严重的问题,很可能是之前存在的vdom(或者其他react内部的状态)影响了新的渲染。
兼容性
chrome53以上支持shadowDOM,可以看到兼容性一般,如果强调兼容的话可以考虑iframe来做隔离,但是使用了iframe主页面的数据传递也阻隔了。这就需要库的调用方做取舍了。
升级polyfill
babel帮我们做了很多将es6的一些语法转换成es5,但是babel也有不能转换的,转译出来的结果在默认情况下并不包括 ES6 对运行时的扩展,例如,builtins(内建,包括 Promise、Set、Map 等)、内建类型上的原型扩展(如 ES6 对 Array、Object、String 等内建类型原型上的扩展)以及Regenerator(用于generators / yield)等都不包括在内。
这时就需要polyfill来填补这个对运行时的扩展了,现所有的polyfill都需要依赖开源库core-js,他提供es6、7、8的新特性。
由于之前无意的使用到一个ES10的新特性flat,导致低版本浏览器运行错误,解决方案是升级babel-polyfill到7.4.4(babel-polyfill基于core-js再封装),可支持更多的es新特性。但最好的做法是使用core-js@3,然后自定义打包一个满足业务需求的polyfill。
The text was updated successfully, but these errors were encountered: