vue 启动时卡死_十分钟浅入Vue 原理

vue原理

引用

众所周知vue是一个MVVM 渐进式框架,MVVM是vue的设计模式,在vue框架中数据会自动驱动视图。

1、MVVM设计模式

510dc1971a2bc3c6e9548334daa66ef3.png
解释

View是视图,就是DOM;对应视图也就是HTML部分--代表UI组件,它负责将数据模型转化成UI展现出来。 Model是模型,就是vue组件里的data,或者说是vuex里的数据;--代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。 ViewModel--监听模型数据也就是data的的改变和控制视图行为、处理用户交互,简单理解就是一个同步View和Model的对象,连接Model和View。

总结

在MVVM架构下,ViewModel之间并没有直接的联系,而是通过ViewMode进行交互,Model和ViewModel之间的交互是双向的,因此View数据的变化会同步到Model中,而Model数据的变化也会立即反应到View上。

ViewModel通过双向数据绑定把View层和Model层连接了起来,而View和Model之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM,不需要关注数据状态的同步问题,复杂的数据状态维护完全由MVVM来统一管理。

由此,我们可以引出vue是响应式的

2、响应式

说明

Vue 的响应式原理是核心是通过 ES5 的保护对象的 Object.defindeProperty中的访问器属性中的 getset方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到真实 DOM 树上。

2.1 双向数据绑定原理

检测data变化的核心APIObject.defindeProperty

基本使用

const data = {};
let name = "张三";Object.defineProperty(data,'name',{get:function(){console.log('触发get')return name},set:function(newVal){console.log('触发set')name=newVal}
})//测试
console.log(data.name)   // 触发get  张三
data.name = '李四'         // 触发set

这样就是可以实现数据的获取和赋值的监听

2.2 接下来看看vue是如何监听data变化的

//触发更新视图
function updateView() {console.log('视图更新')
}
//重新定义数组原型
const oldArrayProperty = Array.prototypo
//创建新对象,原型指向oldArrayProperty,在拓展新的方法(这样不会影响原型)
let arrayProto = Array.prototype
let methods = ['pop', 'shift', 'unshift', 'sort', 'reverse', 'splice', 'push']
methods.forEach(methodName => {arrayProto[methodName] = function () {updateView ()oldArrayProperty[methodName].call(this,...arguments)}
})
//监听对象属性
function observer(target){if(typeof target !=='object' || target === null) {//不是对象或者数组return target}//重新定义数组原型if (Array.isArray(target)) {target.__proto__ = arrProto}//重新定义各个属性(for in 对象/数组都可以遍历)for(let key in target) {defineReactive(target,key,target[key])}
}
//重新定义属性,监听起来
function defineReactive (target, key, value){//递归深度监听observer(value)//核心API Object.defineProperty(target,key,{get(){return value},set(newValue){if(newValue !== value) {// 深度监听observer(newValue)//设置新值value = newvalue//触发更新视图updateView()}}})
}
// 准备数据
const data = {name: 'zhangsan',age: 20,info: {address: '北京' // 需要深度监听},nums: [10, 20, 30]
}data.name = 'lisi' //视图更新data.age = 21      //视图更新console.log('age', data.age) //age 21data.x = '100' // 新增属性,监听不到 —— 所以有 Vue.setdelete data.name // 删除属性,监听不到 —— 所以有 Vue.detedata.info.address = '上海' // 深度监听data.nums.push(4) // 视图更新
缺点
  • 深度监听obj,需要递归到底,一次性计算量大,如果数据过大页面,页面可能会卡死
  • 无法监听新增属性/删除属性(所以vue提供了Vue.set Vue.delete
  • 无法原生监听数组,需要做特殊处理

3、vdom和diff

背景

DOM操作是非常耗时的,Vue 和React 是数据驱动视图,就是 通过 虚拟DOM(vdom)来解决的这个问题

3.1 vdom

vdom就是一段js形式的html代码

js 模拟 DOM 结构

<div id ='app' class='box'><p>p标签的文本</p><ul style='font-size:20px'><li>li标签文本</li></ul>
</div>{tag: 'div',props: {id: 'app',className: 'box'},children: [{tag: 'p',children: 'p标签的文本'},{tag: 'ul',props: {style: 'font-size:20px'},children: [{tag: 'li',children:'li标签文本'}]}]}
  • tag 标签
  • props 属性(包括 id、className 、 style、事件等)
  • children 子元素,数组或者字符串
拓展

可以通过学习snabbdom 进一步了解

var snabbdom = require('snabbdom');
var patch = snabbdom.init([ // Init patch function with chosen modulesrequire('snabbdom/modules/class').default, // makes it easy to toggle classesrequire('snabbdom/modules/props').default, // for setting properties on DOM elementsrequire('snabbdom/modules/style').default, // handles styling on elements with support for animationsrequire('snabbdom/modules/eventlisteners').default, // attaches event listeners
]);
var h = require('snabbdom/h').default; // helper function for creating vnodesvar container = document.getElementById('container');var vnode = h('div#container.two.classes', {on: {click: someFn}}, [h('span', {style: {fontWeight: 'bold'}}, 'This is bold'),' and this is just normal text',h('a', {props: {href: '/foo'}}, 'I'll take you places!')
]);
// Patch into empty DOM element – this modifies the DOM as a side effect
patch(container, vnode);var newVnode = h('div#container.two.classes', {on: {click: anotherEventHandler}}, [h('span', {style: {fontWeight: 'normal', fontStyle: 'italic'}}, 'This is now italic type'),' and this is still just normal text',h('a', {props: {href: '/bar'}}, 'I'll take you places!')
]);
// Second `patch` invocation
patch(vnode, newVnode); // Snabbdom efficiently updates the old view to the new state
解析
  • h 是一个函数,接收三个参数(标签或选择器,属性,子节点数组),返回一个vnode结构;
  • patch 补丁的意思;
  • patch(containerro/容器, vnode/虚拟dom) ,表示把vnode渲染到DOM结构中
  • patch(vnode, newVnode); 表示更新已有的内容(具体怎么计算更新对应的内容就是使用diff算法)
  • patch(containerro, null); 清空DOM结构

3.2 diff算法,新旧vnode对比,计算出最小的更新范围

核心
  • 同层级比较(只比较同一层级,不跨级比较)
  • tag 不相同,则直接删除重建,不在深度比较
  • tag 和 key,两个都相同,则认为是相同节点,不在深度比较

fae0eb7080ce1dd831f1d86d1569f49c.png

61a2389d03a55886c52cb00177f5ccd3.png

再此推荐两篇文章

  • 解析vue2.0的diff算法
  • VirtualDOM与diff(Vue实现)

4、渲染过程

vue组件渲染/更新过程(异步渲染)

  • 初次渲染过程
  • 更新过程

4.1初次渲染过程

  • 解析模板为render函数(一般在开发环境已经完成,vue-loader)4
  • 触发响应式,监听data属性getter setter(模板中使用到的变量会触发getter)
  • 执行render函数(触发getter),生成vnode,patch(elem,vnode)渲染到页面上
注意

​ 如果模板中没有用的data数据就不会触发getter,因为和视图没关系(vue里面的优化)

4.2 更新过程

  • 修改data的数据,触发setter(此前data数据在getter中已被监听)
  • 重新执行render函数,生成newVnode(新的虚拟dom)
  • 使用 patch(vnode,newVnode)更新到页面上

b6f36870aaa86e3ff105d3117929ab63.png
  • 1、编译模板生成render函数,生成vdom
  • 2、执行render函数,触发data中的getter
  • 3、getter方法收集依赖(通俗点就是,在模板里面触发了哪个变量的getter,就把哪个变量观察起来)
  • 4、在依赖中setter修改data中的数据的时候,Notify看下修改的那个数据是不是之前被观察起来的
  • 5、如果是之前观察起来的,就重新渲染( re-render),重新生成render函数,生成newVdom形成一个闭环

5、路由

vue分为hash(默认)以及 history 两个路由模式

f4121cc9f7121529c41010919badca9c.png
解析
  • protocol - 协议
  • hostname - 主机名
  • port - 端口
  • pathname - url 路径
  • search - ?号之后的参数
  • hash - #号之后的部分

5.1 hash

特点
  • hash 变化会触发页面跳转,即浏览器的前进,后退
  • hash 变化不会刷新页面,SPA(单页面)必须的特点
  • hash 永远不会提交到server 端

vue中就是通过hash 的变化触发路由的变化,来触发视图的渲染

js 实现hash
<body><p>hash路由</p><button id='btn'>修改 hash</button>
</body><script>//hash 变化 包括;//a. js 修改URL//b. 手动修改url的hash//c.浏览器的前进、后退//页面初次加载获取hashwindow.addEventListener ('DOMCintentLoaded',() =>{console.log('hash',location.hash)})//hash变化触发window.onhashchange = (event) =>{console.log('hash',location.hash)}//js 修改 urldocument.getElementById('btn').addEventListener('click',()=>{location.href = '#/user'})
</script>

5.2 history

h5 history 主要是通过 history.pushState 跳转 和 window.onpopstate 监听页面的前进和后退

<body><p>historyh路由</p><button id='btn'>修改 url</button>
</body><script>//页面初次加载获取hashwindow.addEventListener ('DOMCintentLoaded',() =>{console.log('load',location.pathname)})//js 修改 urldocument.getElementById('btn').addEventListener('click',()=>{//pushState 有三个参数//第一个参数是个js对象,可以放任何的内容,可以在onpostate事件中(后面介绍)获取到便于做相应的、处理。//第二个参数是页面标题:目前所有浏览器都不支持,填空字符串即可//第三个参数是个字符串,就是保存到history中的url。let state= {title:'新页面'}history.pushState(state,'','user')})//监听浏览器的前进、后退window.onpostate = (event) => {console.log(event.state)  // {title:'新页面'}console.log(location.pathname)}
</script>

上面的代码如果放在本地html 文件中运行 js代码会报错,需要放在web服务器

注意

history 模式需要后端配合,就是无论用户访问什么路由,所有路由的切换都由前端来做,后端只需要返回index.html的文件,如果后面没有配置兼容,当访问user这个路由,点击刷新,就会报user页面找不到

以上内容纯属个人理解,若有不对,请留言纠正!

关注【前端知识小册】,第一时间获取前端优质文章!

cc225ae5a252573b3326937ff4772d83.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/364410.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

centos7.3 安装 mysql-5.7.13

系统环境: [rootlocalhost ~]# cat /etc/RedHat-release CentOS release 6.7 (Final)[rootlocalhost tools]# uname -aLinux localhost 2.6.32-573.22.1.el6.x86_64 #1 SMP Wed Mar 23 03:35:39 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux[rootlocalhost tools]# 软件准备:[root…

GARFIELD@12-20-2004

克已复礼为仁转载于:https://www.cnblogs.com/rexhost/archive/2004/12/20/79502.html

Java 8的功能基础

Java 8彻底改变了Java。 它很可能是过去10年中最重要的Java版本。 有很多新功能&#xff0c;包括默认方法&#xff0c;方法和构造函数引用以及lambda&#xff0c; 仅举几例 。 更有趣的功能之一是新的java.util.stream API&#xff0c;正如Javadoc所述&#xff0c;该API支持 …

JSON.stringify()和JOSN.parse()

JSON.stringify()跟JSON.parse() 终于把这两个方法搞清楚了&#xff01;&#xff01;&#xff01; JSON.tringify()&#xff1a;把一个json数据转化成JSON string JSON.stringify({uno:1,dos:2},null,\t)"{"uno": 1,"dos": 2}"JSON.stringfy({u…

查表法实现反正切_关于python实现CRC32的应用和总结

关于python实现CRC32的应用和总结目前使用的Crc计算包含Crc32和Crc32mpeg2两种计算方式。循环冗余检验 CRC 差错检测技术能够证明数据是完整的&#xff0c;是无差错的&#xff08;只是非常近似的认为是无差错的&#xff09;。保证数据可靠性传输的方法包含如下&#xff1a;检验…

bootstrap html5 表单验证,基于Bootstrap+jQuery.validate实现表单验证

这大概是一种惯例&#xff0c;学习前台后台最开始接触的业务都是用户注册和登录。现在社会坚持以人为本的理念&#xff0c;在网站开发过程同样如此。User是我们面对较多的对象&#xff0c;也是较核心的对象。最开始的用户注册和登陆这块&#xff0c;也就尤为重要。用户注册和登…

JavaFX技巧1:可调整大小的Canvas

在使用FlexGanttFX时&#xff0c;我不得不处理很多JavaFX Canvas节点。 我正在使用它在时间轴上呈现活动。 甘特图中的每一行都是一个Canvas节点。 用户可以选择单独调整每行的大小。 因此&#xff0c;我不得不找出调整画布大小的最佳方法&#xff0c;这种现成的方法无法调整大…

12日疯人认证百度云_12月15日上海实习汇总(百度、美图、哔哩哔哩等)

上海实习实习汇总 | 实习内推 | 寒假实习博世 采购助理Job Title: 采购部实习生Job Description:1. Create Purchase Decision (PD), initiate internal approval workflow.2. Maintain basic data in SAP, SupplyOn, SRM, internal system Pilum .etc.3. Issue purchase order…

15必须阅读Java 8教程

Java 8于上个月发布&#xff0c;其中充满了新功能和幕后优化。 互联网在覆盖所有这些新增加的方面&#xff08;包括好的和坏的&#xff09;一直做得很好。 我认为最好汇总一下我们认为是最好的一些教程&#xff0c;以帮助您快速掌握最新信息和需要了解的知识。 Java 8新功能列…

随机森林和gbdt结合_决策树与迭代决策树(GBDT)

关注数学&#xff0c;关注AI&#xff0c;关注我们公众号ID&#xff1a;Math-AI阅读目录1. 决策树的模型2. 决策树的基本知识3. ID3、C4.5&CART4. Random Forest5. GBDT6. 参考内容今天我们来谈一谈机器学习算法中的各种树形算法&#xff0c;包括ID3、C4.5、CART以及基于集成…

猫眼html源码,50 行代码教你爬取猫眼电影 TOP100 榜所有信息

点击上方“CSDN”&#xff0c;选择“置顶公众号”关键时刻&#xff0c;第一时间送达&#xff01;今天&#xff0c;手把手教你入门 Python 爬虫&#xff0c;爬取猫眼电影 TOP100 榜信息。作者 | 丁彦军本文经授权转自「程序人生」对于 Python 初学者来说&#xff0c;爬虫技能是应…

JuJu团队1月4号工作汇报

JuJu团队1月4号工作汇报 JuJu Scrum 团队成员今日工作剩余任务困难飞飞将model嵌入GUI美化UI无婷婷调试代码提升acc无恩升--写python版本的evaluate.jl无金华修改loader待安排无胡凯--考试无陈灿协调协调无PM报告 整个项目的任务量预期为250 people*hour&#xff0c; 目前已经解…

大数据技术与应用实训心得_GXCGQ16D传感器与检测技术应用实训考核设备

(一)产品概述依据国家人力资源与社会保障部《技工院校工学结合课程教学改革试点工作方案》设计&#xff0c;围绕典型工作任务(即传感器实训模块)确定课程目标&#xff0c;选择课程内容&#xff0c;制定专业教学计划&#xff0c;根据国家职业标准中相关内容。将机电工学结合中有…

IIS 7.5绑定中文域名转码启动站点报“值不在预期的范围内”

问题现象 IIS 7.5在绑定中文域名转码后&#xff0c;启动站点会出现【值不在预期的范围内】&#xff1a; 解决方案此问题是由于中文域名绑定错误导致的&#xff0c;IIS 7.5针对中文域名会自动转换为punycode码&#xff0c;所以不需要绑定punycode码&#xff0c;如果要绑定中文域…

if判断代码 转变为 流程图

转换规则如下&#xff1a; if 代表一个菱形问号 if后面的条件代表菱形里的内容↓yes&#xff08;向下箭头和yes&#xff09; if同级的else代表右拐向下箭头和no 执行语句块代表一个矩形。 if 今天发工资:先还信用卡的钱if 有剩余:又可以happy了&#xff0c;O(∩_∩)O哈哈~else:…

刷新问题

最近新建立了一个MDI多文档工程,但不知道是何原因,只打开MDI父窗体进行界面界面就已经刷新不过来了,如果界面大小变化,更是不堪忍受,不知道是什么原因,而且我已经把窗体设置了不透明.页面的控件都变成模糊的,看不清,如下,请大家帮忙解决.转载于:https://www.cnblogs.com/bluecl…

jenkins修改pom文件_动手实践:美化 Jenkins 报告插件的用户界面

对于 Jenkins 而言&#xff0c;可使用插件来可视化各种构建步骤的结果。有一些插件可用于呈现测试结果、代码覆盖率、静态分析等。这些插件通常都会获取给定构建步骤的构建结果&#xff0c;并在用户界面中显示它们。为了呈现这些细节&#xff0c;大多数插件使用静态 HTML 页面&…

01:saltstack 基本使用

目录&#xff1a;zabbix其他篇 01&#xff1a;saltstack 基本使用 02&#xff1a;saltstack-api使用详解 目录&#xff1a; 1.1 准备实验环境: 安装系统1.2 克隆一台虚拟机完成使用环境1.3 saltstack介绍1.4 saltstack安装 1.5 saltstack常用模块 1.6 salt ssh详解 1.7 Salt Gr…

matlab批量修改txt内容_MATLAB作图实例:18:为饼图添加文本标签和百分比

创建饼图时&#xff0c;MATLAB会用切片所代表的整个饼图的百分比来标记每个饼图切片。您可以更改标签以显示不同的文本。简单文字标签用简单的文本标签创建一个饼图。x [1,2,3];pie(x,{Item A,Item B,Item C})带有百分比和文本的标签创建带有包含自定义文本和每个切片的预先计…

python 怎么算l2范数_数学推导+纯Python实现机器学习算法13:Lasso回归

版权说明&#xff1a;本公号转载文章旨在学习交流&#xff0c;不用于任何商业用途&#xff0c;版权归原作者所有&#xff0c;如有异议&#xff0c;敬请后台联络我们&#xff0c;议定合作或删除&#xff0c;我们将第一时间按版权法规定妥善处理&#xff0c;非常感谢&#xff01;…