【教學向】再加150行代碼教你實現一個低配版的web component庫(2) —原理篇

動圖鎮樓

圖片描述

在線演示: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

Web Component庫大體流程

圖片描述

黑框如下是否是很眼熟,就是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) —原理篇

相關文章
相關標籤/搜索