其實Web Component是前端界一直很是熱衷的一個領域,由於原生的HTML在維護複雜網頁應用時,實在是太差了。因此纔出現了諸如Google的Ploymer
、Facebook的Reactjs
等等。並且不少MVVM
的框架也自帶組件化的方案,例如Angularjs
的指令,但貌似ng
的這個用起來太複雜。用第三方組件化的框架去實現的話,你須要依賴框架自己不少東西,不少時候咱們只是簡單的幾個組件,不是很大,也不是不少,因此爲了保證組件的輕量,簡單
,其實這個時候咱們並不想採用第三方的框架。接下來我會介紹使用Shadow DOM和registerElement
的方式去實現組件化。javascript
先看看實現後的調用方式:css
<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
組件。效果以下:html
好了看了效果,咱們來看看具體怎麼實現的吧。在線demo查看前端
一般狀況下,咱們一個組件通常是由html
模板,css
樣式,js
腳本邏輯三部分組成的。他們的做用我就很少廢話了。至於當前組件的css樣式自定義方法請看我上一篇文章CSS3實現自定義checkbox,這裏我就不重複這部分了。java
component-checkbox.html
文件, 這個文件會被當作整個組件,在咱們須要引用的頁面中經過link
標記動態的引入。 component-checkbox.html
文件即包含了HTML模板,CSS樣式,JS三個部分,他們在組件文件中的分佈以下:<template> <style>// 放CSS樣式定義</style> // 放HTML標記 </template> <script type="text/javascript"> // JS腳本邏輯 </script>
<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腳本這個部分,因此請看下面的詳細描述。node
Shadow DOM提供了一種獨立封裝`html', 'css', 'js'到組件文件的一種方法,這樣Shadow DOM內部的樣式文件及js等等都與引用頁面處於隔離狀態,互相獨立,因此沒必要擔憂他們之間會不會出現樣式,js相互亂引用的狀況出現。固然調用頁面與Shadow DOM的通訊則須要經過js來完成。css3
能夠在瀏覽器中實現自定義element, 固然會有人想到說'document.createElement()'方法也能夠建立不一樣的元素,可是很顯然registerElement
更強大些,具體就不展開了。git
// 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; } })(