WebComponent Hall: Deep into Custom Element from the past to the present

Preface

_When it comes to Custom Element, you must think of a similar HTML Component that fails.HTML Component is a new technology introduced at the beginning of IE5 to "enhance" native elements. Although it is only supported by IE, IE10 has begun to abandon it, and although it is mastered and not used, it still does not affect us to understand it in a research mindset:)

Play HTML Component

_HTML Component is short for htc and consists of two parts: definition and application.The definition part is written in the.htc file (MIME is text/x-component), which consists of htc unique tags, JScript, global objects (elements, windows, etc.), and the application part is written in the html file, which is attached to specific elements through the behavior rules of CSS.

Definition section

**HTC Unique Tags**
_PUBLIC:COMPONENT, root node. _
_PUBLIC:PROPERTY, defines elements that expose custom attributes/attributes. _
_Attribute
_NAME, attribute name used in html file
_INTERNALNAME, the attribute name used in the htc file, defaults to NAME
_VALUE, property default
_PUT, function name corresponding to setter
_GET, function name corresponding to getter
_PUBLIC:EVENT, defines the element to expose custom events. _
_Attribute
_NAME, public event name, such as onheadingchange
_ID, the name of the event used within htc, such as ohc. and then triggered by ohc.fire(createEventObject())
_PUBLIC:ATTACH, Subscribe Events_
_Attribute
_EVENT, the event name of the subscription, such as onheadingchange
_ONEVENT, event handler body, such as headingchangehandler()
_FOR, the host of the event (element,document,window, element by default)
_PUBLIC:METHOD, Define Element Exposure Method_
_Attribute
_NAME, method name used in html file
_INTERNALNAME, the method name used in the htc file, defaults to NAME.Implement specific method body in JScript
_PUBLIC:DEFAULTS, set HTC default configuration_
**HTC Life Cycle Events**
ondocumentready, triggered when added to DOM tree, triggered after oncontentread
oncontentready, triggered when added to DOM tree
ondetach, triggered when you detach from the DOM tree, also triggered when you refresh the page
oncontentsave, triggered when copying (ctrl-c) elementary content
**HTC Global Objects**
Element, the element instance attached to
runtimeStyle, the style attribute of the attached element instance
Document, html document object
**HTC Global Functions**
createEventObject(), create event object
Attach Event (evtName, handler), Subscribe to Events. Note: Attach Event is not generally recommended to subscribe to events. Subscribe to events with <PUBLIC:ATTACH> which will automatically help us perform detach operations to avoid memory leaks.
detachEvent(evtName[, handler]), unsubscribe event

Application section

Introducing.htc
1. Basic Opening Method

<style>
  css-selector{
    behavior: url(file.htc);
  }
</style>

2. Open multiple

<style>
  css-selector{
    behavior: url(file1.htc) url(file2.htc);
  }
</style>

_You can see that matching elements through css-selector and attaching htc to the elements makes it feel like Angular JS specifies additional elements through attribute E!
3. Custom Elements

<html xmlns:x>
    <head>
        <style>
            x\:alert{
                behavior: url(x-alert.htc);
            }
        </style>
    </head>
    <body>
        <x:alert></x:alert>
    </body>
</html>

_Custom elements are cumbersome by specifying the namespace x:alert for the custom element and listing the namespace xmlns:x on the HTML node.(Multiple namespaces can coexist <html xmlns:x xmlns:y>)
_Let's try to define an x:alert element to see how it works!

Custom x:alert element

x-alert.htc

<PUBLIC:COMPONENT>
    <PUBLIC:ATTACH EVENT="oncontentready" ONEVENT="onattach()"></PUBLIC:ATTACH>
    <PUBLIC:ATTACH EVENT="ondetach" ONEVENT="ondetach()"></PUBLIC:ATTACH>

    <PUBLIC:METHOD NAME="close"></PUBLIC:METHOD>
    <PUBLIC:METHOD NAME="show"></PUBLIC:METHOD>

    <PUBLIC:PROPERTY NAME="heading" PUT="putHeading" SET="setHeading"></PUBLIC:PROPERTY>
    <PUBLIC:EVENT NAME="onheadingchange" ID="ohc"></PUBLIC:EVENT>
    <PUBLIC:ATTACH EVENT="onclick" ONEVENT="onclick()"></PUBLIC:ATTACH>

    <script language="JScript">
        /* 
         * private region
         */
        function toArray(arrayLike, sIdx, eIdx){
           return Array.prototype.slice.call(arrayLike, sIdx || 0, eIdx || arrayLike.length)
        }
        function curry(fn /*, ...args*/){
            var len = fn.length
              , args = toArray(arguments, 1)

            return len <= args.length 
                   ? fn.apply(null, args.slice(0, len)) 
                   : function next(args){
                        return function(){
                            var tmpArgs = args.concat(toArray(arguments))
                            return len <= tmpArgs.length ? fn.apply(null, tmpArgs.slice(0, len)) : next(tmpArgs)
                        }
                     }(args)
        }
        function compile(tpl, ctx){
            var k
            for (k in ctx){
                tpl = tpl.replace(RegExp('\$\{' + k + '\}'), ctx[k]
            }
            return tpl
        }

        // Element internal structure
        var tpl = '<div class="alert alert-warning alert-dismissible fade in">\
                        <button type="button" class="close" aria-label="Close">\
                          <span aria-hidden="true">&times;</span>\
                        </button>\
                        <div class="content">${raw}</div>\
                      </div>'
        var getHtml = curry(compile, tpl)
        /* 
         * leftcycle region
         */
        var inited = 0, oHtml = ''
        function onattach(){
            if (inited) return

            oHtml = element.innerHTML
            var ctx = {
                raw: heading + oHtml
            }
            var html = genHtml(ctx)
            element.innerHTML = html

            runtimeStyle.display = 'block'
            runtimeStyle.border = 'solid 1px red'
        }
        function ondetach(){}
        /* 
         * public method region
         */
        function show(){
            runtimeStyle.display = 'block'
        }
        function close(){
            runtimeStyle.display = 'none'
        }
        /*
         * public property region
         */
        var heading = ''
        function putHeading(val){
            if (heading !== val){
                setTimeout(function(){
                    var evt = createEventObject()
                    evt.propertyName = 'heading'
                    ohc.fire(evt)
                }, 0)
            }
            heading = val
        }
        function getHeading(){
            return heading
        }

        /*
         * attach event region
         */
        function onclick(){
            if (/^\s*close\s*$/.test(event.srcElement.className)){
                close()
            }
        }
    </script>
</PUBLIC:COMPONENT>

Reference x:alert

index.html

<html xmlns:x>
<head>
    <title></title>
    <style>
        x\:alert{
            behavior: url(x-alert.htc);
        }
    </style>
</head>
<body>
    <x:alert id="a" heading="Hello world!"></x:alert>    
    <script language="JScript">
        var a = document.getElementById('a')
        a.onheadingchange = function(){
            alert(event.propertyName + ':' + a.heading)
        } 
        // a.show()
        // a.close()
        // document.body.appendChilid(document.createElement('x:alert'))
    </script>
</body>
</html>

feel

_When writing HTC, I feel like writing C. I declare events, attributes, methods, etc. through HTC unique tags, and then provide specific implementation through JScript. In fact, I feel the same when writing Angular2, but the feeling here is stronger.
Here's a list of the surprises HTC gave me when developing!
1. The JScript code in the htc file is scoped to the htc file itself and does not pollute the script context of the html file;
2. Custom attributes with attribute accessors greatly improve our control over custom attributes;

And then there's the slot
1. The HTC behavior is separated from element binding, which has the advantage of flexibility and the disadvantage of non-self-contained. It is too verbose for the user to bind itself once for each introduction.I think that Angular is the right way to bind elements flexibly and self-contained through attribute E!
2. The API has a bug.If the ondocumentread event says it will trigger when the html document is loaded, it will trigger only once. In fact, it will always trigger after the oncontentread event. There is no API for fireEvent at all. It just inherits the pits of IE as before.
3. Setting inline style through runtimeStyle will lose the benefits of inheriting, cascading, and other CSS features;
4. The internal structure of a custom element is influenced by external JS and CSS, not a truly closed element.

summary

_I'm sorry that the content of this article is quite correct as described in the title. For a more comprehensive view, please check Mr. Xu Fei's The Crisis of Web Components from the Decline of HTML Components .If you look at Custom Element alone, it's no different from HTML Component and doesn't completely solve the problem of custom elements/components, but in addition to Custom Element, Web Component has three other good partners (Shadow DOM,template,html imports) working together to provide a complete solution for custom elements, of which Shadow DOM canIt is said that the most important thing is to continue the research in the future:)
_Respect the original, reprint from: http://www.cnblogs.com/fsjohnhuang/p/5987853.html ^^Fatty John

Thank

The Crisis of Web Components from the Decline of HTML Components
HTC Reference
Using HTML Components to Implement DHTML Behaviors in Script

Keywords: Attribute IE angular Windows

Added by Assorro on Wed, 03 Jul 2019 19:38:51 +0300