How to Inherit Custom Elements and Extend New Methods in Other JS

Create a New Web Component with an Old One

This means how to create a new custom element component using an existing custom element component.

For example, there is an A component, which works fine. Then there is a B component, although the semantics are far from the A component, the functional core is the same. At this point, it would be wasteful to reopen a B component, and it would be wrong to use the A component semantics directly.

For example, the core of swipe switching and tab switching is the same. If there is already a Tab component, how can we re-implement a Swipe carousel component in a very simple way? This is the implementation to be explored here.

1. Toast Prompt Component Diagram

However, the tab effect is relatively complicated, and it is not suitable for use as a case, so here we use the toast component as an illustration.

Usually, Toast prompt components are prompt text content. The effect of Loading is similar to the Toast prompt. Therefore, many components integrate this global loading prompt effect into the Toast component.

Functionally, it's not impossible. But from the perspective of semantics and component management, this hint should belong to the Loading component. At this point, you can use component inheritance to customize two completely different custom element components.

2. Code Example

Suppose there is a file named itcodar-toast.js, and the JS code in the file is as follows, which is used to customize the <itcodar-toast> element:

// Define <itcodar-toast> element
class ITCodarToast 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('itcodar-toast')) {
    customElements.define('itcodar-toast', ITCodarToast);
}

export default ITCodarToast;

Implemented very basic capabilities, defined a custom property open, defined show() and hide() methods, defined render() method, and executed when the prompt element is displayed.

At this point, if we want to achieve a full-screen loading effect, we can fully inherit ITCodarToast here. Then redefine a new custom element, such as <itcodar-toast>, to do so.

// Define <itcodar-loading> element
import ITCodarToast from './itcodar-toast.js';
class ITCodarLoading extends ITCodarToast {
    render () {
        // Show loading content
        this.innerHTML = '<i class="spin"></i>';
    }
}
if (!customElements.get('itcodar-loading')) {
    customElements.define('itcodar-loading', ITCodarLoading);
}

It's over in less than ten lines of code. Use extends for an inheritance, and use the customElements.define() method to redefine a custom element. At this point, the open attribute of the <itcodar-toast> component element, as well as the show() and hide() methods are all inherited. For different methods, directly overwrite with the same name. For new methods, direct setup is very flexible.

Finally, as long as the CSS style of the corresponding custom element is added, our needs are realized.

3. Run to Test

Run the program, click the button, and the Toast prompt appears normally and disappears automatically after 3s. And clicking the loading display button shows the effect of loading.

Two effects, one using the <itcodar-loading> element and the other using the <itcodar-loading> element. They appear to be completely different components, but in fact, the kernel code uses the same set. This takes into account both maintainability and semantics.

Enhanced and Expanded the Original Web Components

That is to say, no new custom element components are created, but the original web components need to be enhanced and expanded to become more powerful. Traditionally, this enhanced extension might be integrated into the original component JS file.

In fact, if this enhanced ability is not very commonly used. Or to make it easier to maintain, because independent management can actually be handled in another JS. If you want to use it, import this JS. If you don't need these extension capabilities, you can still import core JS.

The following is an implementation illustration. Several methods are added to the conventional toast prompt implemented above, indicating success prompts, failure prompts and warning prompts. For example, there is a file called toast-extend.js with JavaScript code like this:

// Extend toast
import Toast from './itcodar-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;

At this point, the <itcodar-toast> element executes methods such as success(), which has a prompt effect that includes the status.

From the Perspective of Actual Development

The above two cases mainly demonstrate how to inherit and extend the existing Web Components components. The implementation details will vary in actual development. For example, the appearance of toast is usually not based on the <itcodar-toast> element, but a non-element object for investigation, hiding the details of the dom element itself.

Take the toast-extend.js example above. A better way to handle the developer experience is not a class extension, but a direct static method is more appropriate. E.g:

// Extend toast
import Toast from './itcodar-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;

Assuming that the above code belongs to toast-extend-static.js, at this point, no custom elements are needed on the page. Directly execute the corresponding success method, and the corresponding toast prompt effect will appear.

<button id="button">Success Notification</button>
<script type="module">
import Toast from './toast-extends-static.js';

button.onclick = function () {
    Toast.success('Succeed');
};

That's all for this article. For the development of native Web Components, for many front-end developers, there is no chance to practice in the production environment. Because there are many mature upper component frameworks in the industry. From the perspective of business development, you do not need to go to the foreword and the bottom.

Although many teams have begun to embrace Web Components, to be honest, they are all veterans who are the mainstay of the team, not just what you want to play.

Of course, opportunities are reserved for those who are prepared. If your technology growth is all driven by business projects, it's actually very important not to embrace these things that may become mainstream in the future. But when your career develops to a certain stage, you may encounter a state of being too high and too low.



Leave a reply



Submit