天天看点

实现checkbox组件化(Component) 文章

之前我写了一篇自定义checkbox的文章,通过css3实现自定义的checkbox,并没有使用当今流行的Reactjs, 或者Vuejs之类的进行组件化。但是很显然,这样封装的checkbox组件复用的时候非常麻烦。如果在新项目中使用的话,可能需要同时拷贝css和html文件进行整合。从html语义角度上讲,代码的易读性也不是很强,显然这样的组件显然不利于维护。

其实Web Component是前端界一直非常热衷的一个领域,因为原生的HTML在维护复杂网页应用时,实在是太差了。所以才出现了诸如Google的

Ploymer

、Facebook的

Reactjs

等等。而且很多

MVVM

的框架也自带组件化的方案,例如

Angularjs

的指令,但貌似

ng

的这个用起来太复杂。用第三方组件化的框架去实现的话,你需要依赖框架本身很多东西,很多时候我们只是简单的几个组件,不是很大,也不是很多,所以为了保证组件的

轻量,简单

,其实这个时候我们并不想采用第三方的框架。接下来我会介绍使用Shadow DOM和

registerElement

的方式去实现组件化。

先看看实现后的调用方式:

<div class="line">
    <label>checkbox1
    </label>
    <check-box class="mycheck" checked="true" id="ComCheckbox"></check-box>
</div>
<div class="line">
    <label>checkbox2
    </label>
    <check-box class="mycheck" checked="false" id="ComCheckbox1" value="2"></check-box>
</div>           

看起来是不是很简洁,调用自定义的

checkbox

组件不需要那么多扰乱阅读的元素,只需要一个明确的

check-box

标签,既可以表示

checkbox

组件。效果如下:

实现checkbox组件化(Component) 文章

好了看了效果,我们来看看具体怎么实现的吧。在线demo查看

组件的组成

通常情况下,我们一个组件一般是由

html

模板,

css

样式,

js

脚本逻辑三部分组成的。他们的作用我就不多废话了。至于当前组件的css样式自定义方法请看我上一篇文章CSS3实现自定义checkbox,这里我就不重复这部分了。

  • 在项目工作区新建一个

    component-checkbox.html

    文件, 这个文件会被当做整个组件,在我们需要引用的页面中通过

    link

    标记动态的引入。 

    component-checkbox.html

    文件即包含了HTML模板,CSS样式,JS三个部分,他们在组件文件中的分布如下:
<template>
    <style>// 放CSS样式定义</style>
// 放HTML标记
</template>
<script type="text/javascript">
// JS脚本逻辑
</script>           

具体HTML/CSS定义

<template id="CheckBox">
    <style>
    .slide-checkbox {
        position: relative;
        width: 120px;
        height: 40px;
        line-height: 40px;
        border-radius: 30px;
        background: #4fbe79;
    }
    
    .slide-checkbox input[type=checkbox] {
        visibility: hidden;
    }
    
    .slide-checkbox label {
        position: absolute;
        height: 30px;
        width: 30px;
        left: 5px;
        top: 5px;
        background: #FFFFFF;
        border-radius: 50% 50%;
        -webkit-transition: all .4s ease;
        -moz-transition: all .4s ease;
        -o-transition: all .4s ease;
        -ms-transition: all .4s ease;
        transition: all .4s ease;
    }
    
    .slide-checkbox input[type=checkbox]:checked + label {
        left: 85px;
    }
    </style>
    <div class="slide-checkbox">
        <input type="checkbox" name="checkbox" id="SlideCheck" />
        <label for="SlideCheck"></label>
    </div>
</template>           

JS的实现

这种组件实现发方法,重点地方就在JS脚本这个部分,所以请看下面的详细描述。

1. Shadow DOM说明

Shadow DOM提供了一种独立封装`html', 'css', 'js'到组件文件的一种方法,这样Shadow DOM内部的样式文件及js等等都与引用页面处于隔离状态,互相独立,所以不必担心他们之间会不会出现样式,js相互乱引用的情况出现。当然调用页面与Shadow DOM的通信则需要通过js来完成。

2. registerElement说明

可以在浏览器中实现自定义element, 当然会有人想到说'document.createElement()'方法也可以创建不同的元素,但是很显然

registerElement

更强大些,具体就不展开了。

3. 详细JS代码

// Whether registerElement is supported
function isCustomElementSupported() {
    return 'registerElement' in document;
}

(function() {
    "use strict";
    if (isCustomElementSupported()) {
        var objectPrototype = Object.create(HTMLElement.prototype);
        var selfDoc = document.currentScript.ownerDocument;

        Object.defineProperty(objectPrototype, 'value', {
            get: function() {
                return this.getAttribute("value") || null;
            },
            set: function(value) {
                this.setAttribute("value", value);
            }
        });

        Object.defineProperty(objectPrototype, 'checked', {
            get: function() {
                return this.getAttribute("checked") || false;
            },
            set: function(isChecked) {
                shadowChecked(this, isChecked);
                this.setAttribute("checked", isChecked);
            }
        });

        objectPrototype.createdCallback = function() {
            var self = this;
            var rootElement = self.createShadowRoot();
            var templateContent = selfDoc.querySelector("#CheckBox").content;
            var nodes = document.importNode(templateContent, true);
            
            // Add template content to shadowRoot element
            rootElement.appendChild(nodes);
            
            var checkbox = rootElement.querySelector("#SlideCheck");
            // init checked value
            if (self.checked == "true") {
                checkbox.checked = true;
            }

            // Add change event to checkbox
            checkbox.addEventListener('change', function() {
                self.checked = this.checked;
            });
        };

        var checkbox = document.registerElement('check-box', {
            prototype: objectPrototype
        });
    }

    // update shadow root 
    function shadowChecked(self, isChecked) {
        var shadowCheck = self.shadowRoot.querySelector("#SlideCheck");
        shadowCheck.checked = isChecked