vue原理

引用

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

1、MVVM设计模式

解释

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,两个都相同,则认为是相同节点,不在深度比较

再此推荐两篇文章

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

5、路由

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

解析

  • 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页面找不到

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

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

vue 启动时卡死_十分钟浅入Vue 原理相关推荐

  1. vue 启动时卡死_使用 Vue 两年后

    先来一组数据 使用时长:2年 团队人数:4人 项目数量:4个 最大项目代码量: 33623行 最大项目 SFC: 643个 最大项目页面: 121个 累计编写通用组件:24个 通用组件代码量:2174 ...

  2. word关闭时卡死_如何修复卡死的Mac

    无论是由单个应用还是由操作系统引起的,许多macOS用户至少经历了一次卡死的计算机.好消息是,大多数情况下,这些问题会自行解决,而无需用户采取任何措施.如果确实发生了卡死(无论多么罕见),则可以采取一 ...

  3. linux pandas教程_十分钟入门 Pandas

    # 十分钟入门 Pandas 本节是帮助 Pandas 新手快速上手的简介.烹饪指南里介绍了更多实用案例. 本节以下列方式导入 Pandas 与 NumPy: In [1]: import numpy ...

  4. python分类预测降低准确率_十分钟掌握python机器学习特征选择

    十分钟掌握python机器学习特征选择-1.jpg (33.2 KB, 下载次数: 0) 2018-6-26 23:01 上传 在机器学习中,特征选择是实践中的一步, 帮你在所有特征中选择对结果贡献最 ...

  5. java程序设计_十分钟说课—Java程序设计(耿祥义)

    "十分钟说课"-Java程序设计 耿祥义视频说课: 课程概述 1. Java入门 1) 重点内容,三个基本步骤: 编写源文件,编译,运行. 2)JDK,使用JDK11以上版本,注意 ...

  6. 逗号后面统一加空格_十分钟搞定字幕,教你做加字幕的“快手菜”

    平台上许多同学有疑问:做视频是否有加字幕的必要呢? 其实除了外语需要翻译.语速过快加字幕方便理解.普通话不标准等情况之外,还是建议有余力的同学可以加上字幕,提升用户的观看体验. 那么问题来了,存在以下 ...

  7. vue data数据修改_史上最强vue总结,万字长文

    vue框架篇 vue的优点 轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十kb: 简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习: 双向数据绑定:保留了angular ...

  8. vue和react相同点_我在React和Vue中创建了相同的应用程序。 这是区别。

    vue和react相同点 by Sunil Sandhu 由Sunil Sandhu 我在React和Vue中创建了相同的应用程序. 这是区别. (I created the same app in ...

  9. vue 箭头函数兼容性_前端学习计划之VUE学习(二)

    创建一个实例 每个Vue应用都是通过Vue函数创建一个新的Vue实例开始的: 数据与方法 当Vue实例按照上述方式被创建时,Vue的响应式系统中就加入了data对象,在使用中可以直接通过属性的调用方式 ...

最新文章

  1. 谷歌丰田联合成果ALBERT了解一下:新轻量版BERT,参数小18倍,性能依旧SOTA
  2. 将客户端移植到Linux和MAC OS
  3. 攻防世界-Misc-stegano(巨详细.零基础)
  4. [SpringMVC]定义多个前缀映射的问题
  5. Shell脚本中$0、$?、$!、$$、$*、$#、$@
  6. C++ 类和对象(二):构造函数、析构函数、拷贝构造函数、运算符重载
  7. centeros6.8 mysql_centeros7安装mysql8,以及设置root密码
  8. 直接从chrome中复制的body到postman中希望能自动识别去除空格
  9. Spring.io本地服务器解决超时问题
  10. 【华为云技术分享】云小课 | 购买的数据盘在服务器看不到?磁盘初始化很重要!
  11. 高通:预计未来几年向苹果公司出售的芯片将减少
  12. C++基础new和delete运算符,new和delete简介
  13. 读SRE Google运维解密有感(一)
  14. JS键盘事件对象之keyCode、charCode、which属性对比
  15. MongoDB 数据库_集合_文档 操作
  16. 01--DNS服务器2
  17. android手机charles证书下载
  18. git 拉取所有远程分支
  19. HTML 复选框元素-复选框(checkbox)
  20. 落单的数IV --- lintcode 824

热门文章

  1. docker 查看日志_8个优秀Docker容器监控工具,收藏了
  2. html中高与行高的区别,深入了解css的行高Line Height属性
  3. 15crmo焊接后多长时间探伤_承压设备渗透探伤检测方法简单操作思路
  4. 新生必会的linux命令,jstat命令详解
  5. 参数php_PHP多参数方法的重构
  6. 汽车电子专业知识篇(二)-汽车以太网如何影响ECU和传感器设计
  7. 面试:数据分析面试SQL操作真题解析
  8. linux cmake 安装mysql5.5.11_以及更高版本_linux cmake 安装mysql5.5.11,以及更高版本
  9. 安徽阜阳计算机高中学校排名,安徽阜阳排名靠前的三大高中,有争议?2020年高考成绩说话!...
  10. php 接入微信 验证,PHP实现微信公众平台企业号验证接口