摘要:一起来实现一个框架最近手痒,当然也是为了近阶段的跳槽做准备,利用周五时光,仿照用法,实现一下的双向绑定数据代理大胡子模板指令,等。
一起来实现一个mvvm框架
最近手痒,当然也是为了近阶段的跳槽做准备,利用周五时光,仿照vue用法,实现一下mvvm的双向绑定、数据代理、大胡子{{}}模板、指令v-on,v-bind等。当然由于时间紧迫,里面的编码细节没有做优化,还请各位看官多多包涵!看招:
实现原理数据的劫持观察(observe)
观察者模式(watcher)
使用es6的类class实现(当然,没有考虑到兼容性,只是为了实现而已)
代码:数据劫持
_observe(obj){ // 递归遍历 // let value; for (const key in obj) { let value; if (obj.hasOwnProperty(key)){ // 利用原理 劫持数据---发布订阅 value = obj[key]; if (typeof value === "object") { console.log("value", value) this._observe(value) } // 订阅(key)数据 if (!this._binding[key]) {this._binding[key]= []}; let binding = this._binding[key] // 重写getter, setter Object.defineProperty(obj, key, { enumerable: true, configurable: true, get() { return value }, set(newVal) { if (value === newVal) return false; value = newVal console.log("newvalue", value) // 主要value更新,就发布通知(监听这个key的所有的)watcher更新(改变dom) binding.forEach(watcher => { console.log("watcher", watcher) watcher.update() }); } }) } } }
实例代理数据
_proxyData(data, vm) { // data身上的所有属性全部挂载到vm实例上 for (const key in data) { // let val = data[key]; // ctx.key = val; Object.defineProperty(vm, key, { configurable: true, enumerable: true, get() { return data[key]; }, set(newVal) { data[key] = newVal; vm._observe(newVal) } }) } }
模板编译,添加发布订阅
_compile(root){ // 获取所有节点 let nodes = root.childNodes // 递归编译 Array.from(nodes).forEach(node => { // 针对每一个节点进行处理 // 元素节点 if (node.nodeType === 1) {//只考虑绑定了一个指令 // 获取节点的属性集合 const attributes = Array.from(node.attributes); // 指令进行编译 if (hasDirective(attributes, "v-bind")) { const attrVal = getDirectiveValue(node, attributes, "v-bind"); const exp = getDirectiveParams(attributes, "v-bind"); // const node.setAttribute(exp, this.$data[attrVal]) this._binding[attrVal].push(new watcher({ vm: this, el: node, exp, attr: attrVal })) } if (hasDirective(attributes, "v-on")) { const eventName = getDirectiveParams(attributes, "v-on"); node.addEventListener(eventName, (e) => { this.$methods[getDirectiveValue(node, attributes, "v-on")].call(this) }) } if (node.hasAttribute("v-model") && node.tagName === "INPUT" || node.tagName === "TEXTAREA") { let attrVal = node.getAttribute("v-model"); this._binding[attrVal].push(new Watcher({ vm: this, el: node, attr: attrVal, name: "v-model" })) node.addEventListener("input", e=> { this.$data[attrVal] = node.value; }) node.value = this.$data[attrVal] } // 递归接着处理 if (node.hasChildNodes()) { this._compile(node) } } // 文本节点 if (node.nodeType === 3) { let text = node.textContent; let keyArr = []; // 获取{{变量}},用正则去匹配;watcher去观察{{变量}}(包裹元素), let newText = text.replace(/{{(w+)}}/g, (match, p0)=> { keyArr = [...keyArr, p0]; // 替换属性为真正的属性值 return this.$data[p0] }) node.textContent = newText; // 把整个文本节点进行监控{{v1}}-----{{v2}};添加到订阅到数组里等待通知 keyArr.forEach(key => { // !this._binding[key] && (this._binding[key] = []) this._binding[key].push(new Watcher({ vm: this, el: node, attr: text })) }) } }) }
观察者实例
class Watcher { constructor({ vm, name, el, exp, attr, }) { this.vm = vm; this.el = el; this.name = name; this.exp = exp; this.attr = attr; } // 更新text,或更新属性 update() { // 改变节点的属性 if (this.el.nodeType === 1) { // this.el.value = this.vm.$data[this.exp] if (this.name === "v-model") { console.log("value", this.el) this.el.value = this.vm.$data[this.attr] } this.el[this.attr] = this.vm.$data[this.exp] } // 文本节点 else { let text = this.attr; // 获取{{变量}},用正则去匹配;watcher去观察{{变量}}(包裹元素), let newText = text.replace(/{{(w+)}}/g, (match, p0)=> { // 替换属性为真正的属性值 return this.vm.$data[p0] }) this.el.textContent = newText; } } }
整体代码
vue实现 {{title}}
{{text}}
我点的时候就会变化{{number}}---{{number}}
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/94277.html
摘要:少年,我看你骨骼精奇,是万中无一的武学奇才,我这有本图片流秘籍,见与你有缘,就送于你了。文件大小,单位为字节,该属性只读。用来读取或文件数据,基于文件大小不同,读取的过程为异步。 showImg(https://segmentfault.com/img/remote/1460000016276887); 少年,我看你骨骼精奇,是万中无一的武学奇才,我这有本《图片流》秘籍,见与你有缘,就...
摘要:方案回退时,跳到页面顶部。踏坑第九式日期转换的问题将日期字符串的格式符号替换成。欢迎感兴趣的各路武林豪杰加入。 前言 少侠,请留步,相见必是缘分,赠与你一部《踏坑秘籍》 扎马步 踏坑第一式 ios竖屏拍照上传,图片被旋转问题 解决方案 // 几个步骤 // 1.通过第三方插件exif-js获取到图片的方向 // 2.new一个FileReader对象,加载读取上传的图片 // 3.在f...
摘要:方案回退时,跳到页面顶部。踏坑第九式日期转换的问题将日期字符串的格式符号替换成。欢迎感兴趣的各路武林豪杰加入。 前言 少侠,请留步,相见必是缘分,赠与你一部《踏坑秘籍》 扎马步 踏坑第一式 ios竖屏拍照上传,图片被旋转问题 解决方案 // 几个步骤 // 1.通过第三方插件exif-js获取到图片的方向 // 2.new一个FileReader对象,加载读取上传的图片 // 3.在f...
阅读 2800·2021-11-22 15:22
阅读 18154·2021-09-22 15:00
阅读 1411·2021-09-07 09:58
阅读 1220·2019-08-30 13:01
阅读 2369·2019-08-29 16:27
阅读 2326·2019-08-26 13:25
阅读 1590·2019-08-26 12:13
阅读 912·2019-08-26 11:53