首页 > 其他分享 >手动实现 vue3 [ reactive, computed, watch ]

手动实现 vue3 [ reactive, computed, watch ]

时间:2022-11-17 01:55:08浏览次数:56  
标签:const computed Dep watch Watcher reactive target

一、vue.js

1 import reactive from "./reactive";
2 import Watcher from "./Watcher";
3 import computed from "./computed";
4 import watch from "./watch";
5 
6 export { reactive, Watcher, computed, watch };

二、reactive.js

 1 import { isObject } from "./utils";
 2 import Dep from "./Dep";
 3 
 4 export default function reactive(data) {
 5     if (isObject(data)) {
 6         Object.keys(data).forEach(function (key) {
 7             defineReactive(data, key);
 8         });
 9     }
10     return data;
11 }
12 function defineReactive(data, key) {
13     let val = data[key];
14     const dep = new Dep();
15 
16     Object.defineProperty(data, key, {
17         get() {
18             dep.depend();
19             return val;
20         },
21         set(newVal) {
22             val = newVal;
23             dep.notify();
24         },
25     });
26 
27     if (isObject(val)) {
28         reactive(val);
29     }
30 }

三、utils.js

1 export function isObject(val) {
2     return typeof val == "object";
3 }

四、Dep.js

 1 export default class Dep {
 2     constructor() {
 3         this.deps = new Set();
 4     }
 5     depend() {
 6         if (Dep.target) {
 7             this.deps.add(Dep.target);
 8         }
 9     }
10     notify() {
11         this.deps.forEach(function (watcher) {
12             watcher.update();
13         });
14     }
15 }
16 Dep.target = null;
17 
18 const targetStack = [];
19 
20 export function pushTarget(_target) {
21     if (Dep.target) {
22         targetStack.push(Dep.target);
23     }
24     Dep.target = _target;
25 }
26 
27 export function popTarget() {
28     if (targetStack.length) {
29         Dep.target = targetStack.pop();
30     } else {
31         Dep.target = null;
32     }
33 }

五、Watcher.js

 1 import Dep, { pushTarget, popTarget } from "./Dep";
 2 
 3 export default class Watcher {
 4     constructor(getter, options = {}) {
 5         const { computed, watch, callback } = options;
 6 
 7         this.getter = getter;
 8         this.computed = computed;
 9         this.watch = watch;
10         this.callback = callback;
11         this.value = "";
12 
13         if (computed) {
14             this.dep = new Dep();
15         } else {
16             this.get();
17         }
18     }
19     depend() {
20         this.dep.depend();
21     }
22     get() {
23         pushTarget(this);
24         const value = this.getter();
25         popTarget();
26         if (this.watch) {
27             this.value = value;
28         }
29         return value;
30     }
31     update() {
32         if (this.computed) {
33             this.get();
34             this.dep.notify();
35         } else if (this.watch) {
36             const oldVal = this.value;
37             this.get();
38             this.callback(this.value, oldVal);
39         } else {
40             this.get();
41         }
42     }
43 }

六、computed.js

 1 import Watcher from "./Watcher";
 2 
 3 export default function computed(getter) {
 4     let def = {};
 5     const watcher = new Watcher(getter, { computed: true });
 6     Object.defineProperty(def, "value", {
 7         get() {
 8             watcher.depend();
 9             return watcher.get();
10         },
11     });
12     return def;
13 }

七、watch.js

1 import Watcher from "./Watcher";
2 
3 export default function watch(getter, callback) {
4     new Watcher(getter, { watch: true, callback });
5 }

八、index.html

 1 <!DOCTYPE html>
 2 <html lang="en">
 3     <head>
 4         <meta charset="UTF-8" />
 5         <meta http-equiv="X-UA-Compatible" content="IE=edge" />
 6         <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 7         <link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
 8         <title>Document</title>
 9     </head>
10     <body>
11         <div id="app">
12             <div class="watcher">
13                 watcher view:
14                 <span class="text"></span>
15                 <button class="change">change</button>
16             </div>
17             <div class="computed">
18                 computed view:
19                 <span class="text"></span>
20                 <button class="change">change</button>
21             </div>
22         </div>
23         <script type="module" src="./main.js"></script>
24     </body>
25 </html>

九、server.js

 1 const http = require("http"),
 2     fs = require("fs");
 3 
 4 const server = new http.Server();
 5 
 6 server.on("request", (req, res) => {
 7     const url = req.url;
 8     const suffix = url.match(/(?<=\.)\w*$/)?.[0] || "js"; // 匹配文件格式
 9     const fileName = url.match(/.*(?=\.\w*$)|\/?\w*/)[0]; // 匹配文件名
10     let mime = "";
11     switch (suffix) {
12         case "html":
13             mime = "text/html";
14             break;
15         case "ico":
16             mime = "image/x-icon";
17             break;
18         default:
19             mime = "text/javascript";
20     }
21 
22     fs.readFile(`.${fileName}.${suffix}`, (err, data) => {
23         res.writeHead(200, {
24             "Content-Type": mime,
25         });
26         res.write(data);
27         res.end();
28     });
29 });
30 
31 server.listen(80);

十、启动

 node server.js ,浏览器访问:http://localhost/index.html

标签:const,computed,Dep,watch,Watcher,reactive,target
From: https://www.cnblogs.com/aurora-power/p/16898141.html

相关文章