You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
253 lines
5.9 KiB
253 lines
5.9 KiB
|
3 years ago
|
import {
|
||
|
|
isFn,
|
||
|
|
noop
|
||
|
|
} from 'uni-shared'
|
||
|
|
|
||
|
|
import {
|
||
|
|
wrapperMPEvent
|
||
|
|
} from 'uni-helpers/patch'
|
||
|
|
|
||
|
|
import {
|
||
|
|
VD_SYNC,
|
||
|
|
UI_EVENT,
|
||
|
|
PAGE_CREATE,
|
||
|
|
PAGE_CREATED,
|
||
|
|
MOUNTED_DATA,
|
||
|
|
UPDATED_DATA
|
||
|
|
} from '../../../constants'
|
||
|
|
|
||
|
|
import {
|
||
|
|
removeVdSync,
|
||
|
|
registerVdSync
|
||
|
|
} from '../subscribe-handlers/on-vd-sync'
|
||
|
|
|
||
|
|
import {
|
||
|
|
vdSyncCallbacks
|
||
|
|
} from '../subscribe-handlers/on-vd-sync-callback'
|
||
|
|
|
||
|
|
import {
|
||
|
|
hookKeyboardEvent
|
||
|
|
} from './keyboard'
|
||
|
|
|
||
|
|
import parseComponentCreateOptions from './parse-component-create-options'
|
||
|
|
|
||
|
|
// TODO 临时通过序列化,反序列化传递dataset,后续可以全部保留在service,不做传递
|
||
|
|
function parseDataset (dataset) {
|
||
|
|
const ret = Object.create(null)
|
||
|
|
Object.keys(dataset).forEach(name => {
|
||
|
|
try {
|
||
|
|
ret[name] = JSON.parse(dataset[name])
|
||
|
|
} catch (e) { // dataset 存在两种,一种是被JSON.stringify的,一种是原始的
|
||
|
|
ret[name] = dataset[name]
|
||
|
|
}
|
||
|
|
})
|
||
|
|
return ret
|
||
|
|
}
|
||
|
|
|
||
|
|
function parseTargets (event) {
|
||
|
|
const targetDataset = event.target && event.target.dataset
|
||
|
|
if (targetDataset) {
|
||
|
|
event.target.dataset = parseDataset(targetDataset)
|
||
|
|
}
|
||
|
|
const currentTargetDataset = event.currentTarget && event.currentTarget.dataset
|
||
|
|
if (currentTargetDataset) {
|
||
|
|
event.currentTarget.dataset = parseDataset(currentTargetDataset)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function wrapperEvent (event) {
|
||
|
|
parseTargets(event)
|
||
|
|
event.preventDefault = noop
|
||
|
|
event.stopPropagation = noop
|
||
|
|
return wrapperMPEvent(event)
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleVdData = {
|
||
|
|
[UI_EVENT]: function onUIEvent (vdBatchEvent, vd) {
|
||
|
|
vdBatchEvent.forEach(([cid, nid, event]) => {
|
||
|
|
nid = String(nid)
|
||
|
|
const target = vd.elements.find(target => target.cid === cid && target.nid === nid)
|
||
|
|
if (!target) {
|
||
|
|
if (process.env.NODE_ENV !== 'production') {
|
||
|
|
console.error(`event handler[${cid}][${nid}] not found`)
|
||
|
|
}
|
||
|
|
return
|
||
|
|
}
|
||
|
|
const type = event.type
|
||
|
|
const mpEvent = wrapperEvent(event)
|
||
|
|
if (type === 'focus' || type === 'blur') {
|
||
|
|
hookKeyboardEvent(mpEvent, event => {
|
||
|
|
target.dispatchEvent(type, event)
|
||
|
|
})
|
||
|
|
} else {
|
||
|
|
target.dispatchEvent(type, mpEvent)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function onVdSync (vdBatchData, vd) {
|
||
|
|
vdBatchData.forEach(([type, vdData]) => {
|
||
|
|
handleVdData[type](vdData, vd)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
export class VDomSync {
|
||
|
|
constructor (pageId, pagePath, pageQuery, pageVm) {
|
||
|
|
this.pageId = pageId
|
||
|
|
this.pagePath = pagePath
|
||
|
|
this.pageQuery = pageQuery
|
||
|
|
this.pageVm = pageVm
|
||
|
|
this.batchData = []
|
||
|
|
this.vms = Object.create(null)
|
||
|
|
this.initialized = false
|
||
|
|
|
||
|
|
this.pageCreateData = false
|
||
|
|
|
||
|
|
this.elements = [] // 目前仅存储事件 element
|
||
|
|
|
||
|
|
this._init()
|
||
|
|
}
|
||
|
|
|
||
|
|
_init () {
|
||
|
|
registerVdSync(this.pageId, (vdBatchData) => {
|
||
|
|
onVdSync(vdBatchData, this)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
addMountedVm (vm) {
|
||
|
|
vm._$mounted() // 触发vd数据同步
|
||
|
|
this.addVdSyncCallback(function mounted () {
|
||
|
|
vm.__call_hook('mounted')
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
addUpdatedVm (vm) {
|
||
|
|
vm._$updated() // 触发vd数据同步
|
||
|
|
this.addVdSyncCallback(function mounted () {
|
||
|
|
vm.__call_hook('updated')
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
addVdSyncCallback (callback) {
|
||
|
|
isFn(callback) && vdSyncCallbacks.push(callback)
|
||
|
|
}
|
||
|
|
|
||
|
|
getVm (id) {
|
||
|
|
return this.vms[id]
|
||
|
|
}
|
||
|
|
|
||
|
|
addVm (vm) {
|
||
|
|
this.vms[vm._$id] = vm
|
||
|
|
}
|
||
|
|
|
||
|
|
removeVm (vm) {
|
||
|
|
const cid = vm._$id
|
||
|
|
if (vm === this.vms[cid]) { // 仅相同vm的才移除,否则保留
|
||
|
|
// 目前同一位置的vm,cid均一样
|
||
|
|
// 移除尚未同步的data
|
||
|
|
this.batchData = this.batchData.filter(data => data[1][0] !== cid)
|
||
|
|
delete this.vms[cid]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
addElement (elm) {
|
||
|
|
this.elements.indexOf(elm) === -1 && this.elements.push(elm)
|
||
|
|
}
|
||
|
|
|
||
|
|
removeElement (elm) {
|
||
|
|
const elmIndex = this.elements.indexOf(elm)
|
||
|
|
if (elmIndex === -1) {
|
||
|
|
if (process.env.NODE_ENV !== 'production') {
|
||
|
|
console.error(`removeElement[${elm.cid}][${elm.nid}] not found`)
|
||
|
|
}
|
||
|
|
return
|
||
|
|
}
|
||
|
|
this.elements.splice(elmIndex, 1)
|
||
|
|
}
|
||
|
|
|
||
|
|
push (type, cid, data, options) {
|
||
|
|
const typeData = [cid, data]
|
||
|
|
if (options) {
|
||
|
|
typeData.push(options)
|
||
|
|
}
|
||
|
|
this.batchData.push([type, typeData])
|
||
|
|
}
|
||
|
|
|
||
|
|
find (type, cid) {
|
||
|
|
return this.batchData.find(data => data[0] === type && data[1][0] === cid)
|
||
|
|
}
|
||
|
|
|
||
|
|
sendPageCreate (data) {
|
||
|
|
this.pageCreateData = data
|
||
|
|
UniServiceJSBridge.publishHandler(VD_SYNC, {
|
||
|
|
data: [
|
||
|
|
[PAGE_CREATE, data]
|
||
|
|
],
|
||
|
|
options: {
|
||
|
|
timestamp: Date.now()
|
||
|
|
}
|
||
|
|
}, [this.pageId])
|
||
|
|
}
|
||
|
|
|
||
|
|
flush () {
|
||
|
|
if (!this.initialized) {
|
||
|
|
this.initialized = true
|
||
|
|
this.batchData.push([PAGE_CREATED, [this.pageId, this.pagePath, this.pageQuery]])
|
||
|
|
}
|
||
|
|
const batchData = this.batchData.filter(data => {
|
||
|
|
if (data[0] === UPDATED_DATA && !Object.keys(data[1][1]).length) {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
return true
|
||
|
|
})
|
||
|
|
this.batchData.length = 0
|
||
|
|
if (batchData.length) {
|
||
|
|
UniServiceJSBridge.publishHandler(VD_SYNC, {
|
||
|
|
data: batchData,
|
||
|
|
options: {
|
||
|
|
timestamp: Date.now()
|
||
|
|
}
|
||
|
|
}, [this.pageId])
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
restorePageCreate () {
|
||
|
|
this.batchData.push([PAGE_CREATE, this.pageCreateData])
|
||
|
|
}
|
||
|
|
|
||
|
|
restoreMountedData () {
|
||
|
|
const addMountedData = (vm) => {
|
||
|
|
if (vm._$id) {
|
||
|
|
this.push(MOUNTED_DATA, vm._$id, vm._$data, parseComponentCreateOptions(vm))
|
||
|
|
}
|
||
|
|
// TODO vue 中 $children 顺序不可靠,可能存在恢复误差
|
||
|
|
vm.$children.forEach(childVm => addMountedData(childVm))
|
||
|
|
}
|
||
|
|
addMountedData(this.pageVm)
|
||
|
|
}
|
||
|
|
|
||
|
|
restorePageCreated () {
|
||
|
|
this.batchData.push([PAGE_CREATED, [this.pageId, this.pagePath, this.pageQuery]])
|
||
|
|
}
|
||
|
|
|
||
|
|
restore () {
|
||
|
|
this.initialized = true
|
||
|
|
this.batchData.length = 0
|
||
|
|
|
||
|
|
this.restorePageCreate()
|
||
|
|
this.restoreMountedData()
|
||
|
|
this.restorePageCreated()
|
||
|
|
|
||
|
|
this.flush()
|
||
|
|
}
|
||
|
|
|
||
|
|
destroy () {
|
||
|
|
this.batchData.length = 0
|
||
|
|
this.vms = Object.create(null)
|
||
|
|
this.initialized = false
|
||
|
|
this.elements.length = 0
|
||
|
|
removeVdSync(this.pageId)
|
||
|
|
}
|
||
|
|
}
|