学什么东西都从hello world开始, 我也不知道为啥。

恩,先上demo代码, 然后提出问题, 之后解答问题, 最后源码说明。

hello world - demo:

        class Hello extends Omi.Component {    // 1. Hello类先继承Component类constructor(str, data) {    // 2. Hello类构造函数的参数和个数随便传,但是必须要有个数据对象data(其实可以是对象或者传undefined,因为其还有第二个参数,不传undefined的话,第二个参数就变成了第一个参数)super(data);    //  3. es6和es5的继承还是有区别的,es6需要先得到父类的this实例,然后子类对其加工。Component父类其实可以接受2个参数的,这里就先接受data数据对象作为第一个参数this.str = str;console.log(this);}style() {    // 4. style方法其实是Hello类重写了Component类的style方法(其实父类的style方法也只是空函数)return `h1 {color: red;}`;}clickHandle(t, evt) {    // 5. Hello类的原型方法和Component类没关系哈
                console.log(t, evt);}render() {    // 6. render方法也是Hello类重写了Component类的render方法return `<h1 οnclick="clickHandle(this, event)">aaa{{name}}</h1>
                `;}};var hello = new Hello('str', {name: 'hello world'});    // 7. 创建Hello类的实例Omi.render(hello, '#app');    // 8.让omi渲染(生成html和局部css和把内置事件和对应的实例clickHandle函数关联起来)

先看看omi中文文档的说明:

组件生成的HTML最终会插入到#app中。上面的例子展示了Omi的部分特性:

  • data传递: new Hello(data,..)的data可以直接提供给render方法里的模板
  • 局部CSS: h1只对render里的h1生效,不会污染外面的h1
  • 声明式事件绑定: onclick调用的就是组件内的handleClick,this可以拿到当前的DOM元素,还可以拿到当前的event
  • 文档地址:https://alloyteam.github.io/omi/website/docs-cn.html#

接下来说说这个demo的疑问和疑问的说明:

疑问1:
自己写的类一定要继承Omi.Component类吗?

答:废话,想用omi,你还不继承别人的属性和方法,怎么玩下去(当然牛逼的人可以自己写哈)。
注: Component类是核心, 源码在component.js中,然后
Omi.Component = Component; 把Component类挂载到Omi的Component对象上去了。

疑问2:
super()方法中可以传什么数据类型的参数,和参数的个数?

答:Component构造函数可以接收2个参数。

理论上可以有这几种传参的方式:

传1个参数 super()/super(undefined), super({}), super('str'), super(true), super([]), super(null)

传2个参数 super(data, 真值)

先说传1个参数会导致啥吧:

传 true, 'str', [], null, 会使变量isReRendering则为true, {}, undefined/或者不传参数, 变量isReRendering则为false,然而isReRendering变量是if的条件会开了2个分支,

处理不同的逻辑。

传2个参数会怎样啊:

第二个参数可以任意类型的值:因为会和对象{server: false, ignoreStoreData: false}合并

感受下omi的源码:

constructor(data, option) {    // data: 数据data, option: 一般为对象const componentOption = Object.assign({    // 和并optionserver: false,    // 老版中的server属性ignoreStoreData: false    // 忽略存储数据
        }, option);this._omi_ignoreStoreData = componentOption.ignoreStoreData;    // 是否忽略存储数据属性_omi_ignoreStoreData//re render the server-side rendering html on the client-sideconst type = Object.prototype.toString.call(data);    // data的数据类型const isReRendering = type !== '[object Object]' && type !== '[object Undefined]';    // 是否重新渲染if (isReRendering) {this.renderTo = typeof data === "string" ? document.querySelector(data) : datathis._hidden = this.renderTo.querySelector('.omi_scoped__hidden_data')this.id = this._hidden.dataset.omiIdthis.data = JSON.parse(this._hidden.value)} else {this.data = data || {};    // 给实例添加 data属性this._omi_server_rendering = componentOption.server;    // _omi_server_rendering属性this.id = this._omi_server_rendering ? (1000000 + Omi.getInstanceId()) : Omi.getInstanceId();    // id属性
        };this.refs = {};this.children = [];    // 每个实例的孩子this.childrenData = [];    // 每个实例孩子的数据this.HTML = null;    // 实例中render返回的字符串this._addedItems = [];Omi.instances[this.id] = this;    // Omi._instanceId 对应 Component类的每个实例(或者子类)this.dataFirst = true;    this._omi_scoped_attr =  Omi.STYLESCOPEDPREFIX + this.id;    // 实例的样式局部属性 omi_scoped_ + id//this.BODY_ELEMENT = document.createElement('body')this._preCSS = null;    // 预设样式this._omiGroupDataCounter = {}; if (this._omi_server_rendering || isReRendering) {this.install()this._render(true)this._childrenInstalled(this)this.installed()}}

疑问3:
style()方法是干啥的?

答: style方法返回一个css字符串,用来生成局部css的。style方法中可以写各种语句哈。只要返回css字符串即可。

疑问4:
render()方法是干啥的?

答:render方法返回一个html字符串,就是html组合好的标签啦。render方法中可以写各种语句哈。只要返回字符串即可。

疑问5:

那omi是怎么帮我们生成局部css和html插入到指定的dom容器中呢。html内置的事件又是怎样对应起Hello类中clickHandle方法?

答:这一切就得从Omi.render(hello, '#app'); 这个语句开始。

Omi.render = function(component , renderTo , incrementOrOption){    // 实例, 渲染到的dom, xxcomponent.renderTo = typeof renderTo === "string" ? document.querySelector(renderTo) : renderTo;    // 实例的renderTo属性if (typeof incrementOrOption === 'boolean') {component._omi_increment = incrementOrOption;    // 实例的_omi_increment 属性(老版)} else if (incrementOrOption) {    // 新增component._omi_increment = incrementOrOption.increment;component.$store = incrementOrOption.store;if (component.$store) {component.$store.instances.push(component);};component._omi_autoStoreToData = incrementOrOption.autoStoreToData;};component.install();    // Component类的install方法(被实例继承了)component._render(true);    // Component类的_render方法(被实例继承了)
        component._childrenInstalled(component);component.installed();return component;}

render方法就omi上的一个静态方法,接收3个参数(实例, 渲染到的dom, xx), xx表示我也不清楚这个变量干啥的,以后肯定会知道的。
      方法中的这个语句对于这个demo很重要component._render(true);接下来终点看看这个方法.

这个方法里面对于这个demo最重要的语句就是
      this._generateHTMLCSS(); // 生成 html 和 css, 怎么生成html和css呢,看如下代码

    _generateHTMLCSS() {    // 生成css 和 htmlthis.CSS = (this.style()|| '').replace(/<\/?style>/g,'');    // 处理下style()方法中的字符串样式if (this.CSS) {this.CSS = style.scoper(this.CSS, "[" + this._omi_scoped_attr + "]");    // 给css标签搞成 (标签名[omi_scoped_0], [omi_scoped_0] 标签名) 变成属性选择器if (this.CSS !== this._preCSS && !this._omi_server_rendering) {    // 现在的CSS不等于_preCSS 且 _omi_server_rendering 为假值style.addStyle(this.CSS, this.id);    // 在head中添加局部cssthis._preCSS = this.CSS;    // 本次的css存一下
            };};let tpl = this.render();    // 用户提供的html字符串this.HTML = this._scopedAttr(Omi.template(tpl ? tpl : "", this.data), this._omi_scoped_attr).trim();    // 给每个html元素添加omi_scoped_0 = '', 有模板数据的也计算好了. eg: <h1 omi_scoped_0 οnclick="clickHandle(this, event)">aaahello world</h1>if (this._omi_server_rendering) {this.HTML = '\r\n<style id="'+Omi.STYLEPREFIX+this.id+'">\r\n' + this.CSS + '\r\n</style>\r\n'+this.HTMLthis.HTML += '\r\n<input type="hidden" data-omi-id="' + this.id + '" class="' + Omi.STYLESCOPEDPREFIX + '_hidden_data" value=\'' + JSON.stringify(this.data) + '\'  />\r\n'}}

局部css生成好了,并且添加到了head中了,html也生成好了,并且把data数据也生成好了,这里使用的是Mustache模板。
      那html中的声明式事件绑定怎么和clickHandle方法对应的呢,代码如下:

// event.js 文件 正则不好,感兴趣的可以研究一把
function scopedEvent(tpl,id) {    // 模板字符串, idreturn tpl.replace(/<[\s\S]*?>/g, function (item) {return item.replace(/on(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave|Abort|Blur|Cancel|CanPlay|CanPlayThrough|Change|Click|Close|ContextMenu|CueChange|DblClick|Drag|DragEnd|DragEnter|DragLeave|DragOver|DragStart|Drop|DurationChange|Emptied|Ended|Error|Focus|Input|Invalid|KeyDown|KeyPress|KeyUp|Load|LoadedData|LoadedMetadata|LoadStart|MouseDown|MouseEnter|MouseLeave|MouseMove|MouseOut|MouseOver|MouseUp|MouseWheel|Pause|Play|Playing|Progress|RateChange|Reset|Resize|Scroll|Seeked|Seeking|Select|Show|Stalled|Submit|Suspend|TimeUpdate|Toggle|VolumeChange|Waiting|AutoComplete|AutoCompleteError|BeforeCopy|BeforeCut|BeforePaste|Copy|Cut|Paste|Search|SelectStart|Wheel|WebkitFullScreenChange|WebkitFullScreenError|TouchStart|TouchMove|TouchEnd|TouchCancel|PointerDown|PointerUp|PointerCancel|PointerMove|PointerOver|PointerOut|PointerEnter|PointerLeave)=(('([\s\S]*?)')|("([\s\S]*?)"))/g, function (eventStr, b, c) {if (c.indexOf('Omi.instances[') === 1) {    // 声明式事件函数如果包含Omi.instances[ 的话return eventStr;    // 那就直接返回 "οnclick="Omi.instances[0].clickHandle(this, event)""} else if (c.lastIndexOf(')') === c.length - 2) {    // 找到c指定的)最后出现的位置 和 去掉2个"" 相等的话return eventStr.replace(/=(['|"])/, '=$1Omi.instances[' + id + '].');   // eg: "οnclick="Omi.instances[0].clickHandle(this, event)""} else {let str = eventStr.replace(/=(['|"])/, '=$1Omi.instances[' + id + '].');return str.substr(0, str.length - 1) + "(event)" +  str.substr(str.length - 1, 1);};});});
}

内置事件也对应好了,那就把html插到指定的dom容器中去吧。

this.renderTo.innerHTML = this.HTML;

ps:

好了, hello world的这个demo就这么说完了, 这个简单的demo只是抽取了对应的源码,
每个demo都将只抽取对应源码, 等到所有demo写完,omi源码基本就明白是怎么一回事了。

如果写的有问题,欢迎指出,也可以进群(看开篇扯蛋的帖子)和原作者交流。哈哈

转载于:https://www.cnblogs.com/sorrowx/p/6582601.html

Omi框架学习之旅 - Hello World 及原理说明相关推荐

  1. Omi框架学习之旅 - 生命周期 及原理说明

    生命周期 name avatars company constructor 构造函数 new的时候 install 初始化安装,这可以拿到用户传进的data进行处理 实例化 installed 安装完 ...

  2. Omi框架学习之旅 - 插件机制之omi-touch 及原理说明

    这个插件也能做好多好多的事,比如上拉下拉加载数据,轮播,等一切和运动有关的特效. 具体看我的allowTouch这篇博客,掌握了其用法,在来看它是怎么和omi结合的.就会很简单. 当然使用起来也比较方 ...

  3. Omi框架学习之旅 - 插件机制之omi-finger 及原理说明

    以前那篇我写的alloyfinger源码解读那篇帖子,就说过这是一个很好用的手势库,hammer能做的,他都能做到, 而且源码只有350来行代码,很容易看懂. 那么怎么把这么好的库作为omi库的一个插 ...

  4. Omi框架学习之旅 - 通过对象实例来实现组件通讯 及原理说明

    组件通讯不是讲完了吗(上帝模式还没讲哈),怎么又多了种方式啊. 你484傻,多一种选择不好吗? 其实这个不属于组件通讯啦,只是当父组件实例安装和渲染完毕后,可以执行installed这个方法(默认是空 ...

  5. 滴滴Booster移动APP质量优化框架 学习之旅 三

    推荐阅读: 滴滴Booster移动App质量优化框架-学习之旅 一 Android 模块Api化演练 不一样视角的Glide剖析(一) 滴滴Booster移动App质量优化框架-学习之旅 二对重复资源 ...

  6. 滴滴Booster移动APP质量优化框架 学习之旅 二

    推荐阅读: 滴滴Booster移动App质量优化框架-学习之旅 一 Android 模块Api化演练 不一样视角的Glide剖析(一) 续写滴滴Booster移动APP质量优化框架学习之旅,上篇文章分 ...

  7. Django web框架学习之旅(4)

    <Django Web 框架> 目录 Django shell的使用 admin 后台数据库管理 自定义后台管理数据表 修改后台Models的展现形式 模型管理器类 数据库表管理 数据表关 ...

  8. Django web 框架学习之旅(3)

    <Django Web 框架> 目录 静态文件 Django中的应用 - app 什么是应用(app) 创建应用app Django应用的结构组成 数据库 和 模型 Django下使用my ...

  9. Spring Security 框架学习之十二 单点登录原理(部分注解是我原创,其余是转载网上电子书内容,献丑了,写的不对请大家见谅,如有侵权我立即删除)(主要是为了自己学的知识备忘)

      下图中的redis通常作为抽离出来的独立的外部session对象数据容器 (上面说的是:如果将共享顶级域名下的各个子系统的sessionId(会话标识信息),session对象数据信息,用户身份认 ...

最新文章

  1. Java数据结构——解析算术表达式
  2. SliverLight注册字典转换器方法
  3. Oracle+Python适合 Oracle DBA 使用的 Python
  4. 更强、更稳、更高效:解读 etcd 技术升级的三驾马车
  5. SAP ABAP:获取汇率的完整实现之一
  6. [BUUCTF-pwn]——axb_2019_fmt32
  7. css 实现16:9比例自适应手机尺寸,可设置任意比例
  8. quot;蓝筹quot;如何使程序猿?
  9. JS几种数组遍历方式以及性能分析对比
  10. go 怎么等待所有的协程完成_Go语言中的sync.Cond 的特点与用法
  11. Spring mvc+ Hibernate的基础dao类。
  12. 木马群起攻击Word文档 360补丁保护办公安全
  13. 计算机断网后怎么连接网络连接,电脑突然断网, 连接不上网络怎么办? 三种方法轻松找回...
  14. 用Vue-cli从头搭建项目
  15. 此计算机没有Intel处理器,而加速Android仿真器需要该处理器
  16. 通信专业实务(四)——互联网
  17. 软件需求工程 高校教学平台 软件需求规格说明书 part 1 (重点!!!)
  18. window10中的ssh通过代理连接目标服务器
  19. RPA机器人流程自动化(Robotic process automation)
  20. msm8974 camera reset pin时序问题汇总

热门文章

  1. 什么叫冷备用状态_开关在运行、冷备用、热备用分别指开关在什么状态?
  2. 什么是Injective Protocol
  3. 程序员拿到阿里巴巴的入职通知书,却因为工资“低”不想去?狂
  4. 重装系统——win10
  5. SSM框架的汽车销售管理系统
  6. C++ API 设计 08 第三章 模式
  7. 《安富莱嵌入式周报》第254期:2022.02.21--2022.02.27
  8. 再谱新篇 | 美格智能SLM750模组连获日本三大运营商权威认证
  9. Python:shape函数用法
  10. 树莓派激光雷达导航小车底盘的基本操作