模拟vue数据监测-对象

  1. 过程原理:vue将data做一层处理(defineProperty)->赋值给 _data -> 数据代理给vue
  2. 效果:

image.png

  1. 代码 ```vue <!DOCTYPE html>

    1. <meta charset="UTF-8" />
    2. <title>Document</title>

    1. <script type="text/javascript" >
    2. let data = {
    3. name:'尚硅谷',
    4. address:'北京',
    5. }
    6. //创建一个监视的实例对象,用于监视data中属性的变化
    7. const obs = new Observer(data)
    8. console.log(obs)
    9. //准备一个vm实例对象
    10. let vm = {}
    11. vm._data = data = obs
    12. function Observer(obj){
    13. //汇总对象中所有的属性形成一个数组
    14. const keys = Object.keys(obj)
    15. //遍历
    16. keys.forEach((k)=>{
    17. Object.defineProperty(this,k,{
    18. get(){
    19. return obj[k]
    20. },
    21. set(val){
    22. console.log(`${k}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`)
    23. obj[k] = val
    24. }
    25. })
    26. })
    27. }
  1. </script>
  2. </body>

  1. <a name="tzQSA"></a>
  2. # vue数据监测
  3. **vue会给data每一层递归添加defineProperty,无论是数组还是对象**<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1624878/1626516625090-e75960c8-aa54-44f5-bd2b-76a4a79ecd8b.png#clientId=u145a8a1f-3452-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=520&id=Sqdj8&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1039&originWidth=940&originalType=binary&ratio=1&rotation=0&showTitle=false&size=162719&status=done&style=none&taskId=ua7e3b7c2-a36e-4dce-91b8-0fae2be25c9&title=&width=470)<br />**注意事项:**
  4. 1. vm = this
  5. 1. 不能操作数组索引要用API
  6. 1. 后追加的属性没有响应式,要用set
  7. ```vue
  8. <!DOCTYPE html>
  9. <html>
  10. <body>
  11. <!--
  12. Vue监视数据的原理:
  13. 1. vue会监视data中所有层次的数据。
  14. 2. 如何监测对象中的数据?
  15. 通过setter实现监视,且要在new Vue时就传入要监测的数据。
  16. (1).对象中后追加的属性,Vue默认不做响应式处理
  17. (2).如需给后添加的属性做响应式,请使用如下API:
  18. Vue.set(target,propertyName/index,value) 或
  19. vm.$set(target,propertyName/index,value)
  20. 3. 如何监测数组中的数据?
  21. 通过包裹数组更新元素的方法实现,本质就是做了两件事:
  22. (1).调用原生对应的方法对数组进行更新。
  23. (2).重新解析模板,进而更新页面。
  24. 4.在Vue修改数组中的某个元素一定要用如下方法:
  25. 1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
  26. 2.Vue.set() 或 vm.$set()
  27. 特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!
  28. -->
  29. <!-- 准备好一个容器-->
  30. <div id="root">
  31. <h1>学生信息</h1>
  32. <button @click="student.age++">年龄+1岁</button> <br/>
  33. <button @click="addSex">添加性别属性,默认值:男</button> <br/>
  34. <button @click="student.sex = '未知' ">修改性别</button> <br/>
  35. <button @click="addFriend">在列表首位添加一个朋友</button> <br/>
  36. <button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button> <br/>
  37. <button @click="addHobby">添加一个爱好</button> <br/>
  38. <button @click="updateHobby">修改第一个爱好为:开车</button> <br/>
  39. <button @click="removeSmoke">过滤掉爱好中的抽烟</button> <br/>
  40. <h3>姓名:{{student.name}}</h3>
  41. <h3>年龄:{{student.age}}</h3>
  42. <h3 v-if="student.sex">性别:{{student.sex}}</h3>
  43. <h3>爱好:</h3>
  44. <ul>
  45. <li v-for="(h,index) in student.hobby" :key="index">
  46. {{h}}
  47. </li>
  48. </ul>
  49. <h3>朋友们:</h3>
  50. <ul>
  51. <li v-for="(f,index) in student.friends" :key="index">
  52. {{f.name}}--{{f.age}}
  53. </li>
  54. </ul>
  55. </div>
  56. </body>
  57. <script type="text/javascript">
  58. Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
  59. const vm = new Vue({
  60. el:'#root',
  61. data:{
  62. student:{
  63. name:'tom',
  64. age:18,
  65. hobby:['抽烟','喝酒','烫头'],
  66. friends:[
  67. {name:'jerry',age:35},
  68. {name:'tony',age:36}
  69. ]
  70. }
  71. },
  72. methods: {
  73. addSex(){
  74. //this.student.sex = '男' //错误
  75. // Vue.set(this.student,'sex','男')
  76. this.$set(this.student,'sex','男')
  77. },
  78. addFriend(){
  79. this.student.friends.unshift({name:'jack',age:70})
  80. },
  81. updateFirstFriendName(){
  82. this.student.friends[0].name = '张三'
  83. },
  84. addHobby(){
  85. this.student.hobby.push('学习')
  86. },
  87. updateHobby(){
  88. // this.student.hobby[0]='开车'//错误
  89. // this.student.hobby.splice(0,1,'开车')
  90. // Vue.set(this.student.hobby,0,'开车')
  91. this.$set(this.student.hobby,0,'开车')
  92. },
  93. removeSmoke(){
  94. this.student.hobby = this.student.hobby.filter((h)=>{
  95. return h !== '抽烟'
  96. })
  97. }
  98. }
  99. })
  100. </script>
  101. </html>

代码 - 实现数据监测(Observer类的实现)

image.png
image.png
image.png