【教学向】再加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) —原理篇

相关文章
相关标签/搜索