data.js 3.7 KB
Newer Older
fxy060608's avatar
init v3  
fxy060608 已提交
1 2 3 4 5
import {
  guid,
  hasOwn
} from 'uni-shared'

fxy060608's avatar
fxy060608 已提交
6 7 8
import {
  MOUNTED_DATA,
  UPDATED_DATA
fxy060608's avatar
fxy060608 已提交
9 10
} from '../../../constants'

fxy060608's avatar
init v3  
fxy060608 已提交
11 12 13 14 15
import {
  VDomSync
} from './vdom-sync'

import {
fxy060608's avatar
fxy060608 已提交
16
  V_IF,
17
  V_FOR,
fxy060608's avatar
fxy060608 已提交
18
  V_SHOW,
fxy060608's avatar
fxy060608 已提交
19 20 21 22
  V_ELSE_IF,
  B_CLASS,
  B_STYLE
} from '../../constants'
fxy060608's avatar
init v3  
fxy060608 已提交
23 24 25 26 27

import {
  diff
} from './diff'

fxy060608's avatar
fxy060608 已提交
28
export function initData (Vue) {
fxy060608's avatar
init v3  
fxy060608 已提交
29 30
  Vue.prototype._$s = setData

fxy060608's avatar
fxy060608 已提交
31
  Vue.prototype._$setData = function setData (type, data) {
fxy060608's avatar
init v3  
fxy060608 已提交
32
    this._$vd.push(type, this._$id, data)
fxy060608's avatar
fxy060608 已提交
33 34
  }

fxy060608's avatar
fxy060608 已提交
35
  Vue.prototype._$mounted = function mounted () {
fxy060608's avatar
fxy060608 已提交
36 37 38 39 40 41 42 43 44 45 46
    if (!this._$vd) {
      return
    }
    diff(this._$newData, this._$data, this._$vdMountedData)
    this._$data = JSON.parse(JSON.stringify(this._$newData))
    if (this.mpType === 'page') {
      // 页面 mounted 之后,第一次同步数据
      this._$vd.flush()
    }
  }

fxy060608's avatar
fxy060608 已提交
47
  Vue.prototype._$updated = function updated () {
fxy060608's avatar
fxy060608 已提交
48 49 50
    if (!this._$vd) {
      return
    }
fxy060608's avatar
fxy060608 已提交
51 52 53 54
    // TODO 自定义组件中的 slot 数据采集是在组件内部,导致所在 context 中无法获取到差量数据
    // 如何保证每个 vm 数据有变动,就加入 diff 中呢?
    // 每次变化,可能触发多次 beforeUpdate,updated
    // 子组件 updated 时,可能会增加父组件的 diffData,如 slot 等情况
fxy060608's avatar
fxy060608 已提交
55 56
    diff(this._$newData, this._$data, this._$vdUpdatedData)
    this._$data = JSON.parse(JSON.stringify(this._$newData))
fxy060608's avatar
fxy060608 已提交
57 58 59 60
    // setTimeout 一下再 nextTick( 直接 nextTick 的话,会紧接着该 updated 做 flush,导致父组件 updated 数据被丢弃)
    this._$vd.initialized && setTimeout(() => {
      this.$nextTick(this._$vd.flush.bind(this._$vd))
    }, 0)
fxy060608's avatar
init v3  
fxy060608 已提交
61 62 63
  }

  Object.defineProperty(Vue.prototype, '_$vd', {
fxy060608's avatar
fxy060608 已提交
64
    get () {
fxy060608's avatar
init v3  
fxy060608 已提交
65 66 67 68 69
      return this.$root._$vdomSync
    }
  })

  Vue.mixin({
fxy060608's avatar
fxy060608 已提交
70
    beforeCreate () {
fxy060608's avatar
init v3  
fxy060608 已提交
71 72 73 74 75 76 77
      if (this.$options.mpType) {
        this.mpType = this.$options.mpType
      }
      if (this.mpType === 'app') {
        return
      }
      if (this.mpType === 'page') {
78
        this._$vdomSync = new VDomSync(this.$options.pageId, this.$options.pagePath, this)
fxy060608's avatar
init v3  
fxy060608 已提交
79 80 81 82
      }
      if (this._$vd) {
        this._$id = guid()
        this._$vd.addVm(this)
fxy060608's avatar
fxy060608 已提交
83 84
        this._$vdMountedData = Object.create(null)
        this._$setData(MOUNTED_DATA, this._$vdMountedData)
fxy060608's avatar
init v3  
fxy060608 已提交
85 86 87 88
        this._$data = Object.create(null)
        this._$newData = Object.create(null)
      }
    },
fxy060608's avatar
fxy060608 已提交
89
    beforeUpdate () {
fxy060608's avatar
init v3  
fxy060608 已提交
90 91 92
      if (!this._$vd) {
        return
      }
fxy060608's avatar
fxy060608 已提交
93 94
      this._$vdUpdatedData = Object.create(null)
      this._$setData(UPDATED_DATA, this._$vdUpdatedData)
fxy060608's avatar
init v3  
fxy060608 已提交
95 96
      this._$newData = Object.create(null)
    },
fxy060608's avatar
fxy060608 已提交
97
    beforeDestroy () {
fxy060608's avatar
init v3  
fxy060608 已提交
98 99 100 101
      if (!this._$vd) {
        return
      }
      this._$vd.removeVm(this)
fxy060608's avatar
fxy060608 已提交
102
      this._$vdomSync && this._$vdomSync.destroy()
fxy060608's avatar
init v3  
fxy060608 已提交
103 104 105 106
    }
  })
}

fxy060608's avatar
fxy060608 已提交
107
function setData (id, name, value) {
fxy060608's avatar
fxy060608 已提交
108 109 110 111 112 113 114
  switch (name) {
    case B_CLASS:
      value = this._$stringifyClass(value)
      break
    case B_STYLE:
      value = this._$normalizeStyleBinding(value)
      break
115
    case V_IF:
fxy060608's avatar
fxy060608 已提交
116
    case V_SHOW:
fxy060608's avatar
fxy060608 已提交
117
    case V_ELSE_IF:
fxy060608's avatar
fxy060608 已提交
118
      value = value ? 1 : 0
fxy060608's avatar
fxy060608 已提交
119 120 121
      break
    case V_FOR:
      return setForData.call(this, id, value)
fxy060608's avatar
init v3  
fxy060608 已提交
122 123
  }

fxy060608's avatar
fxy060608 已提交
124
  return ((this._$newData[id] || (this._$newData[id] = {}))[name] = value)
fxy060608's avatar
init v3  
fxy060608 已提交
125 126
}

fxy060608's avatar
fxy060608 已提交
127
function setForData (id, value) {
fxy060608's avatar
fxy060608 已提交
128
  const diffData = this._$newData[id] || (this._$newData[id] = {})
fxy060608's avatar
fxy060608 已提交
129
  const vForData = diffData[V_FOR] || (diffData[V_FOR] = [])
fxy060608's avatar
fxy060608 已提交
130 131 132 133 134

  if (value.forItems) {
    return value.forItems
  }

fxy060608's avatar
init v3  
fxy060608 已提交
135 136 137 138 139 140 141 142 143 144 145 146
  const {
    forIndex,
    key
  } = value

  if (!hasOwn(value, 'keyIndex')) {
    vForData[forIndex] = key
  } else {
    (vForData[forIndex] || (vForData[forIndex] = {}))['k' + value.keyIndex] = key
  }
  return key
}