根据Object.defineProperty 获取对象中属性值与属性值改变时的触发时机

  1. let obj = {};
  2. let userName = "rock"
  3. Object.defineProperty(obj, 'userName', {
  4. get() {
  5. // 添加依赖
  6. return userName;
  7. },
  8. set(newVal) {
  9. // 更新依赖
  10. console.log(newVal, 'setter')
  11. userName = newVal;
  12. }
  13. })
  14. obj.userName
  15. "rock"
  16. obj.userName = '12'
  17. 12 setter
  18. "12"

极简版的Vue

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>Document</title>
  7. </head>
  8. <body>
  9. <div class="app">
  10. <h3>极简版vue</h3>
  11. <div class="userName">{{userName}}</div>
  12. <div class="description">{{description}}</div>
  13. <input type="text" v-modal="userName" />
  14. <input type="text" v-modal="description" />
  15. </div>
  16. </body>
  17. <script src="./1.js"></script>
  18. <script>
  19. window.onload = function () {
  20. let app = new Vue({
  21. el: '.app',
  22. data: {
  23. userName: '我是rock++',
  24. description: '前端技术学习',
  25. },
  26. });
  27. };
  28. </script>
  29. </html>
  1. let targetNodes = [];
  2. let target = null;
  3. function defineReactive(data) {
  4. Object.keys(data).forEach(key => {
  5. let val = data[key];
  6. let dep = new Dependence();
  7. Object.defineProperty(data, key, {
  8. get() {
  9. // 添加依赖
  10. dep.push();
  11. targetNodes.push(val)
  12. return val
  13. },
  14. set(newVal) {
  15. dep.notify(newVal)
  16. val = newVal;
  17. }
  18. })
  19. })
  20. return data
  21. }
  22. class Dependence {
  23. static target = null;
  24. targetNodes = [];
  25. push() {
  26. if (Dependence.target) {
  27. this.targetNodes.push(Dependence.target)
  28. }
  29. }
  30. notify(value) {
  31. console.log(value, this)
  32. this.targetNodes.forEach(node => {
  33. node.textContent = value
  34. })
  35. }
  36. }
  37. function compile(data, template) {
  38. let children = template.children;
  39. for (let i = 0; i < children.length; i++) {
  40. let childEl = children[i];
  41. if (childEl.matches("[v-modal]")) {
  42. let attr = childEl.getAttribute("v-modal");
  43. childEl.value = data[attr];
  44. childEl.addEventListener("input", function (ev) {
  45. data[attr] = ev.target.value
  46. })
  47. } else {
  48. const content = childEl.textContent;
  49. const regexp = /{{(.+?)\}\}/;
  50. const match = content?.match(regexp);
  51. if (match) {
  52. const key = match[1];
  53. Dependence.target = childEl;
  54. childEl.innerText = data[key]
  55. Dependence.target = null
  56. }
  57. }
  58. }
  59. }
  60. class Vue {
  61. constructor({ el, data }) {
  62. let templateNode = document.querySelector(el);
  63. const observeableData = defineReactive(data);
  64. console.log(observeableData, 'observeableData')
  65. compile(observeableData, templateNode);
  66. console.log(Dependence.targetNodes, '>targetNodes>')
  67. }
  68. }