vue核心原理实现

vue示例

通过一个小案例, 对比vue开发和原生开发的区别

  1. vue的核心就是数据响应式, 数据改变视图跟随改变

  2. 通过数据驱动视图, 我们就不用直接操作DOM元素了, 这就是vue开发与原生开发的区别

    Document

    {{title}}

    {{item.name}}
    {{item.choose}}
    复制代码
     <script src="./js/data.js"></script>
     <script src="./js/vue.js"></script>
     <script src="./js/index.js"></script>

    var goods = [
    {
    name: 'iPhone 12',
    choose: 0,
    },
    {
    name: '荣耀X30',
    choose: 1,
    },
    {
    name: 'Redmi Note 11',
    choose: 3,
    },
    {
    name: 'OPPO K9x',
    choose: 0,
    },
    {
    name: '华为Nova10pro',
    choose: 1,
    },
    ];

    var vm = new Vue({
    // 配置对象
    el: '.container',
    data: {
    // 界面数据
    title: '淘东手机',
    goods: goods,
    },
    // 计算属性
    computed: {
    count: function () {
    var sum = 0;
    for (var i = 0; i < this.goods.length; i++) {
    sum += this.goods[i].choose;
    }
    return sum;
    },
    },
    });

vue原理

准备基础代码

复制代码
.card {
  width: 300px;
  border: 2px solid rgb(74, 125, 142);
  border-radius: 10px;
  font-size: 2em;
  padding: 0 20px;
  margin: 0 auto;
  background: lightblue;
  color: #333;
}

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
  <link rel="stylesheet" href="./index.css" />
</head>

<body>
  <div class="card">
    <p id="firstName"></p>
    <p id="lastName"></p>
    <p id="age"></p>
  </div>
  // <input type="text" oninput="user.name = this.value" />
  // <input type="date" onchange="user.birth = this.value" />
  <script src="./index.js"></script>
</body>

</html>

var user = {
  name: '袁进',
  birth: '2002-5-7',
};

// 显示姓氏
function showFirstName() {
  document.querySelector('#firstName').textContent = '姓:' + user.name[0];
}

// 显示名字
function showLastName() {
  document.querySelector('#lastName').textContent = '名:' + user.name.slice(1);
}

// 显示年龄
function showAge() {
  var birthday = new Date(user.birth);
  var today = new Date();
  today.setHours(0), today.setMinutes(0), today.setMilliseconds(0);
  thisYearBirthday = new Date(
    today.getFullYear(),
    birthday.getMonth(),
    birthday.getDate()
  );
  var age = today.getFullYear() - birthday.getFullYear();
  if (today.getTime() < thisYearBirthday.getTime()) {
    age--;
  }
  document.querySelector('#age').textContent = '年龄:' + age;
}


showFirstName()
showLastName()
showAge()

改造一下程序, 初步实现 "数据驱动视图"

复制代码
var user = {
  name: '袁进',
  birth: '2002-5-7',
};

// 显示姓氏
function showFirstName() {
  document.querySelector('#firstName').textContent = '姓:' + user.name[0];
}

// 显示名字
function showLastName() {
  document.querySelector('#lastName').textContent = '名:' + user.name.slice(1);
}

// 显示年龄
function showAge() {
  var birthday = new Date(user.birth);
  var today = new Date();
  today.setHours(0), today.setMinutes(0), today.setMilliseconds(0);
  thisYearBirthday = new Date(
    today.getFullYear(),
    birthday.getMonth(),
    birthday.getDate()
  );
  var age = today.getFullYear() - birthday.getFullYear();
  if (today.getTime() < thisYearBirthday.getTime()) {
    age--;
  }
  document.querySelector('#age').textContent = '年龄:' + age;
}


showFirstName()
showLastName()
showAge()


/**
 * 当我们改变数据时, 如何让视图更新呢?
 * --重新调用一下方法呗! 这不很简单嘛 
 */
user.name = '张三彭'
showFirstName()
showLastName()

user.birth = '1999-1-1'
showAge()


/**
 * 可以实现自动调用方法吗? 
 * 当我改变了数据, 就自动调用方法更新视图.岂不美哉?
 * --我来试试吧
 */
user.name = '张三彭'
// 如何自动调用依赖该属性的函数?
// showFirstName()
// showLastName()

/**
 * 思路分析
 * 1.如何感知属性的读取和设置呢? -- 属性访问器
 * 2.自动调用依赖属性的方法
 */
let internalName = user.name;
Object.defineProperty(user, 'name', {
  get: function () {
    console.log('有人在读取 name 属性');
    return internalName;
  },
  set: function (val) {
    internalName = val
    console.log('有人修改 name 属性, 值为' + val);
    showFirstName()
    showLastName()
  }
})
user.name = '李四康'
  1. 现在, 无论是通过编码还是通过控制台, 只要修改了user对象的name属性, 就可以自动调用该属性的方法, 从而自动更新视图

上面的代码还只是玩具, 如果需要通用, 就要封装

复制代码
/**
 * 观察对象的所有属性
 */
// 问题1: 如何调用依赖该属性的函数???
// --在get函数中依赖收集
// --在set函数中派发更新
function observe(obj) {
  for (const key in obj) {
    let internalValue = obj[key]
    let funcs = [];
    Object.defineProperty(obj, key, {
      get: function () {
        // 依赖收集:  记录是哪些函数在用我
        if (window.__func && !funcs.includes(window.__func)) {
          funcs.push(window.__func);
        }
        return internalValue
      },
      set: function (val) {
        internalValue = val
        // 派发更新: 运行依赖我的函数
        for (let index = 0; index < funcs.length; index++) {
          funcs[index]()
        }
      }
    })
  }
}


// 问题2: 依赖怎么收集呢?
// --封装一个代理方法, 方法执行前记录方法
// --方法不要直接调用, 使用代理方法间接调用
// autorun <- showFristName
function autorun(fn) {
  window.__func = fn
  fn()
  window.__func = null
}

var user = {
  name: '袁进',
  birth: '2002-5-7',
};

// 显示姓氏
function showFirstName() {
  document.querySelector('#firstName').textContent = '姓:' + user.name[0];
}

// 显示名字
function showLastName() {
  document.querySelector('#lastName').textContent = '名:' + user.name.slice(1);
}

// 显示年龄
function showAge() {
  var birthday = new Date(user.birth);
  var today = new Date();
  today.setHours(0), today.setMinutes(0), today.setMilliseconds(0);
  thisYearBirthday = new Date(
    today.getFullYear(),
    birthday.getMonth(),
    birthday.getDate()
  );
  var age = today.getFullYear() - birthday.getFullYear();
  if (today.getTime() < thisYearBirthday.getTime()) {
    age--;
  }
  document.querySelector('#age').textContent = '年龄:' + age;
}

/**
 * 封装代码
 */
observe(user) // 观察对象

autorun(showFirstName)
autorun(showLastName)
autorun(showAge)

<!DOCTYPE html>
<html lang="en">

<head>
  ... ... 
</head>

<body>
  <div class="card">
    <p id="firstName"></p>
    <p id="lastName"></p>
    <p id="age"></p>
  </div>
  <input type="text" oninput="user.name = this.value" />
  <input type="date" onchange="user.birth = this.value" />
  <script src="./iuv.js"></script>
  <script src="./index.js"></script>
</body>

</html>
  1. 整个代码的健壮性还是不够的, 但是代码的思想跟vue源码是一致的
  2. 数据响应式的本质是数据变化后自动调用依赖数据的方法
相关推荐
木圭的AI时代指南3 分钟前
实测 MiniMax M3.1 Flash:同一道 Three.js 大题,两个 agent 差出 4.6 倍
开发语言·javascript·ecmascript
西红柿炖牛腩3549 分钟前
3D 模型压缩脚本又报错又配环境?换个不用维护的方案
javascript·3d·性能优化
tryCbest41 分钟前
Vue3——第 6 篇:事件处理与表单绑定——v-on 与 v-model
前端·javascript·vue.js
恋猫de小郭44 分钟前
Flutter 的文字为什么比 SwiftUI 更细?问题主要在 Skia 的 256 项查找表里
android·前端·flutter
lexiangqicheng1 小时前
前端高阶面试核心通关指南:深入解析Vue3与React18底层原理及性能优化
前端·面试·性能优化
怕浪猫1 小时前
前端对接聊天 API:我用 React 做了一个比 ChatGPT 还好看的界面
前端·后端·面试
程序员小孔.1 小时前
基于 Spring Cloud + Vue 的 JEEWMS 开源仓储管理平台设计与实现
前端·javascript·vue.js·spring boot·spring cloud·开源
IT_陈寒1 小时前
深入理解Python:核心原理与最佳实践
前端·人工智能·后端
创世虚拟世界1 小时前
把 3D 虚拟世界拉到本地:vibe coding 的手感,是从看见自己那一行改动开始的
javascript·数据库·人工智能·3d·gitee·虚拟现实
我喜欢就喜欢1 小时前
Chrome 插件开发实战指南
前端·chrome