| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- import Watcher from '../../observer/watcher'
- import Dep from '../../observer/dep'
- import { observe } from '../../observer/index'
- import {
- warn,
- hasOwn,
- isReserved,
- isPlainObject,
- bind
- } from '../../util/index'
- export default function (Vue) {
- /**
- * Accessor for `$data` property, since setting $data
- * requires observing the new object and updating
- * proxied properties.
- */
- Object.defineProperty(Vue.prototype, '$data', {
- get () {
- return this._data
- },
- set (newData) {
- if (newData !== this._data) {
- this._setData(newData)
- }
- }
- })
- /**
- * Setup the scope of an instance, which contains:
- * - observed data
- * - computed properties
- * - user methods
- * - meta properties
- */
- Vue.prototype._initState = function () {
- this._initMethods()
- this._initData()
- this._initComputed()
- }
- /**
- * Initialize the data.
- */
- Vue.prototype._initData = function () {
- var data = this.$options.data
- data = this._data = typeof data === 'function'
- ? data()
- : data || {}
- if (!isPlainObject(data)) {
- data = {}
- process.env.NODE_ENV !== 'production' && warn(
- 'data functions should return an object.',
- this
- )
- }
- // proxy data on instance
- var keys = Object.keys(data)
- var i = keys.length
- while (i--) {
- this._proxy(keys[i])
- }
- // observe data
- observe(data, this)
- }
- /**
- * Swap the instance's $data. Called in $data's setter.
- *
- * @param {Object} newData
- */
- Vue.prototype._setData = function (newData) {
- newData = newData || {}
- var oldData = this._data
- this._data = newData
- var keys, key, i
- // unproxy keys not present in new data
- keys = Object.keys(oldData)
- i = keys.length
- while (i--) {
- key = keys[i]
- if (!(key in newData)) {
- this._unproxy(key)
- }
- }
- // proxy keys not already proxied,
- // and trigger change for changed values
- keys = Object.keys(newData)
- i = keys.length
- while (i--) {
- key = keys[i]
- if (!hasOwn(this, key)) {
- // new property
- this._proxy(key)
- }
- }
- oldData.__ob__.removeVm(this)
- observe(newData, this)
- this._digest()
- }
- /**
- * Proxy a property, so that
- * vm.prop === vm._data.prop
- *
- * @param {String} key
- */
- Vue.prototype._proxy = function (key) {
- if (!isReserved(key)) {
- // need to store ref to self here
- // because these getter/setters might
- // be called by child scopes via
- // prototype inheritance.
- var self = this
- Object.defineProperty(self, key, {
- configurable: true,
- enumerable: true,
- get: function proxyGetter () {
- return self._data[key]
- },
- set: function proxySetter (val) {
- self._data[key] = val
- }
- })
- }
- }
- /**
- * Unproxy a property.
- *
- * @param {String} key
- */
- Vue.prototype._unproxy = function (key) {
- if (!isReserved(key)) {
- delete this[key]
- }
- }
- /**
- * Setup computed properties. They are essentially
- * special getter/setters
- */
- function noop () {}
- Vue.prototype._initComputed = function () {
- var computed = this.$options.computed
- if (computed) {
- for (var key in computed) {
- var userDef = computed[key]
- var def = {
- enumerable: true,
- configurable: true
- }
- if (typeof userDef === 'function') {
- def.get = makeComputedGetter(userDef, this)
- def.set = noop
- } else {
- def.get = userDef.get
- ? userDef.cache !== false
- ? makeComputedGetter(userDef.get, this)
- : bind(userDef.get, this)
- : noop
- def.set = userDef.set
- ? bind(userDef.set, this)
- : noop
- }
- Object.defineProperty(this, key, def)
- }
- }
- }
- function makeComputedGetter (getter, owner) {
- var watcher = new Watcher(owner, getter, null, {
- lazy: true
- })
- return function computedGetter () {
- if (watcher.dirty) {
- watcher.evaluate()
- }
- if (Dep.target) {
- watcher.depend()
- }
- return watcher.value
- }
- }
- /**
- * Setup instance methods. Methods must be bound to the
- * instance since they might be passed down as a prop to
- * child components.
- */
- Vue.prototype._initMethods = function () {
- var methods = this.$options.methods
- if (methods) {
- for (var key in methods) {
- this[key] = bind(methods[key], this)
- }
- }
- }
- }
|