Vue2的核心原理剖析

✨ 用了这么久的Vue2了你真的 知其然,知其所以然么?

今天博主就为大家带来一篇对Vue核心功能的部分剖析\textcolor{pink}{今天博主就为大家带来一篇对Vue核心功能的部分剖析}Vue

后续文章会用更多小案例来帮助大家理解Vue的原理\textcolor{green}{后续文章会用更多小案例来帮助大家理解Vue的原理}Vue

前言:

  • 相信大家阅读过很多关于Vue2的文章,我也阅读过很多,但是大部分文章介绍的都是如何在项目中进行应用,技术点如果使用,功能如何实现;
  • 今天小编为大家带来这篇Vue2的核心原理剖析就是为大家介绍我们常用的Vue2他是如何实现的核心内容,我们简单代码的背后究竟他做了哪些,让大家能够 知其然,知其所以然

学习目标:

  • 了解Object.defineProperty原理
  • 了解set、get关联使用
  • 了解数据反应到识图的过程
  • 了解视图更换如何影响数据
  • 掌握MVVM

Object.defineProperty

 <script>// 1. 字面量定义let data = {name: 'aa'}data.name = 'bb' // 这种情况下我们并不能知道name属性发生了变化// 2. Object.defineProperty  let data1 = {}Object.defineProperty(data1, 'name', {// 当我们访问data1的name属性的时候自动调用的方法// 并且get函数的返回值就是你拿到的值get() {console.log('你访问了data1的name属性')return 'aa'},// 当我们设置修改name属性的时候自动调用的函数// 并且属性最新的值会被当成实参传入进来set(newValue) {console.log('你修改了data1的name属性最新的值为', newValue)// 这个位置 只要你修改了name属性就会得到执行// 所以如果你想要在name变化的时候 完成一些自己的事情// 都可以放到这里来执行// 1. ajax()// 2. 操作一块dom区域}})// 以上是js中对象定义的另外一种方案,可以在访问属性和设置属性的时候自动调用对应的函数// 访问属性:data.name  data['name']  // 设置属性:data.name = 'bb'  data['name'] = 'bb'</script>
 响应式的核心API   

get、set

 <script>// let data = {//   name: 'aa'// }let data = {}let _name = 'aa'Object.defineProperty(data, 'name', {get() {console.log('你访问了data1的name属性')return _name},set(newValue) {console.log('你修改了data1的name属性最新的值为', newValue)_name = newValue}})// 问题产生的原因:get中直接返回了一个固定的值,并且set函数中新值拿到了但是没有做任何事情// 解决方案:通过声明一个中间变量,让get函数中return出去这个变量// 并且在set函数中把最新的值设置到这个中间变量身上,起到一个set和get操作的一个// 数据的效果</script>

数据反应到视图

数据的变化可以引起视图的变化(通过操作dom把数据放到对应的位置上去 如果数据变化之后就用数据最新的值再重新放一次)

方案一:命令式操作

  1. document.querySelector(’#app’).innerText = data.name
  2. set函数中重新执行一下document.querySelector(’#app’).innerText = data.name

方案二:声明式渲染
v-text指令的实现

 <p v-text="name"></p>

核心逻辑:通过‘模板编译’找到标记了v-text的元素,然后把对应的数据通过操作domapi放上去

 <div id="app"><p v-text="name"></p><p></p></app>

1.通过app根元素找到所有的子节点 (元素节点,文本节点…) -> dom.nodeChilds
2.通过节点类型筛选出元素节点 (p) -> nodeType 1元素节点 3文本节点
3.通过v-text找到需要设置的具体的节点 <p v-text></p>
4.找到绑定了v-text标记的元素 拿到它身上所有的属性 id class v-text=“name”
5.通过v-text=“name” 拿到指令类型 ‘v-text’ 拿到需要绑定的数据的属性名 ‘name’
6.判断当前是v-text指令 然后通过操作domapi 把name属性对应的值放上去 node.innerText = data[name]
以上整个过程可以称作‘模板编译’

视图的变化反映到数据

input元素 v-model双向绑定
M -> V
V -> M

M -> V

1.通过app根元素找到所有的子节点 (元素节点,文本节点…) -> dom.nodeChilds
2.通过节点类型筛选出元素节点 (p) -> nodeType 1元素节点 3文本节点
3.通过v-text找到需要设置的具体的节点 <p v-text></p>
4.找到绑定了v-text标记的元素 拿到它身上所有的属性 id class v-text=“name”
5.通过v-model=“name” 拿到指令类型 ‘v-model’ 拿到需要绑定的数据的属性名 ‘name’
6.判断当前是v-model指令 然后通过操作domapi 把name属性对应的值放上去 node.value = data[name]
v-model和v-text除了指令类型不一致,使用的dom api不一致 其它的步骤是完全一致的

V -> M

本质:事件监听在回调函数中拿到input中输入的最新的值然后赋值给绑定的属性

 node.addEventListener('input',(e)=>{data[name] = e.target.value})

以上总结:
1.数据的响应式
2.数据变化影响视图
3.视图变化影响数据
4.指令是如何实现的(常规实现逻辑)

优化工作:
1.通用的数据响应式处理

   data(){return {name:'cp',age:28}}
基于现成的数据,然后都处理成响应式
 Object.keys(data) // 由所有的对象的key组成的数组Object.keys(data).forEach(key=>{// key 属性名// data[key]  属性值// data 原对象// 将所有的key都转成get和set的形式defineReactive(data,key,data[key])})function defineReactive(data,key,value){Oject.defineProperty(data, key, {get(){return value},set(newValue){value = newValue}})}

2.发布订阅模式
问题:

  <div><p v-text="name"></p><p v-text="name"></p><div  v-text="age"></div></div>

name发生变化之后 我需要做的事情是更新俩个p标签,而现在不管你更新了哪个数据,所有的标签都会被重新
操作赋值,无法做到精准更新

解决问题的思路:
1.数据发生变化之后最关键的代码是什么?

 node.innerText = data[name]

2.设计一个存储结构
每一个响应式数据可能被多个标签绑定 是一个‘一对多’的关系

 {name: [()=>{ node(p1).innerText = data[name]},()=>{ node(p2).innerText = data[name]}...]}

发布订阅(自定义事件) 解决的问题就是 ‘1对多’的问题
实现简单的发布订阅模式:
浏览器的事件模型
dom.addEventLister(‘click’,()=>{})
只要调用click事件,所有绑定的回调函数都会执行 显然是一个1对多的关系

  const Dep = {map:{},collect(eventName,fn){// 如果从来没有收集过当前事件就先初始化成数组if(!this.map[eventName]){this.map[eventName] = []}// 已经初始化好了就直接往里面push添加this.map[eventName].push(fn)},trigger(eventName){this.map[eventName].forEach(fn=>fn())}}

使用发布订阅模式优化现存问题
先前的写法 不管是哪个数据发生变化我们都是粗暴的执行一下compile函数即可

现在的写法 我们在compile函数初次执行的时候 完成更新函数的收集 然后在数据变化的时候
通过数据的key找到相对应的更新函数 依次执行 达到精准更新的效果

写在最后

原创不易,还希望各位大佬支持一下\textcolor{blue}{原创不易,还希望各位大佬支持一下}

👍 点赞,你的认可是我创作的动力!\textcolor{green}{点赞,你的认可是我创作的动力!}

⭐️ 收藏,你的青睐是我努力的方向!\textcolor{green}{收藏,你的青睐是我努力的方向!}

✏️ 评论,你的意见是我进步的财富!\textcolor{green}{评论,你的意见是我进步的财富!}

看完文章啦 验证大家对这篇文章的掌握 大家参与下方的投票呦!

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

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

相关文章

Scrum之成败——从自身案例说起,仅供参考

从07年中初次接触Scrum的概念到其中几年项目中逐渐实践CI、TDD&#xff0c;到亲自掌握项目实践Scrum近一年&#xff0c;最终我们放弃了Scrum这个框架和所谓的“自组织”。原因为何&#xff1f; 1.成员放弃了Scrum所“赋予”的“权利” 比如领用任务、评估工作量、自组织协作、决…

sanic官方文档解析之下载和Configuration

1,sanic框架是做什么的? sanic的官方网址:https://sanic.readthedocs.io/en/latest/sanic框架是一个类似于flask框架的在Python3.5以上版本的文本服务器,他能够快速的编写,它是通过惊人的开发效率完成开发,希望通过这篇文章得到激励sanic框架的理念是:简单,高效 sanic的应用如…

首秀 Express 框架

文章目录框架特性express的使用初始化项目&#xff1a;下载框架模块&#xff1a;测试代码&#xff1a;总结以上代码&#xff1a;请求处理的中间件概念&#xff1a;中间件——app.use基本用法&#xff1a;next的用法app.use中间件的应用路由的保护网站维护公告自定义404&#xf…

云原生技能树测评

前言 利用午休后的10多分钟时间&#xff0c;看了看APP的技能树板块&#xff0c;简单的提出几个看法&#xff01; 答题过程 可以设置为闯关类型&#xff0c;答对一道后可以进入下一关&#xff0c;或者是一个章节为一关&#xff0c;让大家一直有一种期待 回答错误数量 可以…

原型和闭包

原型和闭包 一切皆对象 一切皆对象&#xff08;类型值除外&#xff09; undefined, number, string, boolean属于简单的值类型 函数、数组、对象、new Number(10)都是对象。他们都是引用类型 Null是基本数据类型&#xff0c;不是引用数据类型 基本数据类型的值就是它本身的值&a…

python 排序算法

冒泡排序&#xff1a; 1 #coding:utf-82 3 比较相邻的元素&#xff0c;每一趟交换后&#xff0c;最后的元素是最大的。4 第一次比较n-1次&#xff0c;第二次比较n-2次。。。第n-1次比较1次5 进行n-1次冒泡次数6 最优时间复杂度O(n),最坏时间复杂度O(n^2)7 8 9 def bubble_sort…

奖励 CSDN 社区的领军人物

设计动机 领军人物榜单在这里&#xff1a;https://blog.csdn.net/rank/list/role CSDN 是中国 IT 人士学习、成长、成功的平台&#xff0c; 这个平台有很多博主&#xff0c; 博主写的很多优秀文章获得了粉丝。 那么&#xff0c; 博主获得粉丝之后&#xff0c; 博主以粉丝为荣…

一文教会你何为重绘、回流?

文章目录css图层图层创建的条件重绘(Repaint)回流触发重绘的属性触发回流的属性常见的触发回流的操作优化方案requestAnimationFrame----请求动画帧写在最后学习目标&#xff1a; 了解前端Dom代码、css样式、js逻辑代码到浏览器展现过程了解什么是图层了解重绘与回流了解前端层…

mockjs中的方法(三)

1&#xff09;Mock.mock()&#xff1b; Mock.mock( url, type, template, function(options) ); 其中 url 是定义我们要请求的 url 地址&#xff0c;以便于我们请求的时候 mock 去进行拦截&#xff0c;知道我们要去请求那个值&#xff1b;但是它也是可选的&#xff0c;而且格式…

js函数、js对象的这些点你真的懂吗?

本篇学习目标 ✨了解函数&#xff08;高级&#xff09;原型原型链概念\textcolor{green}{了解函数&#xff08;高级&#xff09;原型原型链概念}了解函数&#xff08;高级&#xff09;原型原型链概念 ✨掌握函数作用域\textcolor{green}{掌握函数作用域}掌握函数作用域 ✨掌握…

前端处理跨域的几种方式

什么是跨域&#xff1f; 跨域是指一个域下的文档或脚本试图去请求另一个域下的资源&#xff0c;这里跨域是广义的。 广义的跨域&#xff1a; 1、资源跳转&#xff1a;A链接、重定向、表单提交 2、资源嵌入&#xff1a; <link>、<script>、<img>、<frame&g…

程序员必知的缓存套图

文章目录1. 线程与进程1.1 进程:1.2. 线程:1.3. 关系2. 浏览器内核模块组成4. 事件循环机制5. 缓存5.1. 缓存理解5.2. 缓存分类5.3. 缓存使用示意图5.4. 缓存中的header参数1. 线程与进程 1.1 进程: 进程是计算机中的程序关于某数据集合上的一次运行活动&#xff0c;是系统进…

安装webpack及使用

前言 你是否也是只会运用框架中集成好的Webpack配置呢&#xff1f;你明白每一项的意义么&#xff1f;你懂多少Webpack的个性化配置项呢&#xff1f;本篇文章为你讲解Webpack中的各种配置项参数及作用&#xff01; 文章目录了解Webpack相关开启项目编译打包应用使用webpack配置…

Python基础-os模块 sys模块

sys模块 与操作系统交互的一个接口 文件夹相关 os.makedirs(dirname1/dirname2) 可生成多层递归目录os.removedirs(dirname1) 若目录为空&#xff0c;则删除&#xff0c;并递归到上一级目录&#xff0c;如若也为空&#xff0c;则删除&#xff0c;依此类推os.mkdir(dirnam…

php单例型(singleton pattern)

搞定&#xff0c;吃饭 <?php /* The purpose of singleton pattern is to restrict instantiation of class to a single object. It is implemented by creating a method within the class that creates a new instance of that class if one does not exist. If an obje…

开启关闭各种服务

开启&关闭 Mac版 查找被占用的8080端口&#xff0c;根据pid杀掉进程 查找8080端口 losf -i:8080 根据pid杀掉进程 kill -9 pid iMac:~ acui$ lsof -i:8080 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME java 62948 ting 93u IPv6 0x6697d6…

助你提高效率的几个Vue指令

前言 很多使用Vue的同学往往最容易忽略的指令&#xff0c;由于在这里考虑到很多初学甚至还没有开始接触Vue的同学呢&#xff0c;在介绍v-clos之前呢就先以大家都熟知的v-model编写小demo v-model 相信大家对v-model并不陌生&#xff0c;简单来讲他就是用于在表单控件以及组建…

掌握Mock摆脱后端同学的束缚

文章目录前言Mock概述mock.js安装Mock规范Mock的使用总结前言 当下采用前后端分离模式开发Web应用已经成为气候&#xff0c;在开发阶段有一个不成文的规定则是 项目开发后端先行 但是作为前端开发工程师的我们&#xff0c;难道在搭建完页面后只能等待后端的接口么&#xff1f;…

户外鞋简介

. 单论品牌&#xff08;主要以登山鞋及徙步鞋为主&#xff09;&#xff1a; 高级品牌&#xff1a;SCARPA、ASOLO、MONTRAIL、ZAMBERLAN、vasque、Lowa、La Sportiva 价格都较高&#xff0c;单价都在千元以上&#xff0c;品质一流&#xff0c;做工精细。 中档品牌&#xff1a;Tr…

Vue技能树上线啦

前言 前端现在越来越多样化&#xff0c;语言众多&#xff0c;大家使用的框架也比较杂&#xff0c;在广泛的前端技术栈面前我唯爱Vue&#xff08;仅代表个人观点勿喷小伙伴们&#xff09;可能很多人觉得我是因为简单&#xff0c;其实并不然&#xff0c;我尝试过很多框架&#x…