拆解Vue - 手写MVVM (2)

363 阅读3分钟

mvvm.js(中枢办公室)

	* ifredom同学,来到公司,刚刚刷完新闻,准备开始愉快的工作。
	* 突然收到消息,下午领导要来视察了!
	* 这下可好,得先拿出一个肉眼可见的成果出来展示。
	* 怎么办呢?先把最终的样子做出来,至于里面是什么状态嘛,大家都懂。
	* 还好,有现成的Vue可以模仿,那就先模仿调用写写看。

index.html

先观摩观摩Vue官方给出的极简示例是什么样。
一部分html内容, 一部分JS内容,一部分最终呈现UI。其中核心的JS内容,通过类Vue创建了一个实例 app,其中传了一个对象形式的参数,参数内含有两项 eldata. 在这里插入图片描述

	* ifredom 想了想,直接创建 index.html ,模仿Vue参数调用的形式.
	* 引入一个空文件 mvvm.js 模拟vue.js.
	* 当然也要有一个获取参数的操作,打印一下。
	* 也要有一个改变参数的操作,使用延时模拟一下。
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>mvvm-demo</title>
</head>

<body>
  <div id="app">
    <div class="name"></div>
  </div>

  <script src="mvvm.js"></script>
  <script>
  
    var vm = new Mvvm({
      el: "#app",
      data: {
        name: "ifredom"
      }
    })
    console.log(vm); //  Mvvm(...)
    //  获取参数,并打印
    console.log(vm.name); // undefined
    
    setTimeout(() => {
      //  设置参数
      vm.name = "newValue";
      console.log(vm); // Mvvm(...)
      console.log(vm.name); // newValue
    }, 2000);

  </script>
</body>

</html>
* 经过观察,Vue是一个类,el参数,作用是存储dom节点,获取方式类似jquery。
* data参数不知道有啥用,先保存在this._data上。
* (此处取名为_data也是跟vue保持一致)

mvvm.js

class Mvvm {
  constructor(options) {
    this.el = document.querySelector(options.el);
    this._data = options.data;
  }
}

* mvvm.js(中枢办公室)的架子已经搭建起来了,  index调用mvvm类.

* var app = new Vue(...) 

* 这里有个问题,Vue所有在data中的参数都是可以直接通过新创建的实例app.message拿到......

* 而我写的vm.name打印结果是 undefined,说明没有获取到data传入的参数

* 先把这一步模仿出来,使用跟vue一样的方式:

object.defineProperty(参数代理)

// mvvm.js
class Mvvm {
  constructor(options) {
    this.el = document.querySelector(options.el);
    this._data = options.data; // 

    this.proxyData(options.data);
  }

  // 参数代理, 实现 vm.xxx -> vm._data.xxx
  proxyData(data) {
    Object.keys(data).forEach((key) => {
      Object.defineProperty(this, key, {
        get() {
          return this._data[key];
        },
        set(newValue) {
          this._data[key] = newValue;
        },
        enumerable: true,
        configurable: true,
      });
    });
  }
}

写好了代理参数后,再测试一下参数的读写情况

// index.html
  <script>
    var vm = new Mvvm({
      el: "#app",
      data: {
        name: "ifredom"
      }
    })
    console.log(vm);	// Mvvm(...)
    console.log(vm.name); // ifredom  !!!不再是undefined
    setTimeout(() => {
      vm.name = "Tom";
      console.log(vm);	// Mvvm(...)
      console.log(vm._data.name);// Tom
      console.log(vm.name); // Tom   代理成功
    }, 2000);
  </script>

ui更新

	* 办公室已经搭建好了,(获取)收集信息,(设置)发送信息也已经没有问题,距离给boss展示的PPT产品,只差让信息 (data) 的变化在UI上表现出来。
	* 这一步就需要朝阳市民(compile)去执行,首先收集UI信息,然后在收到信息变化后,能够更新UI.
	* 不过时间紧迫啊,PPT产品,能变化UI即可。
	* 所以,一旦set值,那么我就更新UI.

很简单就一句代码。

  // 参数代理, 实现 vm.xxx -> vm._data.xxx
  proxyData(data) {
    Object.keys(data).forEach((key) => {
      Object.defineProperty(this, key, {
        get() {
          return this._data[key];
        },
        set(newValue) {
          this.el.innerHTML = this._data[key]; // 更改模板数据的值
          this._data[key] = newValue;
        },
        enumerable: true,
        configurable: true,
      });
    });
  }
 * 呵呵,应付BOSS足够了.
 * 天网监控系统(MVVM)不就是这样么,数据变化,UI更新,这不就成了么?
 * 不过我们显然不能止步于此,给boss优化用户体验,提升产品竞争力,拿下年度最强PPT...
 * 添加个输入框可以输入任意数据,而不是将数据在代码里写死。
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>mvvm-demo</title>
</head>

<body>
  <div id="app"></div>
  <input type="text" id="input">

  <script src="mvvm.js"></script>
  <script>
    var vm = new Mvvm({
      el: "#app",
      data: {
        name: "ifredom"
      }
    })

    setTimeout(() => {
      vm.name = "Tom";
    }, 2000);

    var input = document.querySelector("#input");
    input.addEventListener("input",function(e){
      vm.name = e.target.value;
    })

  </script>
</body>

</html>

PPT展示效果

在这里插入图片描述

------ 如果文章对你有用,感谢>>>点赞 | 收藏 <<<