三合一网站程序,搜索引擎优化规则,asp 网站名字,网站开发怎么收客户费使用简单的代码逻辑#xff0c;理一理实现逻辑 为了方便理解#xff0c;案例中#xff0c;没有使用虚拟dom和抽象语法树#xff0c;是通过直接操作dom来实现的
1.模板语法
先看一个简单的实现#xff1a;
this.compile( this.$el ); 执行模板编译#xff0c;如果是文本…使用简单的代码逻辑理一理实现逻辑 为了方便理解案例中没有使用虚拟dom和抽象语法树是通过直接操作dom来实现的
1.模板语法
先看一个简单的实现
this.compile( this.$el ); 执行模板编译如果是文本节点且有{{}}模板语法则取$data中的值进行数据替换如果是元素节点 继续递归判断 大概就是以此来实现modal中的数据渲染到View中
html:
body
div idapph1 {{ str }} /h1{{ str }}p{{b}}/p
/div
script typetext/javascript srcvue.js/script
script typetext/javascript
new Vue({el:#app,data : {str:你好,b:这也是data的数据}
})
/script
/bodyvue.js
class Vue{constructor( options ){// 获取到#appthis.$el document.querySelector(options.el);// 获取到data数据this.$data options.data;// 执行模板解析this.compile( this.$el );}compile( node ){node.childNodes.forEach((item,index){// 如果是元素节点 说明还有子继续递归if( item.nodeType 1 ){this.compile( item );}// 如果是文本节点如果有{{}}就替换成数据if( item.nodeType 3 ){//正则匹配{{}}let reg /\{\{(.*?)\}\}/g;let text item.textContent;//给节点赋值item.textContent text.replace(reg,(match,vmKey){// 排除空格 拿到属性名称vmKey vmKey.trim();//属性名称 在$data中取值return this.$data[vmKey];})}})}
}页面显示如下 替换了{{}}中的数据 2.生命周期执行顺序
在编写代码时不管外面怎么写顺序内部生命周期执行顺序是固定的不受顺序影响
class Vue{constructor( options ){// 1.执行beforeCreate 并绑定thisif( typeof options.beforeCreate function ){options.beforeCreate.bind(this)();}// 挂载data 从这里之后可以获取数据 this.$data值this.$data options.data;// 2.执行created 并绑定thisif( typeof options.created function ){options.created.bind(this)();}// 3.执行beforeMount并绑定thisif( typeof options.beforeMount function ){options.beforeMount.bind(this)();}//挂载 节点 从这里之后可以获取dom this.$el值this.$el document.querySelector(options.el);// 4.执行mounted 并绑定thisif( typeof options.mounted function ){options.mounted.bind(this)();}// 这里之后可与获取 this.$data值 和 this.$el值}
}3.添加事件
模板编译过程中判断元素节点是否有click,change…事件属性有则addEventListener添加对应事件当触发addEventListener的时候执行绑定方法一般方法在methods中会定义。
class Vue{constructor( options ){this.$options options;if( typeof options.beforeCreate function ){options.beforeCreate.bind(this)();}this.$data options.data;if( typeof options.created function ){options.created.bind(this)();}if( typeof options.beforeMount function ){options.beforeMount.bind(this)();}this.$el document.querySelector(options.el);//模版解析this.compile( this.$el );if( typeof options.mounted function ){options.mounted.bind(this)();}}compile( node ){node.childNodes.forEach((item,index){//元素节点if( item.nodeType 1 ){// 判断元素节点是否绑定了clickif( item.hasAttribute(click) ){// click后绑定的属性名称let vmKey item.getAttribute(click).trim();item.addEventListener(click,( event ){// 查找method里面的方法 并挂载事件this.eventFn this.$options.methods[vmKey].bind(this);// 点击后 执行方法this.eventFn(event);})}if( item.childNodes.length 0 ){this.compile( item );}}//这是文本节点如果有{{}}就替换成数据if( item.nodeType 3 ){//正则匹配{{}}let reg /\{\{(.*?)\}\}/g;let text item.textContent;//给节点赋值item.textContent text.replace(reg,(match,vmKey){vmKey vmKey.trim();return this.$data[vmKey];})}})}
}4. 数据劫持
Object.defineProperty是 JavaScript 中的一个方法用于在一个对象上定义一个新属性或者修改一个现有属性的配置。 它接受三个主要参数要定义属性的对象、属性名称作为字符串和一个包含属性描述符的对象。
let obj {};
Object.defineProperty(obj, name, {value: John,writable: true,enumerable: true,configurable: true
});
console.log(obj.name); // 输出: John先看一个简单的实现
class Vue{constructor( options ){this.$options options;if( typeof options.beforeCreate function ){options.beforeCreate.bind(this)();}// 这是datathis.$data options.data;// 处理数据this.proxyData();if( typeof options.created function ){options.created.bind(this)();}if( typeof options.beforeMount function ){options.beforeMount.bind(this)();}this.$el document.querySelector(options.el);if( typeof options.mounted function ){options.mounted.bind(this)();}}//1、给Vue大对象赋属性来自于data中//2、data中的属性值和Vue大对象的属性保持双向劫持proxyData(){for( let key in this.$data ){Object.defineProperty(this,key,{get(){// 取值劫持return this.$data[key];},set( val ){// 设置值劫持this.$data[key] val;}})}}
}5. 依赖收集
Dep依赖收集器类的简单结构示例用于依赖收集和通知更新
class Dep {constructor() {this.subs [];}addSub(watcher) {this.subs.push(watcher);}notify() {this.subs.forEach(watcher {watcher.update();});}
}function defineReactive (obj, key, val) {var dep new Dep();Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: function () {if (Dep.target) {// 依赖收集dep.addSub(Dep.target);}return val;},set: function (newVal) {if (newVal val) return;val newVal;dep.notify();}});
}上溯代码中 if (Dep.target) 为ture 才会依赖收集那什么时候 if (Dep.target) 为ture?
只有当 模板渲染场景 计算属性场景computed 监听器场景watch 情况下才会创建一个watcher 调用watcher.get获取数据把watcher实例赋值给Dep.target触发依赖收集。
模板渲染场景:1.插值表达式 {{}}2.指令绑定条件 v-bind:classactiveClass3.循环指令 v-if v-for例如下面是一个模板渲染场景的插值表达式情况生成watcher第三个参数是是监听到更改值的时候调用的函数。
function generateRenderFunction(ast) {// 遍历节点ast.nodes.forEach(node {if (node.type Interpolation) {let propertyName node.content;let watcher new Watcher(vm, propertyName, () {// 当数据变化时更新节点内容updateNode(node, vm[propertyName]);});}});
}Watcher.prototype.get function () {// Dep.target 表是当前是有监听的Dep.target this;// 然后去取值 走到defineProperty中的get方法中判断 Dep.target不为空依赖收集var value this.getter.call(this.vm);// 依赖收集后清空 Dep.targetDep.target null;// 返回value值return value;
};6. 视图更新
1.模板编译基础 在 Vue 2 中模板编译主要分为三个阶段 解析parse、优化optimize和代码生成codegen。 在解析阶段会将模板字符串转换为抽象语法树AST这个 AST 包含了模板中的各种元素、指令和插值等信息。
2.解析阶段添加Watcher的线索 当解析到模板中的插值表达式如{{ message }}或指令如v - bind、v - model等时编译器会识别出对数据属性的使用。 编译器会为插值表达式创建一个对应的 AST 节点并且在这个节点中记录下需要获取的数据属性。
例如
{type: Interpolation,content: message
}3.从 AST 到Watcher的创建 在代码生成阶段编译器会根据 AST 生成渲染函数render函数 在这个过程中对于每个与数据属性相关的 AST 节点会创建一个Watcher实例来监听对应的数据变化。
function generateRenderFunction(ast) {// 遍历AST节点ast.nodes.forEach(node {//发现是{{}} 插值表达式if (node.type Interpolation) {let propertyName node.content;// 生成watcherlet watcher new Watcher(vm, propertyName, () {// 当数据变化时更新节点内容updateNode(node, vm[propertyName]);});}});// 根据AST和创建的Watcher等生成完整的渲染函数
}当发现类型为Interpolation的节点插值表达式时会提取出相关的数据属性名propertyName然后创建一个Watcher实例。这个Watcher的getter函数会获取对应的vm[propertyName]的值并且在数据变化时会执行一个回调函数来更新对应的节点内容updateNode函数这里假设它用于更新节点。
Watcher 内容
function Watcher (vm, expOrFn, cb, options) {this.vm vm;this.getter parsePath(expOrFn);this.value this.get();
}
Watcher.prototype.get function () {// Dep.target 表是当前是有监听的Dep.target this;var value this.getter.call(this.vm);Dep.target null;return value;
};
Watcher.prototype.update function () {// 处理更新逻辑可能是异步或同步更新if (this.lazy) {this.dirty true;} else if (this.sync) {this.run();} else {queueWatcher(this);}
};
Watcher.prototype.run function () {var value this.get();var oldValue this.value;this.value value;if (this.cb) {this.cb.call(this.vm, value, oldValue);}
};7、虚拟 DOM 和 真实DOM概念、作用
1.1 概念
真实 DOMDocument Object Model是浏览器中用于表示文档结构的树形结构。
h2你好/h2虚拟DOM用 JavaScript 对象来模拟真实 DOM 的结构
{children: undefineddata: {}elm: h1key: undefinedsel: h1text: 你好h1
}步骤 1.用JS对象表示真实的DOM结构生成一个虚拟DOM再用虚拟DOM构建一个真实DOM树渲染到页面 2.状态改变生成新的虚拟DOM与旧的虚拟DOM进行比对比对的过程就是DIFF算法利用patch记录差异 3.把记录的差异用在第一个虚拟DOM生成的真实DOM上视图就更新了。 Vue.js 在早期开发过程中借鉴了 Snabbdom 的设计理念来构建自己的虚拟 DOM 系统
1.2 作用
性能优化方面
真实DOM 当直接操作真实 DOM 时比如频繁地添加、删除或修改节点会引起浏览器的重排reflow和重绘repaint。重排 DOM 结构的改变导致浏览器重新计算元素的几何属性如位置、大小等重绘元素的外观发生改变如颜色、背景等变化只是重新绘制外观而不涉及布局调整。 虚拟DOM 通过一种高效的 Diff 算法比较新旧虚拟 DOM 树的差异可以快速地找出需要更新的部分而不是每次都对整个 DOM 进行重新渲染。虚拟 DOM 的操作在 JavaScript 层面进行比直接操作真实 DOM 快得多当组件的数据发生变化时Vue.js 会收集一段时间内的数据变化然后统一进行虚拟 DOM 的更新和差异比较并根据差异更新真实 DOM避免大量的无谓计算。 8、Diff 算法
源码地址
它的主要作用是比较新数据与旧数据虚拟 DOM 树的差异从而找出需要更新的部分以便将这些最小化的变更应用到真实 DOM上减少不必要的 DOM 操作提高性能。
首先sameVNode 比较一下新旧节点是不是同一个节点同级对比不跨级 下图比较第二层级的右侧左边是P右边是div 那么会认为这两个节点完全不同直接删除旧的p替换新的div。 因为 dom 节点做跨层级移动的情况还是比较少的一般情况下都是同一层级的 dom 的增删改。 但是 diff 算法除了考虑本身的时间复杂度之外还要考虑一个因素dom 操作的次数。 如果是一个list数组新旧节点只是前后顺序的改变直接删除新增dom渲染成本会增加。 2.当节点类型相同的时候Diff 算法会比较节点的属性是否有变化。如果属性有变化就更新真实 DOM 节点的属性。 例如input节点旧虚拟 DOM 中的value属性为abc新虚拟 DOM 中的value属性为defDiff 算法会更新真实 DOM 中input节点的value属性。 3.当节点类型属性都相同则比较是否存在子节点
4.如果新节点和老节点都有子节点需要进一步比较双端diff核心updateChildren diff 算法我们从一端逐个处理的叫做简单 diff 算法。简单 diff 算法其实性能不是最好的比如旧的 vnode 数组是 ABCD新的 vnode 数组是 DABC按照简单 diff 算法A、B、C 都需要移动。 那怎么优化这个算法呢 vue使用的是双端 diff 算法是头尾指针向中间移动分别判断头尾节点是否可以复用如果没有找到可复用的节点再去遍历查找对应节点的下标然后移动。全部处理完之后也要对剩下的节点进行批量的新增和删除。 开启一个循环循环的条件就是 oldStart 不能大于oldEnd newStart不能大于newEnd以下是循环的重要判断
跳过undefined **if (isUndef(oldStartVnode))** 为什么会有undefined老节点移动过程中会产生undefined占位之后的流程图会说明清楚。这里只要记住如果旧开始节点为undefined就后移一位如果旧结束节点为undefined就前移一位。 快捷对比https://www.jianshu.com/p/b9916979a740**4个 else ifsameVnode(xxx)** 1 新开始和旧开始节点比对 如果匹配表示它们位置都是对的Dom不用改就将新、旧节点开始的下标往后移一位即可。 2 旧结束和新结束节点比对 如果匹配也表示它们位置是对的Dom不用改就将新、旧节点结束的下标前移一位即可。 3 旧开始和新结束节点比对 如果匹配位置不对需要更新Dom视图将旧开始节点对应的真实Dom插入到最后一位旧开始节点下标后移一位新结束节点下标前移一位。 4 旧结束和新开始节点比对 如果匹配位置不对需要更新Dom视图将旧结束节点对应的真实Dom插入到旧开始节点对应真实Dom的前面旧结束节点下标前移一位新开始节点下标后移一位。 key值查找2.快捷对比都不满足的情况下 **}else {**
将旧节点数组剩余的vnodeoldStartIdx到oldEndIdx之间的节点进行一次遍历生成由vnode.key作为键idx索引作为值的对象oldKeyToIdx然后遍历新节点数组的剩余vnodenewStartIdx 到 newEndIdx 之间的节点根据新的节点的key在oldKeyToIdx进行查找。 1 找到相同的key 如果和已有key值匹配 那就说明是已有的节点只是位置不对则将找到的节点插入到 oldStartIdx 对应的 vnode 之前并且这里会将旧节点数组中 idxInOld 对应的元素设置为 undefined。如果和已有key值不匹配那就说明是新的节点那就创建一个对应的真实Dom节点插入到旧开始节点对应的真实Dom前面即可 2 没有相同key 没有找到对应的索引则直接createElm创建新的dom节点并将新的vnode插入 oldStartIdx 对应的 vnode 之前。 以上是while内部处理以下是while外部处理
剩余元素处理不满足循环条件后退出循环外处理剩余元素循环外 旧节点数组遍历结束、新节点数组仍有剩余经过两端对比查找都没有查找到则说明新插入内容是处于 oldstartIdx与 oldEndIdx 之间的所以可以直接在 newEndIdx 对应的 vnode 之前创建插入新节点即可。新节点数组遍历结束、旧节点数组仍有剩余则遍历旧节点oldStartIdx 到 oldEndIdx 之间的剩余数据进行移除 因为旧节点oldStartIdx之前的数据和 oldEndIdx之后的数据都是对比确认之后的且数量与新节点数组相同则中间剩下的都是要删除的节点 以上便是vue2的diff的核心流程了具体案例参考这里
什么是MVVM
1.概念 它主要目的是分离用户界面View和业务逻辑Model并通过一个中间层ViewModel来进行数据绑定和交互。 这种模式能够使代码更加清晰、易于维护和扩展。 M: Model 主要代表应用程序的数据和业务逻辑这包括像数据对象如用户信息、产品列表;V:View 是用户直接看到和交互的界面部分通常是指组件中的 template 标签内的 HTML 内容 style 标签内的 CSS 样式也属于视图。VMViewModel 是连接 Model 和 View 的桥梁。像data函数它返回数据对象、computed属性、methods以及生命周期钩子都属于 ViewModelvue源码 MVVM 模式的优势在于它能够很好地分离这使得代码的维护和扩展变得更加容易。开发人员专注于 Model 的业务逻辑设计人员专注于 View 的界面设计 ViewModel 则负责两者之间的沟通和协调。 例如当业务逻辑发生变化如待办事项的完成状态需要增加一个审核流程我们只需要在 Model 部分修改相关的数据结构和处理函数而不会影响到视图的展示逻辑。同样如果要改变视图的外观如将待办事项列表从无序列表改为表格形式只要修改 View 部分的 HTML 和 CSS而不需要大量改动业务逻辑部分。这种分离使得团队协作更加高效也提高了代码的可复用性和可测试性。 web1.0时代 文件全在一起也就是前端和后端的代码全在一起: 1、前端和后端都是一个人开发。(技术没有侧重点或者责任不够细分) 2、项目不好维护。 3、html、css、js页面的静态内容没有后端是没办法工作的(没办法套数据)mvc…都是后端先出的 web2.0时代 ajax出现了就可以:前端和后数据分离了 解决问题: 后端不用等前端页面弄完没后端做后端的事情(写接口)、前布局、特效、发送请求问题: 1、html、c5s、js都在一个页面中单个页面可能内容也是比较多的(也会出现不好维护的情况) MVC、MVVM 前端框架 解决问题:可以把一个特别大”页面进行拆分(组件化)单个组件进行维护
文章转载自: http://www.morning.madamli.com.gov.cn.madamli.com http://www.morning.qlxgc.cn.gov.cn.qlxgc.cn http://www.morning.pdmc.cn.gov.cn.pdmc.cn http://www.morning.hgscb.cn.gov.cn.hgscb.cn http://www.morning.mzqhb.cn.gov.cn.mzqhb.cn http://www.morning.bfjtp.cn.gov.cn.bfjtp.cn http://www.morning.pttrs.cn.gov.cn.pttrs.cn http://www.morning.lpcct.cn.gov.cn.lpcct.cn http://www.morning.spxsm.cn.gov.cn.spxsm.cn http://www.morning.trqhd.cn.gov.cn.trqhd.cn http://www.morning.plxnn.cn.gov.cn.plxnn.cn http://www.morning.qlhkx.cn.gov.cn.qlhkx.cn http://www.morning.ssjee.cn.gov.cn.ssjee.cn http://www.morning.qgtfl.cn.gov.cn.qgtfl.cn http://www.morning.wqpr.cn.gov.cn.wqpr.cn http://www.morning.zrgdd.cn.gov.cn.zrgdd.cn http://www.morning.psxxp.cn.gov.cn.psxxp.cn http://www.morning.mqwnp.cn.gov.cn.mqwnp.cn http://www.morning.zdhxm.com.gov.cn.zdhxm.com http://www.morning.ldcsw.cn.gov.cn.ldcsw.cn http://www.morning.frnjm.cn.gov.cn.frnjm.cn http://www.morning.rhqr.cn.gov.cn.rhqr.cn http://www.morning.lkkgq.cn.gov.cn.lkkgq.cn http://www.morning.zqsnj.cn.gov.cn.zqsnj.cn http://www.morning.nssjy.cn.gov.cn.nssjy.cn http://www.morning.dbnpz.cn.gov.cn.dbnpz.cn http://www.morning.qbgdy.cn.gov.cn.qbgdy.cn http://www.morning.24vy.com.gov.cn.24vy.com http://www.morning.pxbky.cn.gov.cn.pxbky.cn http://www.morning.fflnw.cn.gov.cn.fflnw.cn http://www.morning.ghxzd.cn.gov.cn.ghxzd.cn http://www.morning.gjxr.cn.gov.cn.gjxr.cn http://www.morning.bhqlj.cn.gov.cn.bhqlj.cn http://www.morning.kxqpm.cn.gov.cn.kxqpm.cn http://www.morning.tndhm.cn.gov.cn.tndhm.cn http://www.morning.dfkby.cn.gov.cn.dfkby.cn http://www.morning.zhmgcreativeeducation.cn.gov.cn.zhmgcreativeeducation.cn http://www.morning.sgfnx.cn.gov.cn.sgfnx.cn http://www.morning.pngph.cn.gov.cn.pngph.cn http://www.morning.srmpc.cn.gov.cn.srmpc.cn http://www.morning.pwggd.cn.gov.cn.pwggd.cn http://www.morning.qtwd.cn.gov.cn.qtwd.cn http://www.morning.ftync.cn.gov.cn.ftync.cn http://www.morning.ydhck.cn.gov.cn.ydhck.cn http://www.morning.jkdtz.cn.gov.cn.jkdtz.cn http://www.morning.dmkhd.cn.gov.cn.dmkhd.cn http://www.morning.przc.cn.gov.cn.przc.cn http://www.morning.tntqr.cn.gov.cn.tntqr.cn http://www.morning.bbrf.cn.gov.cn.bbrf.cn http://www.morning.rblqk.cn.gov.cn.rblqk.cn http://www.morning.ljfjm.cn.gov.cn.ljfjm.cn http://www.morning.cwgt.cn.gov.cn.cwgt.cn http://www.morning.rlbc.cn.gov.cn.rlbc.cn http://www.morning.jfch.cn.gov.cn.jfch.cn http://www.morning.ydtdn.cn.gov.cn.ydtdn.cn http://www.morning.lhyhx.cn.gov.cn.lhyhx.cn http://www.morning.znqztgc.cn.gov.cn.znqztgc.cn http://www.morning.xdpjf.cn.gov.cn.xdpjf.cn http://www.morning.bxch.cn.gov.cn.bxch.cn http://www.morning.qxlyf.cn.gov.cn.qxlyf.cn http://www.morning.dgng.cn.gov.cn.dgng.cn http://www.morning.dansj.com.gov.cn.dansj.com http://www.morning.gyfhk.cn.gov.cn.gyfhk.cn http://www.morning.cwtrl.cn.gov.cn.cwtrl.cn http://www.morning.jrlgz.cn.gov.cn.jrlgz.cn http://www.morning.lyldhg.cn.gov.cn.lyldhg.cn http://www.morning.wklrz.cn.gov.cn.wklrz.cn http://www.morning.fbrshjf.com.gov.cn.fbrshjf.com http://www.morning.nfdty.cn.gov.cn.nfdty.cn http://www.morning.kgqww.cn.gov.cn.kgqww.cn http://www.morning.bxqry.cn.gov.cn.bxqry.cn http://www.morning.rcdmp.cn.gov.cn.rcdmp.cn http://www.morning.zfkxj.cn.gov.cn.zfkxj.cn http://www.morning.mxnhq.cn.gov.cn.mxnhq.cn http://www.morning.mkpqr.cn.gov.cn.mkpqr.cn http://www.morning.kqzxk.cn.gov.cn.kqzxk.cn http://www.morning.fwmln.cn.gov.cn.fwmln.cn http://www.morning.yltyr.cn.gov.cn.yltyr.cn http://www.morning.fpkpz.cn.gov.cn.fpkpz.cn http://www.morning.tcxk.cn.gov.cn.tcxk.cn