当前位置: 首页 > news >正文

中昌国际建设集团网站餐饮加盟网站建设案例

中昌国际建设集团网站,餐饮加盟网站建设案例,重庆新闻经典论坛,北京 外贸网站众所周知当下是MVVM盛行的时代#xff0c;从早期的Angular到现在的React和Vue#xff0c;再从最初的三分天下到现在的两虎相争。 无疑不给我们的开发带来了一种前所未有的新体验#xff0c;告别了操作DOM的思维#xff0c;换上了数据驱动页面的思想#xff0c;果然时代的进…众所周知当下是MVVM盛行的时代从早期的Angular到现在的React和Vue再从最初的三分天下到现在的两虎相争。 无疑不给我们的开发带来了一种前所未有的新体验告别了操作DOM的思维换上了数据驱动页面的思想果然时代的进步改变了我们许多许多。 啰嗦话多了起来这样不好。我们来进入今天的主题 划重点 MVVM 双向数据绑定 在Angular1.x版本的时候通过的是脏值检测来处理 而现在无论是React还是Vue还是最新的Angular其实实现方式都更相近了 那就是通过数据劫持发布订阅模式 真正实现其实靠的也是ES5中提供的Object.defineProperty当然这是不兼容的所以Vue等只支持了IE8 为什么是它 Object.defineProperty()说实在的我们大家在开发中确实用的不多多数是修改内部特性不过就是定义对象上的属性和值么干嘛搞的这么费劲(纯属个人想法) But在实现框架or库的时候却发挥了大用场了这个就不多说了只不过轻舟一片而已还没到写库的实力 知其然要知其所以然来看看如何使用 let obj {}; obj.singer 周杰伦; Object.defintProperty(obj, music, {configurable: true, // 可以配置对象删除属性// writable: true, // 可以修改对象enumerable: true // 可以枚举// value: 七里香,// ☆ get,set设置时不能设置writable和value它们代替了二者且是互斥的get() { // 获取obj.music的时候就会调用get方法return 发如雪;},set(val) { // obj.music 听妈妈的话console.log(val); // 听妈妈的话} });console.log(obj); // {singer: 周杰伦, music: 七里香}delete obj.music; // 如果想对obj里的属性进行删除configurable要设为true console.log(obj); // 此时为 {singer: 周杰伦}obj.music 听妈妈的话; // 如果想对obj的属性进行修改writable要设为true console.log(obj); // {singer: 周杰伦, music: 听妈妈的话}for (let key in o) { // 默认情况下通过defineProperty定义的属性是不能被枚举(遍历)的// 需要设置enumerable为true才可以// 不然你是拿不到music这个属性的你只能拿到singerconsole.log(key); // singer, music }以上是关于Object.defineProperty的用法 下面我们来写个实例看看这里我们以Vue为参照去实现怎么写MVVM // index.html bodydiv idapph1{{song}}/h1p《{{album.name}}》是{{singer}}2005年11月发行的专辑/pp主打歌为{{album.theme}}/pp作词人为{{singer}}等人。/p为你弹奏肖邦的{{album.theme}}/div!--实现的mvvm--script srcmvvm.js/scriptscript// 写法和Vue一样let mvvm new Mvvm({el: #app,data: { // Object.defineProperty(obj, song, 发如雪);song: 发如雪,album: {name: 十一月的萧邦,theme: 夜曲},singer: 周杰伦}});/script /body上面是html里的写法相信用过Vue的同学并不陌生 那么现在就开始实现一个自己的MVVM吧 打造MVVM // 创建一个Mvvm构造函数 // 这里用es6方法将options赋一个初始值防止没传等同于options || {} function Mvvm(options {}) { // vm.$options Vue上是将所有属性挂载到上面// 所以我们也同样实现,将所有属性挂载到了$optionsthis.$options options;// this._data 这里也和Vue一样let data this._data this.$options.data;// 数据劫持observe(data); }数据劫持 为什么要做数据劫持 观察对象给对象增加Object.definePropertyvue特点是不能新增不存在的属性 不能存在的属性没有get和set深度响应 因为每次赋予一个新对象时会给这个新对象增加defineProperty(数据劫持) 多说无益一起看代码 // 创建一个Observe构造函数 // 写数据劫持的主要逻辑 function Observe(data) {// 所谓数据劫持就是给对象增加get,set// 先遍历一遍对象再说for (let key in data) { // 把data属性通过defineProperty的方式定义属性let val data[key];observe(val); // 递归继续向下找实现深度的数据劫持Object.defineProperty(data, key, {configurable: true,get() {return val;},set(newVal) { // 更改值的时候if (val newVal) { // 设置的值和以前值一样就不理它return;}val newVal; // 如果以后再获取值(get)的时候将刚才设置的值再返回去observe(newVal); // 当设置为新值后也需要把新值再去定义成属性}});} }// 外面再写一个函数 // 不用每次调用都写个new // 也方便递归调用 function observe(data) {// 如果不是对象的话就直接return掉// 防止递归溢出if (!data || typeof data ! object) return;return new Observe(data); }以上代码就实现了数据劫持不过可能也有些疑惑的地方比如递归 再来细说一下为什么递归吧看这个let mvvm new Mvvm({el: #app,data: {a: {b: 1},c: 2}}); 我们在控制台里看下被标记的地方就是通过递归observe(val)进行数据劫持添加上了get和set递归继续向a里面的对象去定义属性亲测通过可放心食用接下来说一下observe(newVal)这里为什么也要递归还是在可爱的控制台上敲下这么一段代码 mvvm._data.a {b:ok}然后继续看图说话通过observe(newVal)加上了现在大致明白了为什么要对设置的新值也进行递归observe了吧哈哈so easy数据劫持已完成我们再做个数据代理数据代理数据代理就是让我们每次拿data里的数据时不用每次都写一长串如mvvm._data.a.b这种我们其实可以直接写成mvvm.a.b这种显而易见的方式下面继续看下去号表示实现部分function Mvvm(options {}) { // 数据劫持observe(data);// this 代理了this._datafor (let key in data) {Object.defineProperty(this, key, {configurable: true,get() {return this._data[key]; // 如this.a {b: 1}},set(newVal) {this._data[key] newVal;}});} }// 此时就可以简化写法了 console.log(mvvm.a.b); // 1 mvvm.a.b ok; console.log(mvvm.a.b); // ok 写到这里数据劫持和数据代理都实现了那么接下来就需要编译一下了把{{}}里面的内容解析出来数据编译function Mvvm(options {}) {// observe(data);// 编译 new Compile(options.el, this); }// 创建Compile构造函数 function Compile(el, vm) {// 将el挂载到实例上方便调用vm.$el document.querySelector(el);// 在el范围里将内容都拿到当然不能一个一个的拿// 可以选择移到内存中去然后放入文档碎片中节省开销let fragment document.createDocumentFragment();while (child fragment.firstChild) {fragment.appendChild(child); // 此时将el中的内容放入内存中}// 对el里面的内容进行替换function replace(frag) {Array.from(frag.childNodes).forEach(node {let txt node.textContent;let reg /\{\{(.*)\}\}/; // 正则匹配{{}}if (node.nodeType 3 reg.test(txt)) { // 即是文本节点又有大括号的情况{{}}console.log(RegExp.$1); // 匹配到的第一个分组 如 a.b, clet arr RegExp.$1.split(.);let val vm;arr.forEach(key {val val[key]; // 如this.a.b});// 用trim方法去除一下首尾空格node.textContent txt.replace(reg, val).trim();}// 如果还有子节点继续递归replaceif (node.childNodes node.childNodes.length) {replace(node);}});}replace(fragment); // 替换内容vm.$el.appendChild(fragment); // 再将文档碎片放入el中 } 看到这里在面试中已经可以初露锋芒了那就一鼓作气做事做全套来个一条龙现在数据已经可以编译了但是我们手动修改后的数据并没有在页面上发生改变下面我们就来看看怎么处理其实这里就用到了特别常见的设计模式发布订阅模式发布订阅发布订阅主要靠的就是数组关系订阅就是放入函数发布就是让数组里的函数执行// 发布订阅模式 订阅和发布 如[fn1, fn2, fn3] function Dep() {// 一个数组(存放函数的事件池)this.subs []; } Dep.prototype {addSub(sub) { this.subs.push(sub); },notify() {// 绑定的方法都有一个update方法this.subs.forEach(sub sub.update());} }; // 监听函数 // 通过Watcher这个类创建的实例都拥有update方法 function Watcher(fn) {this.fn fn; // 将fn放到实例上 } Watcher.prototype.update function() {this.fn(); };let watcher new Watcher(() console.log(111)); // let dep new Dep(); dep.addSub(watcher); // 将watcher放到数组中,watcher自带update方法 [watcher] dep.addSub(watcher); dep.notify(); // 111, 111 数据更新视图现在我们要订阅一个事件当数据改变需要重新刷新视图这就需要在replace替换的逻辑里来处理通过new Watcher把数据订阅一下数据一变就执行改变内容的操作function replace(frag) {// 省略...// 替换的逻辑node.textContent txt.replace(reg, val).trim();// 监听变化// 给Watcher再添加两个参数用来取新的值(newVal)给回调函数传参new Watcher(vm, RegExp.$1, newVal {node.textContent txt.replace(reg, newVal).trim(); }); }// 重写Watcher构造函数 function Watcher(vm, exp, fn) {this.fn fn;this.vm vm;this.exp exp;// 添加一个事件// 这里我们先定义一个属性Dep.target this;let arr exp.split(.);let val vm;arr.forEach(key { // 取值val val[key]; // 获取到this.a.b默认就会调用get方法});Dep.target null; } 当获取值的时候就会自动调用get方法于是我们去找一下数据劫持那里的get方法function Observe(data) {let dep new Dep();// 省略...Object.defineProperty(data, key, {get() {Dep.target dep.addSub(Dep.target); // 将watcher添加到订阅事件中 [watcher]return val;},set(newVal) {if (val newVal) {return;}val newVal;observe(newVal);dep.notify(); // 让所有watcher的update方法执行即可}}) } 当set修改值的时候执行了dep.notify方法这个方法是执行watcher的update方法那么我们再对update进行修改一下Watcher.prototype.update function() {// notify的时候值已经更改了// 再通过vm, exp来获取新的值let arr this.exp.split(.);let val this.vm;arr.forEach(key { val val[key]; // 通过get获取到新的值});this.fn(val); // 将每次拿到的新值去替换{{}}的内容即可 }; 现在我们数据的更改可以修改视图了这很good还剩最后一点我们再来看看面试常考的双向数据绑定吧双向数据绑定 // html结构input v-modelc typetext// 数据部分data: {a: {b: 1},c: 2}function replace(frag) {// 省略...if (node.nodeType 1) { // 元素节点let nodeAttr node.attributes; // 获取dom上的所有属性,是个类数组Array.from(nodeAttr).forEach(attr {let name attr.name; // v-model typelet exp attr.value; // c textif (name.includes(v-)){node.value vm[exp]; // this.c 为 2}// 监听变化new Watcher(vm, exp, function(newVal) {node.value newVal; // 当watcher触发时会自动将内容放进输入框中});node.addEventListener(input, e {let newVal e.target.value;// 相当于给this.c赋了一个新值// 而值的改变会调用setset中又会调用notifynotify中调用watcher的update方法实现了更新vm[exp] newVal; });});}if (node.childNodes node.childNodes.length) {replace(node);}} 大功告成面试问Vue的东西不过就是这个罢了什么双向数据绑定怎么实现的问的一点心意都没有差评大官人请留步本来应该收手了可临时起意(手痒)再写点功能吧再加个computed(计算属性)和mounted(钩子函数)吧computed(计算属性) mounted(钩子函数) // html结构p求和的值是{{sum}}/pdata: { a: 1, b: 9 },computed: {sum() {return this.a this.b;},noop() {}},mounted() {setTimeout(() {console.log(所有事情都搞定了);}, 1000);}function Mvvm(options {}) {// 初始化computed,将this指向实例initComputed.call(this); // 编译new Compile(options.el, this);// 所有事情处理好后执行mounted钩子函数options.mounted.call(this); // 这就实现了mounted钩子函数}function initComputed() {let vm this;let computed this.$options.computed; // 从options上拿到computed属性 {sum: ƒ, noop: ƒ}// 得到的都是对象的key可以通过Object.keys转化为数组Object.keys(computed).forEach(key { // key就是sum,noopObject.defineProperty(vm, key, {// 这里判断是computed里的key是对象还是函数// 如果是函数直接就会调get方法// 如果是对象的话手动调一下get方法即可// 如 sum() {return this.a this.b;},他们获取a和b的值就会调用get方法// 所以不需要new Watcher去监听变化了get: typeof computed[key] function ? computed[key] : computed[key].get,set() {}});});} 写了这些内容也不算少了最后做一个形式上的总结吧总结通过自己实现的mvvm一共包含了以下东西通过Object.defineProperty的get和set进行数据劫持通过遍历data数据进行数据代理到this上通过{{}}对数据进行编译通过发布订阅模式实现数据与视图同步通过通过通过收了感谢大官人的留步了
http://www.huolong8.cn/news/477906/

相关文章:

  • 公司怎么建立网站吗wordpress用户留言插件
  • 图书馆网站建设情况总结个人网店店铺名字
  • 网站开发设计总结电影里的做视频在线观看网站
  • 招聘网站源码下载北京建筑公司招聘信息
  • seo怎么优化一个网站搜索引擎网站排名
  • 手机网站 html网站的元素
  • 公司网站开发软件比特币网站怎么做
  • 做网站不给源代码asp怎么做网站
  • 用自己网站做邮箱域名解析东莞最新招聘
  • 电商网站目录优化深圳三合一建设网站
  • 做啥网站流量高ssh wordpress
  • 网站的分类有哪些怎么做网站推广佳木斯
  • 网站和主机有什么不同做建网站的公司
  • 北京网站建设推广服务信息网站建设问题大全
  • 网站展示模板免费下载wordpress分享插件
  • wordpress建站比较中铁建设集团门户登录网
  • 专门帮做ppt的网站vip影视网站如何做app
  • 电商网站维护网站后台的搭建
  • 广西建设四库一平台网站网站建设的毕业设计成果
  • 火币网站怎么做空wordpress4.5 缩略图函数
  • 网站建设服湖北网站排名优化
  • 公司建设网站需求分析报告网站经营网络备案信息管理系统
  • 2014中文网站seo排名名单如何建造一个网站
  • 自己怎么做网站购买空间磐石网站建设
  • 酒店如何做网站做响应式网站需要学哪些知识
  • 网站开发实用吗企业网站如何建设报告
  • 乐器网站模板网络文化经营许可证怎么办
  • 重庆做网站及公众号公司小程序介绍
  • 网站研发福田祥菱
  • c2c网站有哪些?鞍山企业做网站