mh-two-thousand-and-two
2024-04-12 3d2ec2fd0578d3ba0a414b0cc4e4a2ae60878596
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import Vue from 'vue'
 
import {
  VD_SYNC,
  PAGE_CREATE,
  MOUNTED_DATA,
  UPDATED_DATA,
  PAGE_CREATED,
  VD_SYNC_CALLBACK
} from '../../../constants'
 
import {
  ON_PAGE_CREATE
} from '../../constants'
 
import {
  VDomSync
} from './vdom-sync'
 
import {
  setCurrentPage
} from '../page'
 
import {
  getPageVueComponent
} from '../../../page-factory'
 
export let vd
 
let PageVueComponent
 
const handleData = {
  [PAGE_CREATE]: function onPageCreate (data) {
    const [pageId, pagePath, pageOptions] = data
    document.title = `${pagePath}[${pageId}]`
 
    // 设置当前页面伪对象,方便其他地方使用 getCurrentPages 获取当前页面 id,route
    setCurrentPage(pageId, pagePath)
    // 通知页面创建,根据当前页面配置信息,初始化部分事件
    UniViewJSBridge.subscribeHandler(ON_PAGE_CREATE, pageOptions, pageId)
    // 初始化当前页面 VueComponent(生成页面样式代码)
    PageVueComponent = getPageVueComponent(pagePath)
    // 生成当前页面 vd
    vd = new VDomSync(pageId, {
      version: pageOptions.version
    })
  },
  [MOUNTED_DATA]: function onMounted (data) {
    vd.addVData.apply(vd, data)
  },
  [UPDATED_DATA]: function onUpdated (data) {
    vd.updateVData.apply(vd, data)
  },
  [PAGE_CREATED]: function onPageCreated (data) {
    const [pageId, pagePath, pageQuery] = data
    const page = getCurrentPages()[0]
    page.options = pageQuery || {}
    page.$vm = new PageVueComponent({
      mpType: 'page',
      pageId,
      pagePath,
      pageQuery
    }).$mount('#app')
  }
}
 
function broadcast (vm, componentName, eventName, ...params) {
  vm.$children.forEach(child => {
    const name = child.$options.name && child.$options.name.replace(/^VUni/, '')
    if (~componentName.indexOf(name)) {
      child.$emit(eventName, ...params)
    }
    broadcast(child, componentName, eventName, ...params)
  })
}
 
const NATIVE_COMPONENTS = ['Camera', 'LivePlayer', 'LivePusher', 'Map', 'Video', 'CoverView', 'CoverImage', 'Ad']
 
function updateView () {
  const pages = getCurrentPages()
  const pageVm = pages[0] && pages[0].$vm
  pageVm && broadcast(
    pageVm,
    NATIVE_COMPONENTS,
    'uni-view-update'
  )
}
 
window.addEventListener('resize', () => {
  updateView()
})
 
window.addEventListener('updateview', updateView)
 
function vdSync ({
  data,
  options
}) {
  let isVdCallback = true
  data.forEach(data => {
    if (data[0] === PAGE_CREATE) { // 页面创建无需触发 callback
      isVdCallback = false
    }
    handleData[data[0]](data[1])
  })
  vd.flush()
  Vue.nextTick(() => {
    // 清空本次 addBatchData
    vd.clearAddBatchVData()
    updateView()
    isVdCallback && UniViewJSBridge.publishHandler(VD_SYNC_CALLBACK)
  })
}
 
function getData (id, name) {
  try {
    const data = this.$r[id][name]
    if (name === 'is' && typeof data === 'object') {
      const components = this.$options.components || {}
      for (const key in components) {
        const value = components[key]
        const options = typeof value === 'function' ? value.options : value
        if (options.__file === data.__file) {
          return options
        }
      }
    }
    return data
  } catch (e) {
    // console.error(this.$options.__file + `:[${this._$id}]$r[${id}][${name}] is undefined`)
  }
}
/**
 * wxs change:prop
 * @param {Object} id
 * @param {Object} name
 */
function getChangeData (id, name) {
  try {
    const value = this.$r[id][name]
    const wxsPropName = name.replace('change:', '')
    this[wxsPropName] = value
    this.$set(this.wxsProps, wxsPropName, value)
    return value
  } catch (e) {
    // console.error(this.$options.__file + `:[${this._$id}]$r[${id}][${name}] is undefined`)
  }
}
 
export function initData (Vue) {
  Vue.prototype._$g = getData
  Vue.prototype._$gc = getChangeData
 
  UniViewJSBridge.subscribe(VD_SYNC, vdSync)
 
  Object.defineProperty(Vue.prototype, '_$vd', {
    get () {
      return !this.$options.isReserved && vd
    }
  })
 
  Vue.mixin({
    beforeCreate () {
      if (this.$options.mpType) {
        this.mpType = this.$options.mpType
      }
      if (this._$vd) {
        this._$vd.initVm(this)
      }
    }
  })
}