打赏

vue 数组 新增元素 响应式原理 7种方法

1、问题

思考一个问题,以下代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>vue 数组 响应式原理</title>
    </head>
    <body>
        <div id="app">
            <div v-for="item in list">
                {{ item }}
            </div>
        </div>

        <script src="https://cdn.bootcss.com/vue/2.5.17/vue.min.js"></script>
        <script type="text/javascript">
            var app = new Vue({
                el: '#app',
                data: {
                    list: [1, 2, 3]
                }
            })
        </script>

    </body>
</html>

当我们在控制台输入:app.list[0] = 100时,vue会监测到变化吗?

 app.push(100)呢? 

 

 引申出的问题就是:

vue对数组新增的元素,包括push、unshift和splice(插入)的元素是怎么做到响应式的呢

 

2、Vue对新增的数组元素响应式原理

(1)核心代码(observer/array.js)

/*
 * not type checking this file because flow doesn't play well with
 * dynamically accessing methods on Array prototype
 */

import { def } from '../util/index'

const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)

const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]

/**
 * Intercept mutating methods and emit events
 */
methodsToPatch.forEach(function (method) {
  // cache original method
  const original = arrayProto[method]
  def(arrayMethods, method, function mutator (...args) {
    const result = original.apply(this, args)
    const ob = this.__ob__
    let inserted
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    if (inserted) ob.observeArray(inserted)
    // notify change
    ob.dep.notify()
    return result
  })
})

在这个函数中使用到了def函数,def函数的定义是(util/lang.js):

export function def (obj: Object, key: string, val: any, enumerable?: boolean) {
  Object.defineProperty(obj, key, {
    value: val,
    enumerable: !!enumerable,
    writable: true,
    configurable: true
  })
}

即对元素的属性重新定义,尤其是value的获取。

 

回到observer/array.js,除了正常返回push、unshift和splice(插入)函数执行的result结果外,还通知了变化!ob.dep.notify! 所以对新增的数组元素实现了响应式的变化。

 

留一个问题:

switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }

为什么push、unshift和splice处理的参数不一样? 

查一下splice的参数有哪些吧。

 

posted @ 2018-11-20 16:46  孟繁贵  阅读(14053)  评论(0编辑  收藏  举报
TOP