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

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

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

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

import {
  generateId
} from '../../../helpers/util'
fxy060608's avatar
init v3  
fxy060608 已提交
29 30 31 32 33

import {
  diff
} from './diff'

fxy060608's avatar
fxy060608 已提交
34 35
import parseComponentCreateOptions from './parse-component-create-options'

fxy060608's avatar
fxy060608 已提交
36
export function initData (Vue) {
fxy060608's avatar
init v3  
fxy060608 已提交
37 38
  Vue.prototype._$s = setData

fxy060608's avatar
fxy060608 已提交
39
  Vue.prototype._$setData = function setData (type, data) {
fxy060608's avatar
fxy060608 已提交
40 41 42 43 44 45
    this._$vd.push(
      type,
      this._$id,
      data,
      type === MOUNTED_DATA && parseComponentCreateOptions(this)
    )
fxy060608's avatar
fxy060608 已提交
46 47
  }

fxy060608's avatar
fxy060608 已提交
48
  Vue.prototype._$mounted = function mounted () {
fxy060608's avatar
fxy060608 已提交
49 50 51 52 53 54 55 56 57 58 59
    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 已提交
60
  Vue.prototype._$updated = function updated () {
fxy060608's avatar
fxy060608 已提交
61 62 63
    if (!this._$vd) {
      return
    }
fxy060608's avatar
fxy060608 已提交
64

fxy060608's avatar
fxy060608 已提交
65 66
    diff(this._$newData, this._$data, this._$vdUpdatedData)
    this._$data = JSON.parse(JSON.stringify(this._$newData))
fxy060608's avatar
fxy060608 已提交
67 68 69 70
    // 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 已提交
71 72 73
  }

  Object.defineProperty(Vue.prototype, '_$vd', {
fxy060608's avatar
fxy060608 已提交
74
    get () {
fxy060608's avatar
init v3  
fxy060608 已提交
75 76 77 78 79
      return this.$root._$vdomSync
    }
  })

  Vue.mixin({
fxy060608's avatar
fxy060608 已提交
80
    beforeCreate () {
fxy060608's avatar
init v3  
fxy060608 已提交
81 82 83 84 85 86 87
      if (this.$options.mpType) {
        this.mpType = this.$options.mpType
      }
      if (this.mpType === 'app') {
        return
      }
      if (this.mpType === 'page') {
fxy060608's avatar
fxy060608 已提交
88
        this._$vdomSync = new VDomSync(this.$options.pageId, this.$options.pagePath, this.$options.pageQuery, this)
fxy060608's avatar
init v3  
fxy060608 已提交
89 90
      }
      if (this._$vd) {
fxy060608's avatar
fxy060608 已提交
91
        this._$id = generateId(this, this.$parent)
fxy060608's avatar
init v3  
fxy060608 已提交
92
        this._$vd.addVm(this)
fxy060608's avatar
fxy060608 已提交
93 94
        this._$vdMountedData = Object.create(null)
        this._$setData(MOUNTED_DATA, this._$vdMountedData)
fxy060608's avatar
init v3  
fxy060608 已提交
95 96 97 98
        this._$data = Object.create(null)
        this._$newData = Object.create(null)
      }
    },
fxy060608's avatar
fxy060608 已提交
99
    beforeUpdate () {
fxy060608's avatar
init v3  
fxy060608 已提交
100 101 102
      if (!this._$vd) {
        return
      }
fxy060608's avatar
fxy060608 已提交
103 104 105 106 107 108 109 110 111 112 113 114
      // 当已存在 _$vdMountedData 时,使用重置后的 _$vdMountedData
      const mountedData = this._$vd.find(MOUNTED_DATA, this._$id)
      if (mountedData) {
        this._$data = Object.create(null) // 清空已有数据
        this._$vdUpdatedData = mountedData[1][1] = Object.create(null)
        if (process.env.NODE_ENV !== 'production') {
          console.log('updated=>mounted:' + this._$id)
        }
      } else {
        this._$vdUpdatedData = Object.create(null)
        this._$setData(UPDATED_DATA, this._$vdUpdatedData)
      }
fxy060608's avatar
init v3  
fxy060608 已提交
115 116
      this._$newData = Object.create(null)
    },
fxy060608's avatar
fxy060608 已提交
117
    beforeDestroy () {
fxy060608's avatar
init v3  
fxy060608 已提交
118 119 120 121
      if (!this._$vd) {
        return
      }
      this._$vd.removeVm(this)
fxy060608's avatar
fxy060608 已提交
122
      this._$vdomSync && this._$vdomSync.destroy()
fxy060608's avatar
init v3  
fxy060608 已提交
123 124 125 126
    }
  })
}

fxy060608's avatar
fxy060608 已提交
127 128 129 130 131 132 133 134 135 136 137 138
function parseExternalClasses (clazz, vm) {
  const mpOptions = vm.$options.mpOptions
  if (mpOptions && Array.isArray(mpOptions.externalClasses)) {
    mpOptions.externalClasses.forEach(externalClass => {
      // 简单替换 externalClass
      const externalClassValue = vm[camelize(externalClass)]
      externalClassValue && (clazz = clazz.replace(externalClass, externalClassValue))
    })
  }
  return clazz
}

fxy060608's avatar
fxy060608 已提交
139
function setData (id, name, value) {
fxy060608's avatar
fxy060608 已提交
140 141
  switch (name) {
    case B_CLASS:
fxy060608's avatar
fxy060608 已提交
142 143 144 145
      value = parseExternalClasses(this._$stringifyClass(value), this)
      break
    case S_CLASS:
      value = parseExternalClasses(value, this)
fxy060608's avatar
fxy060608 已提交
146 147 148 149
      break
    case B_STYLE:
      value = this._$normalizeStyleBinding(value)
      break
150
    case V_IF:
fxy060608's avatar
fxy060608 已提交
151
    case V_SHOW:
fxy060608's avatar
fxy060608 已提交
152
    case V_ELSE_IF:
fxy060608's avatar
fxy060608 已提交
153
      value = value ? 1 : 0
fxy060608's avatar
fxy060608 已提交
154 155 156
      break
    case V_FOR:
      return setForData.call(this, id, value)
fxy060608's avatar
init v3  
fxy060608 已提交
157
  }
fxy060608's avatar
fxy060608 已提交
158 159 160 161 162 163
  // TODO 暂时先传递 dataset 至 view 层(理论上不需要)
  if (name.indexOf('a-data-') === 0) {
    try {
      value = JSON.stringify(value)
    } catch (e) {}
  }
fxy060608's avatar
init v3  
fxy060608 已提交
164

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

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
function fillVForData (forItems, vForData) {
  let i, l
  if (Array.isArray(forItems) || typeof forItems === 'string') {
    for (i = 0, l = forItems.length; i < l; i++) {
      vForData[i] = i
    }
  } else if (typeof forItems === 'number') {
    for (i = 0; i < forItems; i++) {
      vForData[i] = i
    }
  } else if (isObject(forItems)) {
    for (i = 0, l = Object.keys(forItems).length; i < l; i++) {
      vForData[i] = i
    }
  }
}

fxy060608's avatar
fxy060608 已提交
185
function setForData (id, value) {
fxy060608's avatar
fxy060608 已提交
186
  const diffData = this._$newData[id] || (this._$newData[id] = {})
fxy060608's avatar
fxy060608 已提交
187
  const vForData = diffData[V_FOR] || (diffData[V_FOR] = [])
fxy060608's avatar
fxy060608 已提交
188 189

  if (value.forItems) {
190
    value.fill && fillVForData(value.forItems, vForData)
fxy060608's avatar
fxy060608 已提交
191 192 193
    return value.forItems
  }

fxy060608's avatar
init v3  
fxy060608 已提交
194 195 196 197 198 199 200 201 202 203 204
  const {
    forIndex,
    key
  } = value

  if (!hasOwn(value, 'keyIndex')) {
    vForData[forIndex] = key
  } else {
    (vForData[forIndex] || (vForData[forIndex] = {}))['k' + value.keyIndex] = key
  }
  return key
fxy060608's avatar
fxy060608 已提交
205
}