Page.ts 8.0 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1
import { queuePostFlushCb } from 'vue'
fxy060608's avatar
fxy060608 已提交
2
import { isPlainObject } from '@vue/shared'
fxy060608's avatar
fxy060608 已提交
3 4 5 6 7
import {
  UniNode,
  NODE_TYPE_PAGE,
  UniBaseNode,
  IUniPageNode,
fxy060608's avatar
fxy060608 已提交
8
  formatLog,
fxy060608's avatar
fxy060608 已提交
9
  UniEvent,
fxy060608's avatar
fxy060608 已提交
10
  UniNodeJSON,
fxy060608's avatar
fxy060608 已提交
11
  ACTION_TYPE_ADD_EVENT,
fxy060608's avatar
fxy060608 已提交
12 13
  ACTION_TYPE_CREATE,
  ACTION_TYPE_INSERT,
fxy060608's avatar
fxy060608 已提交
14 15
  ACTION_TYPE_PAGE_CREATE,
  ACTION_TYPE_PAGE_CREATED,
fxy060608's avatar
fxy060608 已提交
16 17
  ACTION_TYPE_REMOVE,
  ACTION_TYPE_REMOVE_ATTRIBUTE,
fxy060608's avatar
fxy060608 已提交
18 19
  ACTION_TYPE_REMOVE_EVENT,
  ACTION_TYPE_SET_ATTRIBUTE,
fxy060608's avatar
fxy060608 已提交
20
  ACTION_TYPE_SET_TEXT,
fxy060608's avatar
fxy060608 已提交
21
  CreateAction,
fxy060608's avatar
fxy060608 已提交
22 23 24 25 26 27
  PageAction,
  PageCreateAction,
  PageCreatedAction,
  PageNodeOptions,
} from '@dcloudio/uni-shared'

fxy060608's avatar
fxy060608 已提交
28 29 30 31 32 33 34 35
import {
  ACTION_MINIFY,
  ACTION_TYPE_DICT,
  DictAction,
  Dictionary,
  Value,
  VD_SYNC,
} from '../../../constants'
fxy060608's avatar
fxy060608 已提交
36 37 38 39

export default class UniPageNode extends UniNode implements IUniPageNode {
  pageId: number
  private _id: number = 1
fxy060608's avatar
fxy060608 已提交
40
  private _created: boolean = false
fxy060608's avatar
fxy060608 已提交
41 42
  private createAction: PageCreateAction
  private createdAction: PageCreatedAction
fxy060608's avatar
fxy060608 已提交
43
  private _createActionMap = new Map<number, CreateAction>()
fxy060608's avatar
fxy060608 已提交
44 45 46 47 48 49 50 51
  public updateActions: (PageAction | DictAction)[] = []

  public dicts: Dictionary = []

  public normalizeDict: (
    value: unknown,
    normalizeValue?: boolean
  ) => any | number
fxy060608's avatar
fxy060608 已提交
52

fxy060608's avatar
fxy060608 已提交
53 54
  public isUnmounted: boolean

fxy060608's avatar
fxy060608 已提交
55 56
  private _update: () => void

fxy060608's avatar
fxy060608 已提交
57 58 59 60 61 62 63 64 65 66
  constructor(
    pageId: number,
    options: PageNodeOptions,
    setup: boolean = false
  ) {
    super(NODE_TYPE_PAGE, '#page', null as unknown as IUniPageNode)
    this.nodeId = 0
    this.pageId = pageId
    this.pageNode = this

fxy060608's avatar
fxy060608 已提交
67 68
    this.isUnmounted = false

fxy060608's avatar
fxy060608 已提交
69 70 71
    this.createAction = [ACTION_TYPE_PAGE_CREATE, options]
    this.createdAction = [ACTION_TYPE_PAGE_CREATED]

fxy060608's avatar
fxy060608 已提交
72 73
    this.normalizeDict = this._normalizeDict.bind(this)

fxy060608's avatar
fxy060608 已提交
74 75
    this._update = this.update.bind(this)

fxy060608's avatar
fxy060608 已提交
76 77
    setup && this.setup()
  }
fxy060608's avatar
fxy060608 已提交
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
  _normalizeDict(value: unknown, normalizeValue: boolean = true) {
    if (!ACTION_MINIFY) {
      return value
    }
    if (!isPlainObject(value)) {
      return this.addDict(value as Value)
    }
    const dictArray: [number, number][] = []
    Object.keys(value).forEach((n) => {
      const dict = [this.addDict(n) as number]
      const v = value[n as keyof typeof value] as Value
      if (normalizeValue) {
        dict.push(this.addDict(v) as number)
      } else {
        dict.push(v as number)
      }
      dictArray.push(dict as [number, number])
    })
    return dictArray
  }
  addDict<T extends Value>(value: T): T | number {
    if (!ACTION_MINIFY) {
      return value
    }
    const { dicts } = this
    const index = dicts.indexOf(value)
    if (index > -1) {
      return index
    }
    return dicts.push(value) - 1
  }
fxy060608's avatar
fxy060608 已提交
109 110 111 112
  onCreate(thisNode: UniNode, nodeName: string | number) {
    pushCreateAction(this, thisNode.nodeId!, nodeName)
    return thisNode
  }
fxy060608's avatar
fxy060608 已提交
113 114 115 116 117 118 119 120 121 122 123
  onInsertBefore(
    thisNode: UniNode,
    newChild: UniNode,
    refChild: UniNode | null
  ) {
    pushInsertAction(
      this,
      newChild as UniBaseNode,
      thisNode.nodeId!,
      (refChild && refChild.nodeId!) || -1
    )
fxy060608's avatar
fxy060608 已提交
124 125
    return newChild
  }
fxy060608's avatar
fxy060608 已提交
126 127
  onRemoveChild(oldChild: UniNode) {
    pushRemoveAction(this, oldChild.nodeId!)
fxy060608's avatar
fxy060608 已提交
128 129
    return oldChild
  }
fxy060608's avatar
fxy060608 已提交
130 131 132 133 134 135 136 137 138 139
  onAddEvent(thisNode: UniNode, name: string, flag: number) {
    if (thisNode.parentNode) {
      pushAddEventAction(this, thisNode.nodeId!, name, flag)
    }
  }
  onRemoveEvent(thisNode: UniNode, name: string) {
    if (thisNode.parentNode) {
      pushRemoveEventAction(this, thisNode.nodeId!, name)
    }
  }
fxy060608's avatar
fxy060608 已提交
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
  onSetAttribute(thisNode: UniNode, qualifiedName: string, value: unknown) {
    if (thisNode.parentNode) {
      pushSetAttributeAction(this, thisNode.nodeId!, qualifiedName, value)
    }
  }
  onRemoveAttribute(thisNode: UniNode, qualifiedName: string) {
    if (thisNode.parentNode) {
      pushRemoveAttributeAction(this, thisNode.nodeId!, qualifiedName)
    }
  }
  onTextContent(thisNode: UniNode, text: string) {
    if (thisNode.parentNode) {
      pushSetTextAction(this, thisNode.nodeId!, text)
    }
  }
  onNodeValue(thisNode: UniNode, val: string | null) {
    if (thisNode.parentNode) {
      pushSetTextAction(this, thisNode.nodeId!, val as string)
    }
  }
  genId() {
    return this._id++
  }
fxy060608's avatar
fxy060608 已提交
163
  push(action: PageAction, extras?: unknown) {
fxy060608's avatar
fxy060608 已提交
164 165 166 167 168 169
    if (this.isUnmounted) {
      if (__DEV__) {
        console.log(formatLog('PageNode', 'push.prevent', action))
      }
      return
    }
fxy060608's avatar
fxy060608 已提交
170 171 172 173 174 175 176
    switch (action[0]) {
      case ACTION_TYPE_CREATE:
        this._createActionMap.set(action[1], action)
        break
      case ACTION_TYPE_INSERT:
        const createAction = this._createActionMap.get(action[1])
        if (createAction) {
fxy060608's avatar
fxy060608 已提交
177 178 179 180
          createAction[3] = action[2] // parentNodeId
          if (extras) {
            createAction[4] = extras as UniNodeJSON
          }
fxy060608's avatar
fxy060608 已提交
181 182 183 184 185 186 187
        } else {
          if (__DEV__) {
            console.error(formatLog(`Insert`, action, 'not found createAction'))
          }
        }
        break
    }
fxy060608's avatar
fxy060608 已提交
188
    this.updateActions.push(action)
fxy060608's avatar
fxy060608 已提交
189
    queuePostFlushCb(this._update)
fxy060608's avatar
fxy060608 已提交
190 191 192 193 194 195 196 197 198 199
  }
  restore() {
    this.push(this.createAction)
    // TODO restore children
    this.push(this.createdAction)
  }
  setup() {
    this.send([this.createAction])
  }
  update() {
fxy060608's avatar
fxy060608 已提交
200
    const { dicts, updateActions, _createActionMap } = this
fxy060608's avatar
fxy060608 已提交
201
    if (__DEV__) {
fxy060608's avatar
fxy060608 已提交
202 203 204 205 206 207 208 209
      console.log(
        formatLog(
          'PageNode',
          'update',
          updateActions.length,
          _createActionMap.size
        )
      )
fxy060608's avatar
fxy060608 已提交
210
    }
fxy060608's avatar
fxy060608 已提交
211
    _createActionMap.clear()
fxy060608's avatar
fxy060608 已提交
212 213 214 215 216
    // 首次
    if (!this._created) {
      this._created = true
      updateActions.push(this.createdAction)
    }
fxy060608's avatar
fxy060608 已提交
217
    if (updateActions.length) {
fxy060608's avatar
fxy060608 已提交
218 219 220
      if (dicts.length) {
        updateActions.unshift([ACTION_TYPE_DICT, dicts])
      }
fxy060608's avatar
fxy060608 已提交
221
      this.send(updateActions)
fxy060608's avatar
fxy060608 已提交
222
      dicts.length = 0
fxy060608's avatar
fxy060608 已提交
223 224 225
      updateActions.length = 0
    }
  }
fxy060608's avatar
fxy060608 已提交
226
  send(action: (PageAction | DictAction)[]) {
fxy060608's avatar
fxy060608 已提交
227
    UniServiceJSBridge.publishHandler(VD_SYNC, action, this.pageId)
fxy060608's avatar
fxy060608 已提交
228
  }
fxy060608's avatar
fxy060608 已提交
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
  fireEvent(id: number, evt: UniEvent) {
    const node = findNodeById(id, this)
    if (node) {
      node.dispatchEvent(evt)
    } else if (__DEV__) {
      console.error(formatLog('PageNode', 'fireEvent', id, 'not found', evt))
    }
  }
}

function findNodeById(id: number, uniNode: UniNode): UniNode | null {
  if (uniNode.nodeId === id) {
    return uniNode
  }
  const { childNodes } = uniNode
  for (let i = 0; i < childNodes.length; i++) {
    const uniNode = findNodeById(id, childNodes[i])
    if (uniNode) {
      return uniNode
    }
  }
  return null
fxy060608's avatar
fxy060608 已提交
251 252 253 254 255 256 257
}

function pushCreateAction(
  pageNode: UniPageNode,
  nodeId: number,
  nodeName: string | number
) {
fxy060608's avatar
fxy060608 已提交
258
  pageNode.push([ACTION_TYPE_CREATE, nodeId, pageNode.addDict(nodeName), -1])
fxy060608's avatar
fxy060608 已提交
259 260 261 262 263 264
}

function pushInsertAction(
  pageNode: UniPageNode,
  newChild: UniBaseNode,
  parentNodeId: number,
fxy060608's avatar
fxy060608 已提交
265
  refChildId: number
fxy060608's avatar
fxy060608 已提交
266
) {
fxy060608's avatar
fxy060608 已提交
267 268 269 270
  const nodeJson = newChild.toJSON({
    attr: true,
    normalize: pageNode.normalizeDict,
  })
fxy060608's avatar
fxy060608 已提交
271 272 273 274
  pageNode.push(
    [ACTION_TYPE_INSERT, newChild.nodeId!, parentNodeId, refChildId],
    Object.keys(nodeJson).length ? nodeJson : undefined
  )
fxy060608's avatar
fxy060608 已提交
275 276
}

fxy060608's avatar
fxy060608 已提交
277 278
function pushRemoveAction(pageNode: UniPageNode, nodeId: number) {
  pageNode.push([ACTION_TYPE_REMOVE, nodeId])
fxy060608's avatar
fxy060608 已提交
279 280
}

fxy060608's avatar
fxy060608 已提交
281 282 283 284 285 286
function pushAddEventAction(
  pageNode: UniPageNode,
  nodeId: number,
  name: string,
  value: number
) {
fxy060608's avatar
fxy060608 已提交
287
  pageNode.push([ACTION_TYPE_ADD_EVENT, nodeId, pageNode.addDict(name), value])
fxy060608's avatar
fxy060608 已提交
288 289 290 291 292 293 294
}

function pushRemoveEventAction(
  pageNode: UniPageNode,
  nodeId: number,
  name: string
) {
fxy060608's avatar
fxy060608 已提交
295
  pageNode.push([ACTION_TYPE_REMOVE_EVENT, nodeId, pageNode.addDict(name)])
fxy060608's avatar
fxy060608 已提交
296 297
}

fxy060608's avatar
fxy060608 已提交
298 299 300 301 302 303
function pushSetAttributeAction(
  pageNode: UniPageNode,
  nodeId: number,
  name: string,
  value: unknown
) {
fxy060608's avatar
fxy060608 已提交
304 305 306 307 308 309
  pageNode.push([
    ACTION_TYPE_SET_ATTRIBUTE,
    nodeId,
    pageNode.addDict(name),
    pageNode.addDict(value as Value),
  ])
fxy060608's avatar
fxy060608 已提交
310 311 312 313 314 315 316
}

function pushRemoveAttributeAction(
  pageNode: UniPageNode,
  nodeId: number,
  name: string
) {
fxy060608's avatar
fxy060608 已提交
317
  pageNode.push([ACTION_TYPE_REMOVE_ATTRIBUTE, nodeId, pageNode.addDict(name)])
fxy060608's avatar
fxy060608 已提交
318 319 320 321 322 323 324
}

function pushSetTextAction(
  pageNode: UniPageNode,
  nodeId: number,
  text: string
) {
fxy060608's avatar
fxy060608 已提交
325
  pageNode.push([ACTION_TYPE_SET_TEXT, nodeId, pageNode.addDict(text)])
fxy060608's avatar
fxy060608 已提交
326 327 328 329 330 331 332 333 334
}

export function createPageNode(
  pageId: number,
  pageOptions: PageNodeOptions,
  setup?: boolean
) {
  return new UniPageNode(pageId, pageOptions, setup)
}