分分钟写出Vue原理
第一步完成深度观察
class Vue { constructor (options) { this.$el = options.el; this.$options = options; this.$data = options.data; if (this.$el) { new Observer(this.$data) } }
} class Observer { constructor(data) { this.observe(data) } observe (obj) { if (obj && typeof obj === 'object') { for (const key in obj) { this.defineReactive(obj, key, obj[key]) } } } defineReactive (obj, key, value) { this.observe(value) Object.defineProperty(obj, key, { get () { return value }, set: (newValue) => { if (value !== newValue) { value = newValue this.observe(newValue) } } }) }
}
第二步将DOM放到内存中
class Vue { constructor (options) { this.$el = options.el; this.$options = options; this.$data = options.data; if (this.$el) { new Observer(this.$data) new Compiler(this.$el, this) } }
} class Compiler { constructor (el, vm) { this.vm = vm; this.el = this.isElementNode(el) ? el : document.querySelector(el); let fragment = this.nodeFragment(this.el); this.compile(fragment) this.el.appendChild(fragment) } compile (node) { console.log(node, '分析DOM节点') } nodeFragment (node) { let fragment = document.createDocumentFragment() let firstChild; while (firstChild = node.firstChild) { fragment.appendChild(firstChild) } return fragment } isElementNode (node) { return node.nodeType === 1; }
}
第三步分析模板里面的内容
let CompileUtil = { text (node, expr, vm) { let handler = this.updater['text'] let content = expr.replace(/\{\{(.+?)\}\}/, (...args) => { return this.getValue(args[1], vm) }) handler(node, content) }, getValue(expr, vm) { return expr.split('.').reduce((data, current) => { return data[current] }, vm.$data) }, updater: { text (node, value) { node.textContent = value } }
} class Compiler { constructor (el, vm) { this.vm = vm; this.el = this.isElementNode(el) ? el : document.querySelector(el); let fragment = this.nodeFragment(this.el); this.compile(fragment) this.el.appendChild(fragment) } compile (node) { let nodeList = node.childNodes; Array.from(nodeList, child => { if (this.isElementNode(child)) { this.compileElement(child) this.compile(child) } else { this.compileText(child) } }) } compileElement (node) { // 分析元素节点 } compileText (node) { // 分析文本节点 // 1. 小胡子语法里面要替换成我们想要的内容 let content = node.textContent; if (/\{\{(.+?)\}\}/.test(content)) { CompileUtil.text(node, content, this.vm) } } nodeFragment (node) { let fragment = document.createDocumentFragment() let firstChild; while (firstChild = node.firstChild) { fragment.appendChild(firstChild) } return fragment } isElementNode (node) { return node.nodeType === 1; }
}
第三步观察者模式进行绑定
class Dep { constructor() { this.subs = [] } addSub(watcher) { this.subs.push(watcher) } notify() { this.subs.forEach(watcher => watcher.update()) }
} class Watcher { constructor(vm, expr, cb) { this.vm = vm; this.expr = expr; this.cb = cb; this.oldVale = this.get() } get () { Dep.target = this; // 取值操作 let value = CompileUtil.getValue(this.expr, this.vm) Dep.target = null; return value } update () { let newValue = CompileUtil.getValue(this.expr, this.vm) if (newValue !== this.oldVale) { // 当比较两个值不相等的情况下执行回调 this.cb(this.newValue) } }
} class Vue { constructor(options) { this.$el = options.el; this.$options = options; this.$data = options.data; if (this.$el) { new Observer(this.$data) new Compiler(this.$el, this) } }
} class Observer { constructor(data) { this.observe(data) } observe(obj) { if (obj && typeof obj === 'object') { for (const key in obj) { this.defineReactive(obj, key, obj[key]) } } } defineReactive(obj, key, value) { this.observe(value) let dep = new Dep() Object.defineProperty(obj, key, { get() { Dep.target && dep.addSub(Dep.target) return value }, set: (newValue) => { if (value !== newValue) { value = newValue this.observe(newValue) dep.notify() } } }) }
} let CompileUtil = { text(node, expr, vm) { let handler = this.updater['text'] let content = expr.replace(/\{\{(.+?)\}\}/, (...args) => { new Watcher(vm, args[1], () => { // 处理函数 handler(node, this.getContentValue(vm, expr)) }) return this.getValue(args[1], vm) }) handler(node, content) }, getContentValue (vm, expr) { return expr.replace(/\{\{(.+?)\}\}/, (...args) => { return this.getValue(args[1], vm) }) }, getValue(expr, vm) { return expr.split('.').reduce((data, current) => { return data[current] }, vm.$data) }, updater: { text(node, value) { node.textContent = value } }
} class Compiler { constructor(el, vm) { this.vm = vm; this.el = this.isElementNode(el) ? el : document.querySelector(el); let fragment = this.nodeFragment(this.el); this.compile(fragment) this.el.appendChild(fragment) } compile(node) { let nodeList = node.childNodes; Array.from(nodeList, child => { if (this.isElementNode(child)) { this.compileElement(child) this.compile(child) } else { this.compileText(child) } }) } compileElement(node) { // 分析元素节点 } compileText(node) { // 分析文本节点 // 1. 小胡子语法里面要替换成我们想要的内容 let content = node.textContent; if (/\{\{(.+?)\}\}/.test(content)) { CompileUtil.text(node, content, this.vm) } } nodeFragment(node) { let fragment = document.createDocumentFragment() let firstChild; while (firstChild = node.firstChild) { fragment.appendChild(firstChild) } return fragment } isElementNode(node) { return node.nodeType === 1; }
}
分分钟写出Vue原理相关推荐
- 狗屁不通文章生成器登顶GitHub热榜,分分钟写出万字形式主义大作
前言 GitHub 被誉为全球最大的同性交友网站,--,陪伴我们已经走过 10+ 年时间,它托管了大量的软件代码,同时也承载了程序员无尽的欢乐. 上周给大家分享了一篇10个让你笑的合不拢嘴的Githu ...
- 100个标题模板,让你分分钟写出10万+爆文!
什么样的标题才能吸引读者,这是每一位编辑都必须面对的问题. 网上有各种各样的理论教程,也是很多老司机的经验之谈. 但是真的把这些技巧融汇贯通,需要慢慢的积累经验. 而对于大多数新上路的自媒体运营者来说 ...
- 他写出了 Vue,却做不对这十道 Vue 笔试题
有十道关于 Vue 的选择题,在群里引出了一众社区知名人士竞折腰,最后钓出了 Evan You 本人亲自挑战-- 然后他自己也做错了(其中的某两道). 鲁迅会做错鲁迅文选的阅读理解?有截图为证: 所以 ...
- [vue] 写出你知道的表单修饰符和事件修饰符
[vue] 写出你知道的表单修饰符和事件修饰符 事件修饰符.stop .prevent .capture .self .once .passive 表单修饰符.number .lazy .trim 个 ...
- [vue] 写出多种定义组件模板的方法
[vue] 写出多种定义组件模板的方法 1.字符串 2.模板字面量 3.<script type="x-template"></script> 4.文件组件 ...
- 【视频联动】编译原理:写出布尔表达式A or (B and not(C or D)) 的四元式序列。说明:按照控制语句中的布尔表达式翻译
编译原理:写出布尔表达式A or (B and not(C or D)) 的四元式序列.说明:按照控制语句中的布尔表达式翻译 这里是总结的知识点.如果有问题可以下方留言提问,视频已经放到Bilibi ...
- 基于vue与element-ui写出的关于搜索框搜索关键字,下方关键字高亮的demo
这是一个基于vue与element-ui写出的关于搜索框搜索关键字,下方关键字高亮的demo 希望对大家有所帮助 效果如下: <template><!-- 测试 -->< ...
- 编译原理习题两则(龙书,写出语言的正则定义)
3.3.5.3 注释,即 /* 和 */ 之间的串,且串中没有不在双引号(")中的 */. 注:假设双引号是匹配的. 思路:从空串开始写,写出整体框架后,通过分类讨论的方法不断进行扩充构造. ...
- 【编译原理】写出下列文法对应定义的是什么语言?
1.文法G(Z):Z->aZb|ab定义的是什么样的语言? 答:L(G)={ an bn | n≥1} 2.写出文法G(Z):Z->AB A->aBb|ab B-cB|b 定义的是什 ...
最新文章
- 控件的呈现方法(Rendering)的内核
- 单v100 GPU,4小时搜索到一个鲁棒的网络结构
- FckEditor-未能映射路径/UserFiles/image/
- [Mysql]过大sql文件导入过慢问题解决
- “假一赔十”的4k 120Hz电视能买吗?研究完我服了,水是真的深
- Java虚拟机学习(1):体系结构 内存模型
- malloc 初始化_你真的了解 NSObject 对象的初始化吗?
- 批量调整word表格根据窗口调整内容
- sringboot security基本用法
- [2017.11.11特辑]以一个光棍节表白案例浅谈ECMAScript6模块化的使用方法
- python log函数_Python log10() 函数
- stl标准模板库_C ++标准模板库(STL)中的array :: fill()
- MySQL命令窗口出现中文乱码的解决方法
- rn webview加载本地静态html,React Native - Webview 加载本地文件
- Spring使用Cache、整合Ehcache
- LVM 逻辑卷管理精讲
- C# 使用 NPOI操作excle文件(读取与新建重写)
- 简单粗暴日文键盘布局改为其他语言键盘布局
- Sinew探索金融衍生品领域,增强金融市场流动性
- 亚马逊云科技的IoT+AI能力覆盖边缘与云,在云端提供稳定的云服务支持
热门文章
- 终于有人对语音技术来了次彻头彻尾的批判!
- 15 年经验专家解读 IIoT 的挑战及应对思路!
- 世界500强的科技从业者,依旧逃不出买房难的宿命
- 5G 套餐最快本月开售;谷歌被指骗取人脸数据;Calibre 4.0 发布 | 极客头条
- 阿里开源物联网操作系统 AliOS Things 3.0 发布,集成平头哥 AI 芯片架构!
- 今日七夕!不取标题,只想娶你
- 知乎披露会员业务未来布局,融合社区内容深耕垂直领域
- AI 补代码神器诞生,百度网盘克星诞生,Google 取消中国搜索引擎项目! | 开发者周刊...
- 2019 年备受争议的 Facebook 能否走出去年的阴影?| 畅言
- 程序员惨遭辞退竟只因提了些代码修改意见?