在線演示:https://momoko8443.github.io/...css
書接上文 【教學向】再加150行代碼教你實現一個低配版的web component庫(1) —設計篇html
上文說道一個基本款的custom web component由3大部分組成,同時也必須具有4大功能git
三大部分是github
1. Template(DOM) 2. Style 3. Script (viewModel)
四大功能是web
1. Mvvm 2. Shadow Style 3. Communication 4. Lifecycle (本文不涉及LC的API,但在實現中會隱形的涵蓋這部份內容)
Component定義文件格式以下segmentfault
<!-- myComp.html --> <sf-component> <style> button{ color:red; } p{ color:yellow; } </style> <template> <div> <input type="text" sf-value="this.message"/> <button sf-innerText="this.buttonName" onclick="this.clickHandler()"></button> <p sf-innerText="this.message"> </p> </div> </template> <script> this.message = "this is a component"; this.buttonName = "click me"; this.clickHandler = function(){ alert(this.message); }; </script> </sf-component>
接下去,本篇就會一一講解各個點的原理和大體實現思路,具體代碼會在第三篇 代碼篇中給出mvvm
黑框如下是否是很眼熟,就是Mvvm篇中的流程。加入Component功能咱們幾乎不用動Mvvm部分的代碼,只要在調用Scanner掃描viewModel和view的映射關係以前,咱們把含有Component tag的主DOM Tree升級加工便可。其實Component定義文件中的<template/>和<script/>也是view和viewModel的關係。咱們把Component的定義文件渲染到主DOM Tree上翻譯成view和viewModel的關係,再由Mvvm篇中的Scanner,Renderer作掃描和渲染便可。是否是很簡單?this
咱們把着重點放在黑框上面的部分,也就是生成Component的流程,咱們更加圖中的steps,一步步來看
先放張局部大圖spa
Step 1:RegisterComponent,這一步,是要在SF庫init初始化以前就要進行的,咱們給新的component起個名字tagName,好比my-comp,這樣咱們在之後就能夠用<my-comp/>這個tag在任何地方引入這個component,另外還須要把component定義文件的路徑告訴SF,方便其在初始化的時候加載這些定義文件翻譯
//僞代碼 var sf = new SegmentFault(); sf.registerComponent("my-comp","./components/myComp.html"); sf.init();
Step 2 3 4: Loader加載器在sf.init()時被調用,去加載"./components/myComp.html"這些路徑上的component定義文件,而且把這些定義和tagName造成一份Map返回給SF
Step 5: (第五步至關重要,web component 99%的精髓都在這一步,請認真閱讀)
SF拿到Map後,通知Generator去掃描DOM Tree一旦發現有<my-comp/>標籤出現,則使出DOM替換大法,把Map中my-comp對應的component定義中的template部分的DOM,替換上去。以下圖
DOM替換大法
Q:辣麼,Component定義中的<script>裏的viewModel怎麼辦?
先上一張美圖,你們思考3分鐘
A: 使用new Function()或者eval把<script/>中的viewModel生成一個function,咱們姑且叫它CompViewModel,而後把template
上的sf-xxx=「this.xxxx」的attribute中,等式的左邊所有含有this的部分,替換成vm_隨機數,好比
<template> <div> <p sf-innerText="this.message"></p> </div> </template>
替換成
<template> <div> <p sf-innerText="vm_2333.message"></p> </div> </template>
還記得這個vm_2333是什麼的?沒錯若是你沒有白看Mvvm那兩篇教程的話,vm_2333就是viewModel實例的alias。那還等什麼?趕忙調用sf.registerViewModle("vm_2333",new CompViewModel())註冊這個component的viewModel吧!
有沒有發現web component庫的套路,是否是很簡單?第一步,把index.html(或父組件)中含有的component tagName找出來,而後一通替換和假裝,第二步,讓SF把它當成Mvvm篇中的普通view-viewModel和關係去處理便可。
template和script處理完了,那麼接下去就只剩下style,如何讓<style>標籤中的css定義的做用於只發生在當前?
我給出的辦法是,仍是移花接木大法
<sf-component> <style> p{ color:red; } </style> </sf-component>
第一步,要把這坨css加到index.html的head中去,這樣css纔會生效,可是這樣會污染全局
<html> <head> ... <style type=text/css> p{ color:red; } </style> </head>
第二步,把這坨css進行加工,加上做用域 .myComp ,這樣的話,根據css selector語義,只有在class="myComp"的DOM下的p元素纔會生效
<html> <head> ... <style type=text/css> .myComp p{ color:red; } </style> </head>
第三步,固然是給表明component的DOM最外層上增長一個叫myComp的class了,一個簡單版的Shadow Style就這樣實現了。
至此,一個component的三大組成說完,四大功能還剩communication沒有講
很簡單,實現2個接口便可實現組件通信,具體見上篇《設計篇》有提到
1. Component的屬性能夠被父組件set進值 2. viewModel能夠向外dispatch事件
這2個接口均可以在step 5中經過一些小動做,給加進去,本篇就不具體解釋了,做爲思考題你們回去思考,俗話說的的talk is cheap,show me the code,具體實現會在第三篇《代碼篇》中給出,你們看了本身一目瞭然,比我這裏浪費口舌能更好的理解。
《原理篇》到此結束,下一篇《代碼篇》會在這兩日放出,不過前提仍是點贊超10,最後歡迎你們點贊評論收藏,投硬幣,投香蕉,咱們下次再見。
【教學向】150行代碼教你實現一個低配版的MVVM庫(1)- 原理篇
【教學向】150行代碼教你實現一個低配版的MVVM庫(2)- 代碼篇
【教學向】再加150行代碼教你實現一個低配版的web component庫(1) —設計篇
【教學向】再加150行代碼教你實現一個低配版的web component庫(2) —原理篇