2

Safari不支持build-in自定义元素的兼容处理

 3 years ago
source link: https://www.zhangxinxu.com/wordpress/2021/04/safari-buildin-custom-element-polyfill/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Safari不支持build-in自定义元素的兼容处理

这篇文章发布于 2021年04月26日,星期一,20:12,归类于 JS实例。 阅读 41 次, 今日 40 次 没有评论

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=9929
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。

占位封面图 颈椎帮助

一、Safari又拖后腿了

Safari浏览器不支持build-in自定义元素,只支持匿名自定义元素。

兼容性如下图所示:

Safari不支持内置自定义元素

也就是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>
if (!(self.chrome || self.navigator))
  document.write('<script src="//unpkg.com/@webreflection/custom-elements-builtin"><\x2fscript>');
</script>

不过if判断外加document.write并不是一个好用法,但是,我们直接引用 //unpkg.com/@webreflection/custom-elements-builtin 这个地址也是不行的。

因为这个Polyfill中并没有对浏览器进行区分,按照作者的话,就是浏览器的特性是一直变化的,做浏览器类型判断是不靠谱的。

上面这句话没错,但是,我们可以不进行浏览器区分,直接基于API特性区分就好了。

于是,我对原始的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() 方法执行的时候,组件一定已经完成了初始化。

四、想不到该说什么的小结

想不到该说些什么。

祝大家五一快乐!

什么,五一还有一周。

那就提前祝大家五一快乐,今天五一出游人会很多,大家记得注意安全哦。

2764.svg

(本篇完)1f44d.svg 是不是学到了很多?可以分享到微信
1f44a.svg 有话要说?点击这里

本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。
本文地址:https://www.zhangxinxu.com/wordpress/?p=9929


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK