这篇文章发布于 2021年04月26日,星期一,20:12,归类于 JS实例。 阅读 8370 次, 今日 1 次 一条评论
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=9929
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。
一、Safari又拖后腿了
Safari浏览器不支持build-in自定义元素,只支持匿名自定义元素。
兼容性如下图所示:
也就是Safari默认仅支持下面这种HTML格式的UI组件:
<ui-tips></ui-tips> <ui-drop></ui-drop> <ui-tab></ui-tab> <ui-lighttip></ui-lighttip>
不支持下面这种通过is
属性在原生HTML元素上扩展的web components组件。
<input is="ui-color"> <select is="ui-select"></select> <form is="ui-form"></form> <table is="ui-table"></table>
这就麻烦了,本来很帅气的UI组件,如果只能使用匿名自定义元素实现,就很啰嗦与乏味。
或者,狠狠心,无视Safari浏览器用户群体,可以的,等着被解雇就行。
所以,最好的解决方法就是让Safari浏览器也支持内置自定义元素组件的开发。
怎么办呢?
二、Polyfill build-in custom element
解决方法比较简单,有专门polyfill,只要引入就可以了。
项目地址:
https://github.com/WebReflection/custom-elements-builtin
适用于支持自定义元素,但是不支持内置自定义元素的场景,主要就是针对Safari浏览器。
其中的index.js是非压缩版,es.js是压缩版。
使用的时候可以直接这么使用:
<!-- HTML文档的顶部 -->
<script></script>
不过if
判断外加document.write
并不是一个好用法,但是,我们直接引用 //unpkg.com/@webreflection/custom-elements-builtin 这个地址也是不行的。
因为这个Polyfill中并没有对浏览器进行区分,按照作者的话,就是浏览器的特性是一直变化的,做浏览器类型判断是不靠谱的。
上面这句话没错,但是,我们可以不进行浏览器区分,直接基于API特性区分就好了。
//zxx: 如果你看到这段文字,说明你现在访问是体验糟糕的垃圾盗版网站,你可以访问原文获得很好的体验:https://www.zhangxinxu.com/wordpress/?p=9929(作者张鑫旭)
于是,我对原始的JS代码做了内置的判断处理。
判断逻辑如下代码所示:
class AnyClass extends HTMLBRElement {
constructor () {
super();
this.someMethod = true;
}
}
if (!customElements.get('any-class')) {
customElements.define('any-class', AnyClass, {
extends: 'br'
});
}
// 是否支持 build-in custom element
const isSupportBuildIn = document.createElement('br', {
is: 'any-class'
}).someMethod;
基于特性判断是很安全的,如果浏览器支持内置自定义元素,则 isSupportBuildIn
的返回值就是 true,如果浏览器不支持,则会是 undefined。
优化后的JS代码我已经开源了,放在了gitee上,详见:https://gitee.com/zhangxinxu/build-in-custom-element-polyfill
欢迎大家关注我的这个gitee账号。
三、完美运行下的问题
这段Polyfill真的挺神奇的,原来的Web Components代码无需任何修改,组件功能在Safari浏览器下完美支持,所有组件都运行良好。
然后,真正到业务代码中,进行组件传参处理的时候,发现问题了。
例如,引用代码如下:
<script src="safari-polyfill.js"></script>
<script type="module" src="my-components.js"></script>
<script type="module">
myComponent.someMethod();
</script>
在原生支持内置自定义元素的浏览器下,myComponent.someMethod() 方法是可以正常执行的。
但是在Safari浏览器下,就会报错,undefined不能作为function函数执行。
原因在于,safari-polyfill.js 由于实现机制的限制,会让自定义元素初始化的时机比原生浏览器更靠后。
也就是在Safari浏览器下,myComponent.someMethod()
方法执行的时候,myComponent
这个元素还没有变成内置自定义元素。
因此,执行会出错。
我的解决方法是这样的,在 connectedCallback 生命周期函数中触发一个自定义的 'connected'
事件,这样,就可以通过绑定 'connected'
事件的方式保证业务代码执行的时候,元素已经完成了组件化。
代码示意,组件中的代码部分:
connectedCallback () {
this.dispatchEvent(new CustomEvent('connected'), {
detail: {
type: 'my-components'
}
});
}
然后,业务代码改造成这样就可以了:
<script src="safari-polyfill.js"></script>
<script type="module" src="my-components.js"></script>
<script>
myComponent.addEventListener('connected', function () {
this.someMethod();
});
</script>
这样就可以保证 someMethod() 方法执行的时候,组件一定已经完成了初始化。
四、想不到该说什么的小结
想不到该说些什么。
祝大家五一快乐!
什么,五一还有一周。
那就提前祝大家五一快乐,今天五一出游人会很多,大家记得注意安全哦。
比心!
本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。
本文地址:https://www.zhangxinxu.com/wordpress/?p=9929
(本篇完)
- 聊聊JS DOM变化的监听检测与应用 (0.400)
- JS CustomEvent自定义事件传参小技巧 (0.350)
- 输入框value属性赋值触发js change事件的实现 (0.350)
- 巧用两个type=range input实现区域范围选择 (0.252)
- HTMLUnknownElement与HTML5自定义元素的故事 (0.167)
- 如何继承自定义元素及其他JS中扩展新方法 (0.167)
- 漫谈js自定义事件、DOM/伪DOM自定义事件 (0.150)
- CSS技术分享: 文字在圆形内沿着弧线边界排版 (0.100)
- 面向设计的半封装web组件开发(概要版) (0.086)
- 基于原生HTML的UI组件开发 (0.086)
- Safari 3D transform变换z-index层级渲染异常的研究 (RANDOM - 0.032)
提前祝旭哥五一快乐