如何继承自定义元素及其他JS中扩展新方法

更新日期: 2022-06-20阅读: 943标签: 元素

一、Web组件以旧换新

也就是如何使用已有自定义元素组件创建新的自定义元素组件。

例如有一个 A 组件,运行很OK,然后有一个 B 组件,虽然语义和 A 组件相差甚远,但是功能核心却是一致的。

此时,如果重新开放一个 B 组件就有浪费,直接使用 A 组件语义就不对。

比如说 swipe 切换和 Tab 选项卡切换的核心是一致的,如果已经有了 Tab 组件,我们如何用非常简单的方式重新实现一个 Swipe 轮播组件呢?

这就是这里要探讨的实现。

Toast 提示组件示意

不过选项卡效果相对比较复杂,用来做案例不合适,所以这里使用 toast 组件做示意。

通常 Toast 提示组件都是提示文字内容。


然后,Loading 效果,就是下图所示的加载动画效果,神似 Toast 提示。


因此,很多组件把这个全局的 loading 提示效果集成到了 Toast 组件中。

从功能上说,不是不可以,但是从语义,以及组件管理的角度讲,这个提示应该归属于 Loading 组件才合适。

此时,可以采用组件继承的方式,自定义两个完全不同的自定义元素组件。

代码示意

假设有个名为 zxx-toast.js 的文件,文件中的 JS 代码如下所示,用来自定义 <zxx-toast> 元素:

// 定义 <zxx-toast> 元素
class ZxxToast extends htmlElement {
    static get observedAttributes () {
        return ['open'];
    }
    constructor () {
        super();
    }
    get open () {
        return this.hasAttribute('open');
    }

    set open (val) {
        this.toggleAttribute('open', val);
    }
    
    render () {
        setTimeout(() => {
            this.hide();
        }, 3000);
    }
    
    show () {
        this.open = true;
    }

    hide () {
        this.open = false;    
    }
    
    attributeChangedCallback (name, oldval, newval) {
        if (name == 'open' && this.open) {
            this.render();
        }
    }
}

if (!customElements.get('zxx-toast')) {
    customElements.define('zxx-toast', ZxxToast);
}

export default ZxxToast;

实现了非常基础的能力,定义了一个自定义属性 open ,定义了 show() 和 hide() 显隐方法,定义了 render() 方法,在提示元素显示的时候执行。

此时,我们想要实现全屏 loading 效果,则可以完全继承这里的 ZxxToast,然后重新定义一个新的自定义元素,例如 <zxx-loading> ,则可以这么做。

// 定义 <zxx-loading> 元素
import ZxxToast from './zxx-toast.js';
class ZxxLoading extends ZxxToast {
    render () {
        // 显示 loading 内容
        this.innerHTML = '<i class="spin"></i>';
    }
}
if (!customElements.get('zxx-loading')) {
    customElements.define('zxx-loading', ZxxLoading);
}

不到十行代码就结束了,使用 extends 进行继承,使用 customElements.define() 方法重新定义一个自定义元素。

此时, <zxx-toast> 组件元素的 open 属性,以及 show() 和 hide() 方法全部都继承过来了。

对于不一样的方法,直接同名覆盖,对于新方法,直接设置,非常灵活。

最后,只要再把对应的自定义元素的 css 样式补上,我们的需求就实现了。

运行测试

眼见为实,您可以狠狠地点击这里: Web组件继承为新的自定义元素组件demo

可以看到,点击下面的按钮,Toast 提示正常出现,3s 后自动消失。


而点击 loading 显示按钮,则是下图所示的效果:


两种效果,一个用的是 <zxx-loading> 元素,另外一个使用的是 <zxx-loading> 元素,看起来是完全不同的组件,但实际上内核代码用的都是同一套,于是既兼顾了可维护性,又兼顾了语义。

二、Web组件锦上添花

也就是不创建新的自定义元素组件,但是需要把原来的Web Components组件进行增强扩展,变得更厉害。

传统的方法,这种增强扩展可能集成在原来的组件 JS 文件中。

其实,如果这种增强能力并不是非常常用,或者说为了维护更方便,因为独立管理,其实是可以在另外的 JS 中处理的。

如果要使用,就 import 此 JS,如果不需要这些扩展能力,还是 import 核心 JS 就可以了。

下面是一个实现示意,对上面实现的常规的 toast 提示基础上增加几个方法,表示成功提示、失败提示和警告提示。

例如,有一个名为 toast-extend.js 的文件,里面有如下所示的 JavaScript 代码:

// 扩展 toast 方法元素
import Toast from './zxx-toast.js';

Toast.prototype.success = function (content) {
    if (content) {
        this.innerHTML = content;
    }
    this.setAttribute('type', 'success');
    this.show();
}

Toast.prototype.error = function (content) {
    if (content) {
        this.innerHTML = content;
    }
    this.setAttribute('type', 'error');
    this.show();
}

Toast.prototype.warning = function (content) {
    if (content) {
        this.innerHTML = content;
    }
    this.setAttribute('type', 'warning');
    this.show();
}

export default Toast;

此时, <zxx-toast> 元素执行 success() 之类的方法,就有了包含状态的提示效果了。


眼见为实,您可以狠狠地点击这里: Web组件类扩展为新的组件demo

三、站在实际开发的角度

上面两个案例主要演示如何在现有的 Web Components 组件基础上继承与扩展。

实际开发时候的执行细节会有所不同。

例如,toast 的出现通常不会是基于 <zxx-toast> 元素,而是某个非元素对象进行调研,隐藏 dom 元素本身的细节。

拿上面的 toast-extend.js 举例,对开发人员体验更好的处理方式不是类扩展,而是直接一个静态方法更为合适。

例如:

// 扩展 toast 方法元素
import Toast from './zxx-toast.js';

Toast.success = function (content) {
    const toast = new Toast();
    if (content) {
        toast.innerHTML = content;
    }
    toast.setAttribute('type', 'success');
    toast.show();
    document.body.appendChild(toast);
}

export default Toast;

假设上面代码属于 toast-extend-static.js ,则此时,页面中无需任何自定义元素,直接执行对应的 success 方法,对应的 toast 提示效果就出现了。

示意:

<button id="button">成功提示</button>
<script type="module">
import Toast from './toast-extends-static.js';

button.onclick = function () {
    Toast.success('操作成功');
};
</script>

实时效果如下所示(iframe内嵌页,如果没有效果,点击这里预览):

结语

好,以上就是本文的全部内容了。

对于原生的 Web Components 组件开发,对于很多前端开发人员而言,是没机会在生产环境实践的。

因为业界有很多成熟的上层组件框架,站在业务开发的角度而言,并不需要你去前言和底层游走。

以及,虽然有看到不少团队开始拥抱 Web Components,但是,说实话,操刀的都是团队中流砥柱的老手,不是你想玩就能玩的。

但是,正所谓机会是留给有准备的人的,如果你的技术成长全是靠业务项目驱动,不去拥抱这些其实非常重要,以后可能会成为主流的东西,职业发展到了一定阶段,可能会遇到高不成低不就的状态。

本文地址: https://www.zhangxinxu.com/wordpress/?p=10454

链接: https://fly63.com/article/detial/11768

使用原生js来控制、修改CSS伪元素的方法总汇, 例如:before和:after

在网页中,如果需要使用辅助性/装饰性的内容的时候,这就需要使用伪元素了。在使用伪元素的时候,会发现js并不真能直接控制它,这篇文章主要就介绍下如果间接的控制、修改css中伪元素的方法

CSS隐藏元素的五种方法

用css隐藏页面元素有许多种方法。1、opacity:0;2、visibility:hidden;3、diaplay:none;4、position:absolute;5、clip-path。大家可以根据具体情况选择适合的方法来隐藏元素

CSS隐藏页面元素常用方法_不同场景下使用CSS隐藏元素

使用 CSS 让元素不可见的方法很多,剪裁、定位到屏幕外、明度变化等都是可以的。虽然它们都是肉眼不可见,但背后却在多个维度上都有差别

js动态生成html元素并为元素追加属性

动态生成HTML元素的方法有三种:document.createElement()创建元素,再用appendChild( )添加、使用innerHTML直接将元素添加到指定节点、jQuery创建节点...

原生js删除元素

通过id删除;通过class获取元素;清空一个元素,即删除一个元素的所有子元素 ;原理很简单,就是不断的判断要清空的div还有没有子节点,有的话就删除一个子节点(这里是它的首个子节点),直到删除完毕为止。

原生JS如何获取当前元素属于父元素第几个子元素

我们经常通过document.getElementById 方法来获取到一个元素,这个时候我们经常需要有一个需求,那就是如何判断这个元素在父元素中的位置。原生JS有一个常见的小技巧那就是通过元素的previousSibling 属性,额外需要注意的是该属性会遍历text节点,即回车键。

在js中获取页面元素的属性值时,弱类型导致的诡异事件踩坑记录

前几天写一个js的时候遇到一个非常诡异的事情,这个问题是这样的,我要获取一个页面的DOM元素的val值,判断这个值是否比某个变量大,这个需求原先数字最大也就是10,现在要改了,可能会更多,这个时候我发现比较大小的判断就出了问题:

JS 创建元素的三种方法

动态创建元素一 document.write()body标签中就会插入但是这种方法几乎不用,因为这回影响页面的布局,甚至会将页面原来的内容冲刷掉,从而只显示输出内容;动态创建元素二 innerHTML

去除inline-block元素间的间距

真正意义上的inline-block水平呈现的元素间,换行显示或者空格隔开的情况下会有间距,这是因为浏览器在解析时,会将换行等读取成一个空格导致。

什么是可替换元素?

请问什么是可替换元素和非可替换元素,它们的差异是什么?并举例说明。前端面试中 HTML 的题目本来就最少,而且并不难,翻来覆去也就那几样。我们之前已经谈到过最经典的 HTML 语义化 ,今天就借此机会来谈谈可替换元素。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!