前言
上两篇Mvvm教程的热度超出我的预期,很多码友留言表扬同时希望我继续出下一篇教程,当时我也半开玩笑说只要点赞超10就兑现承诺,没想到还真破了10,所以就有了今天的文章。
准备工作
熟读
【教学向】150行代码教你实现一个低配版的MVVM库(1)- 原理篇
【教学向】150行代码教你实现一个低配版的MVVM库(2)- 代码篇
本篇是在上两篇的基础之上对代码进行进一步扩展,从而实现web component功能,所以读者务必掌握mvvm的实现机制才能深入理解本篇的内容(mvvm是web component的基石)。
什么才是好的 web component 设计
目前市面上各大主流前端框架,凡事带web component功能的,他们的设计水准基本都不入我的法眼,唯一看得上眼的是google的polymer,但是在某些API设计层面也显得略微繁琐(想了解polymer的朋友看一翻一下我专栏里面10篇polymer入门系列教程)
什么是component
html提供的原生标签,比如DIV, BUTTON, INPUT家族,Hx家族等等,这些就好比俄罗斯方块里的一块块标准积木,我们称它们为stand component
某一天这些积木不能满足你的需求了,被扩展或被组合形成了非基本形状
这些新形状就是custom component,自定义组件!为什么要有component呢,好处是什么呢?
1. 可以复用
2. 结构清晰
3. 独立开发
你稍微开动下脑筋就能分析出来了,我就不展开了。
我心目中的web component
在座的各位都写过index.html么?很简单
主要就分成3大块内容,style, dom, script
<!--样式-->
<style>
</style>
<!--DOM UI-->
<body>
</body>
<!--逻辑-->
<script>
</script>
然后外面用个<html></html>包裹
所以这期低配版web component库设计目的很简单,作为一个开发人员,我希望在写一个custom component的时候也能按照index.html的原生风格来写,这是多么的优雅,自然,没有学习成本啊!
这也应该是无数人心目中的web component设计
API设计
所以,我们的SegmentFault.js v2.0的Web Component的设计宗旨就是,尽量接近原生的html结构和使用习惯,接近原生从而把学习成本降到最低,是我追求的东西
<!-- myComp.html //文件名还是以.html结尾,自然 -->
<sf-component>
<style>
<!--css-->
</style>
<template>
<!-- any dom-->
<template>
<script>
//js
</script>
<sf-component>
写个具体的例子
<!-- 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>
一个Component的描述文件定义好了,那么接下去就是如何引入它了。沿用上篇Mvvm中的风格,我们给SegmentFault这个Class弄个registerComponent(tagName,compPath)方法,比如在index.html中
var sf = new SegmentFault();
sf.registerController("xxx",xxx);
...
sf.registerComponent("my-comp","components/myComp.html");
...
sf.init();
而在父组件中我们就可以通过"my-comp"这个我们刚刚注册时起的标签名来引入这个组件
<body>
<div>...<div>
<my-comp></my-comp>
</body>
怎么样!四个字:干净利落
一个Web Component库必须具备的基本素(功)养(能)
1. Mvvm 具备双向绑定功能
2. Shadow Style 具有独立的不污染全局的css功能
3. Communication 具有和父子兄弟组件通讯的功能
4. 拥有生命周期 (属于高级功能,本低配版库不涉及)
第一点Mvvm
Mvvm之前已经实现,我们只要套用之前的实现即可
第二点Shadow Style
可能很多人对这个没什么概念,我沿用前文中的内容,比如我们在component中定义了它的style,如
<!-- myComp.html -->
<sf-component>
<style>
button{
color:red;
}
p{
color:yellow;
}
</style>
<template>
<div>
...
</div>
</template>
<script>
...
</script>
</sf-component>
这里我们在<style></style>标签中,定义了css,其中p和button的写法在传统观念中都是会影响html页面中所有的p元素和button元素的,这是我们不希望发生的,我们希望的是这个<style></style>标签生效的作用域仅仅是在当前的,被定义的component中。这种有独立作用域的css就叫Shadow Style。
要实现Shadow Style,其实有比较简单的做法,本篇设计篇中不会涉及,你可以趁此独立思考下,待下篇看看是否与我不谋而合,或者有比我更加高级的方案。
第三点Communication
即组件之间的通讯,经常有人在sf中问到这个组件通讯问题,其实这个问题是有比较标准的答案的,即3点
1. 父子通讯: 父->子 通过 set 属性, 子->父 抛事件
2. 兄弟通讯: 大儿子 抛事件给 -> 父 -> set 小儿子 的属性
3. 远亲通讯: 走消息总线 (其实就在一个单例上搞事件机制)
要实现通讯机制,其实也不复杂,主要就2个功能,1 父组件可以set子组件的属性, 2 组件可以向外层抛事件,外层也可以监听组件抛出的事件,所以,我们会如此设计这块的内容,觉个例子,代码说话
<body>
<div>...<div>
<my-comp sf-msg="vm.message" sf-oncustomevent="vm.customEventHandler"></my-comp>
</body>
大家注意看,从父组件的角度,我可以使用sf- + propertyName(这里是msg) 来实现外部父组件对组件的赋值,而且还能使用sf-on + 自定义事件名称(这里是customevent) 对组件进行监听。
换个角度,从子组件角度出发,我可以被外部赋值,我可以可以向外部dispatch事件。
<sf-component>
<style>
//...
</style>
<template>
<div>
<div class="compClass">
<input type="text" sf-value="this.message" />
<button sf-innerText="this.buttonName" onclick="this.clickHandler()"></button>
<my-comp2 sf-msg="this.message"></my-comp2>
<p sf-innerText="this.message + ', hi Component1'">
</p>
</div>
</div>
</template>
<script>
this.buttonName = "click me";
this.clickHandler = function () {
alert(this.message);
this.dispatchEvent("customevent", "hello world");//为component的vm,内置一个dispatchEvent方法,用法和原生的事件机制一毛一样。
};
Object.defineProperty(this, "msg", {
set: function (value) {
if (value) {
this.message = value;
}
}
});
</script>
</sf-component>
使用Object.defineProperty可以很大程度上满足我们对set property的需求,另外再给component的vm挂载一个内置的函数this.dispatchEvent来发送自定义事件我们就功德圆满了。
第四点生命周期
你可以给一个组件:由注册->加载定义->显示到DOM Tree->内容更新->从DOM Tree移除->销毁 等一系时间节点定义他的生命周期,如果是做的比较考究的库,你可以把这这些时间节点的变更都一一向用户通知,或者提供api供用户控制。本文设计的低配版库阉割了这部分高级功能,我们就是一教学向的库,不整这些有的没的。
结语
至此,设计篇结束,主要介绍了一下本教学库的设计理念和一些web component的基本概念,欢迎点赞收藏评论,投硬笔投香蕉
如果本文阅读没有问题,请继续服用下一篇
【教学向】150行代码教你实现一个低配版的MVVM库(2)- 代码篇
相关阅读
【教学向】150行代码教你实现一个低配版的MVVM库(1)- 原理篇
【教学向】150行代码教你实现一个低配版的MVVM库(2)- 代码篇
【教学向】再加150行代码教你实现一个低配版的web component库(1) —设计篇
【教学向】再加150行代码教你实现一个低配版的web component库(2) —原理篇
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。