松鼠乐园 松鼠乐园
  • 注册
  • 登录
  • 首页
  • 快捷入口
    • Vue
    • Tensorflow
    • Springboot
    • 语言类
      • CSS
      • ES5
      • ES6
      • Go
      • Java
      • Javascript
    • 工具类
      • Git
      • 工具推荐
    • 服务器&运维
      • Centos
      • Docker
      • Linux
      • Mac
      • MySQL
      • Nginx
      • Redis
      • Windows
    • 资源类
      • 论文
      • 书籍推荐
      • 后端资源
      • 前端资源
      • html网页模板
      • 代码
    • 性能优化
    • 测试
  • 重大新闻
  • 人工智能
  • 开源项目
  • Vue2.0从零开始
  • 广场
首页 › Vue › 118行代码实现一个简单的Vue!深入了解Vue核心原理

118行代码实现一个简单的Vue!深入了解Vue核心原理

迦娜王
2年前Vue
514 0 0
vue的使用方法相信大家都很熟练了,使用起来很简单。但是大部分人不知道其内部的核心原理是怎么样的,今天我们就来一起实现一个简单的vue!
118行代码实现一个简单的Vue!深入了解Vue核心原理
Vue.js

Object.defineProperty() – Vue双向数据绑定实现的核心

实现之前我们得先看一下Object.defineProperty的实现,因为vue主要是通过数据劫持来实现的,通过get、set来完成数据的读取和更新。
118行代码实现一个简单的Vue!深入了解Vue核心原理
Object.defineProperty的实现
118行代码实现一个简单的Vue!深入了解Vue核心原理
Object.defineProperty的实现 从上面可以看到通过get获取数据,通过set监听到数据变化执行相应操作,还是不明白的话可以去看看Object.defineProperty文档。

数据->视图 流程图

118行代码实现一个简单的Vue!深入了解Vue核心原理
数据->视图 流程图

html代码结构

118行代码实现一个简单的Vue!深入了解Vue核心原理
html代码

js调用

118行代码实现一个简单的Vue!深入了解Vue核心原理
js调用 Vue

Vue结构

118行代码实现一个简单的Vue!深入了解Vue核心原理
Vue结构
  • Vue constructor: 构造函数主要是数据的初始化
  • proxyData: 数据代理
  • observer: 劫持监听所有数据
  • compile: 解析dom
  • compileText: 解析dom里处理纯双花括号的操作
  • Watcher: 更新视图操作

Vue constructor 构造函数初始化

118行代码实现一个简单的Vue!深入了解Vue核心原理
Vue constructor 初始化 上面主要是初始化操作,针对传过来的数据进行处理

proxyData – 代理data

118行代码实现一个简单的Vue!深入了解Vue核心原理
proxyData 代理data 上面主要是代理data到最上层,this.xxx的方式直接访问data

observer – 劫持监听

118行代码实现一个简单的Vue!深入了解Vue核心原理
observer 劫持监听 同样是使用 Object.defineProperty 来监听数据,初始化需要订阅的数据。 把需要订阅的数据到push到watcherTask里,等到时候需要更新的时候就可以批量更新数据了下面就是; 遍历订阅池,批量更新视图。
118行代码实现一个简单的Vue!深入了解Vue核心原理
遍历订阅池,批量更新视图

compile -解析dom

首先我们先遍历el元素下面的所有子节点,node.nodeType === 3 的意思是当前元素是文本节点,node.nodeType === 1 的意思是当前元素是元素节点。因为可能有的是纯文本的形式,如纯双花括号就是纯文本的文本节点,然后通过判断元素节点是否还存在子节点,如果有的话就递归调用compile方法。下面重头戏来了,我们拆开看:
118行代码实现一个简单的Vue!深入了解Vue核心原理
上面这个首先判断node节点上是否有v-html这种指令,如果存在的话,我们就发布订阅,怎么发布订阅呢?只需要把当前需要订阅的数据push到watcherTask里面,然后到时候在设置值的时候就可以批量更新了,实现双向数据绑定,也就是下面的操作
118行代码实现一个简单的Vue!深入了解Vue核心原理
然后push的值是一个Watcher的实例,首先他new的时候会先执行一次,执行的操作就是去把纯双花括号 -> 1,也就是说把我们写好的模板数据更新到模板视图上。 最后把当前元素属性剔除出去,我们用Vue的时候也是看不到这种指令的,不剔除也不影响 至于Watcher是什么,看下面就知道了

Watcher 观察者

118行代码实现一个简单的Vue!深入了解Vue核心原理
Watcher 之前发布订阅之后走了这里面的操作,意思就是把当前元素如:node.innerHTML = ‘这是data里面的值’、node.value = ‘这个是表单的数据’ 那么我们为什么不直接去更新呢,还需要update做什么,不是多此一举吗? 其实update记得吗?我们在订阅池里面需要批量更新,就是通过调用Watcher原型上的update方法。

效果

118行代码实现一个简单的Vue!深入了解Vue核心原理
效果 在线演示: http://www.wclimb.site/myVue/

完整代码

class Vue{
 constructor(options = {}){
 this.$el = document.querySelector(options.el);
 let data = this.data = options.data; 
 // 代理data,使其能直接this.xxx的方式访问data,正常的话需要this.data.xxx
 Object.keys(data).forEach((key)=> {
 this.proxyData(key);
 });
 this.methods = options.methods // 事件方法
 this.watcherTask = {}; // 需要监听的任务列表
 this.observer(data); // 初始化劫持监听所有数据
 this.compile(this.$el); // 解析dom
 }
 proxyData(key){
 let that = this;
 Object.defineProperty(that, key, {
 configurable: false,
 enumerable: true,
 get () {
 return that.data[key];
 },
 set (newVal) {
 that.data[key] = newVal;
 }
 });
 }
 observer(data){
 let that = this
 Object.keys(data).forEach(key=>{
 let value = data[key]
 this.watcherTask[key] = []
 Object.defineProperty(data,key,{
 configurable: false,
 enumerable: true,
 get(){
 return value
 },
 set(newValue){
 if(newValue !== value){
 value = newValue
 that.watcherTask[key].forEach(task => {
 task.update()
 })
 }
 }
 })
 })
 }
 compile(el){
 var nodes = el.childNodes;
 for (let i = 0; i < nodes.length; i  ) {
 const node = nodes[i];
 if(node.nodeType === 3){
 var text = node.textContent.trim();
 if (!text) continue;
 this.compileText(node,\'textContent\') 
 }else if(node.nodeType === 1){
 if(node.childNodes.length > 0){
 this.compile(node)
 }
 if(node.hasAttribute(\'v-model\') && (node.tagName === \'INPUT\' || node.tagName === \'TEXTAREA\')){
 node.addEventListener(\'input\',(()=>{
 let attrVal = node.getAttribute(\'v-model\')
 this.watcherTask[attrVal].push(new Watcher(node,this,attrVal,\'value\'))
 node.removeAttribute(\'v-model\')
 return () => {
 this.data[attrVal] = node.value
 }
 })())
 }
 if(node.hasAttribute(\'v-html\')){
 let attrVal = node.getAttribute(\'v-html\');
 this.watcherTask[attrVal].push(new Watcher(node,this,attrVal,\'innerHTML\'))
 node.removeAttribute(\'v-html\')
 }
 this.compileText(node,\'innerHTML\')
 if(node.hasAttribute(\'@click\')){
 let attrVal = node.getAttribute(\'@click\')
 node.removeAttribute(\'@click\')
 node.addEventListener(\'click\',e => {
 this.methods[attrVal] && this.methods[attrVal].bind(this)()
 })
 }
 }
 }
 }
 compileText(node,type){
 let reg = /\{\{(.*?)\}\}/g, txt = node.textContent;
 if(reg.test(txt)){
 node.textContent = txt.replace(reg,(matched,value)=>{
 let tpl = this.watcherTask[value] || []
 tpl.push(new Watcher(node,this,value,type))
 if(value.split(\'.\').length > 1){
 let v = null
 value.split(\'.\').forEach((val,i)=>{
 v = !v ? this[val] : v[val]
 })
 return v
 }else{
 return this[value]
 }
 })
 }
 }
}
class Watcher{
 constructor(el,vm,value,type){
 this.el = el;
 this.vm = vm;
 this.value = value;
 this.type = type;
 this.update()
 }
 update(){ 
 this.el[this.type] = this.vm.data[this.value]
 }
}

完整代码已经放到github上了 -> https://github.com/wclimb/MyVue

结语

感兴趣的朋友可以访问 http://hcysun.me/vue-design/ 查看 Vue核心技术解析 逐行级别的 Vue 源码分析 🙂
118行代码实现一个简单的Vue!深入了解Vue核心原理
vue vue原理
0
12 种使用 Vue 的最佳做法
上一篇
推荐21个顶级的Vue UI库!
下一篇
评论 (0)

请登录以参与评论。

现在登录
聚合文章
Servicios profesionales Organizaciones
1年前
在Gitee收获近 5k Star,更新后的Vue版RuoYi有哪些新变化?
1年前
vue3.x reactive、effect、computed、watch依赖关系及实现原理
1年前
Vue 3 新特性:在 Composition API 中使用 CSS Modules
1年前
标签
AI AI项目 css docker Drone Elaticsearch es5 es6 Geometry Go gru java Javascript jenkins lstm mysql mysql优化 mysql地理位置索引 mysql索引 mysql规范 mysql设计 mysql配置文件 mysql面试题 mysql高可用 nginx Redis redis性能 rnn SpringBoot Tensorflow tensorflow2.0 UI设计 vue vue3.0 vue原理 whistle ZooKeeper 开源项目 抓包工具 日志输出 机器学习 深度学习 神经网络 论文 面试题
相关文章
在Gitee收获近 5k Star,更新后的Vue版RuoYi有哪些新变化?
vue3.x reactive、effect、computed、watch依赖关系及实现原理
Vue 3 新特性:在 Composition API 中使用 CSS Modules
新手必看的前端项目去中心化和模块化思想
松鼠乐园

资源整合,创造价值

小伙伴
墨魇博客 无同创意
目录
重大新闻 Centos CSS Docker ES5 ES6 Go Java Javascript Linux Mac MySQL Nginx Redis Springboot Tensorflow Vue Vue2.x从零开始 Windows 书籍推荐 人工智能 前端资源 后端资源 壁纸 开源项目 测试 论文
Copyright © 2018-2022 松鼠乐园. Designed by nicetheme. 浙ICP备15039601号-4
  • 重大新闻
  • Centos
  • CSS
  • Docker
  • ES5
  • ES6
  • Go
  • Java
  • Javascript
  • Linux
  • Mac
  • MySQL
  • Nginx
  • Redis
  • Springboot
  • Tensorflow
  • Vue
  • Vue2.x从零开始
  • Windows
  • 书籍推荐
  • 人工智能
  • 前端资源
  • 后端资源
  • 壁纸
  • 开源项目
  • 测试
  • 论文
热门搜索
  • jetson nano
  • vue
  • java
  • mysql
  • 人工智能
  • 人脸识别
迦娜王
坚持才有希望
1224 文章
35 评论
242 喜欢
  • 0
  • 0
  • Top