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

fxy060608's avatar
fxy060608 已提交
27
import { VD_SYNC } from '../../../constants'
fxy060608's avatar
fxy060608 已提交
28 29 30 31

export default class UniPageNode extends UniNode implements IUniPageNode {
  pageId: number
  private _id: number = 1
fxy060608's avatar
fxy060608 已提交
32
  private _created: boolean = false
fxy060608's avatar
fxy060608 已提交
33 34
  private createAction: PageCreateAction
  private createdAction: PageCreatedAction
fxy060608's avatar
fxy060608 已提交
35
  private _createActionMap = new Map<number, CreateAction>()
fxy060608's avatar
fxy060608 已提交
36
  public updateActions: PageAction[] = []
fxy060608's avatar
fxy060608 已提交
37

fxy060608's avatar
fxy060608 已提交
38 39
  public isUnmounted: boolean

fxy060608's avatar
fxy060608 已提交
40 41
  private _update: () => void

fxy060608's avatar
fxy060608 已提交
42 43 44 45 46 47 48 49 50 51
  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 已提交
52 53
    this.isUnmounted = false

fxy060608's avatar
fxy060608 已提交
54 55 56
    this.createAction = [ACTION_TYPE_PAGE_CREATE, options]
    this.createdAction = [ACTION_TYPE_PAGE_CREATED]

fxy060608's avatar
fxy060608 已提交
57 58
    this._update = this.update.bind(this)

fxy060608's avatar
fxy060608 已提交
59 60 61 62 63 64
    setup && this.setup()
  }
  onCreate(thisNode: UniNode, nodeName: string | number) {
    pushCreateAction(this, thisNode.nodeId!, nodeName)
    return thisNode
  }
fxy060608's avatar
fxy060608 已提交
65 66 67 68 69 70 71 72 73 74 75
  onInsertBefore(
    thisNode: UniNode,
    newChild: UniNode,
    refChild: UniNode | null
  ) {
    pushInsertAction(
      this,
      newChild as UniBaseNode,
      thisNode.nodeId!,
      (refChild && refChild.nodeId!) || -1
    )
fxy060608's avatar
fxy060608 已提交
76 77
    return newChild
  }
fxy060608's avatar
fxy060608 已提交
78 79
  onRemoveChild(oldChild: UniNode) {
    pushRemoveAction(this, oldChild.nodeId!)
fxy060608's avatar
fxy060608 已提交
80 81
    return oldChild
  }
fxy060608's avatar
fxy060608 已提交
82 83 84 85 86 87 88 89 90 91
  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 已提交
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
  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 已提交
115
  push(action: PageAction, extras?: unknown) {
fxy060608's avatar
fxy060608 已提交
116 117 118 119 120 121
    if (this.isUnmounted) {
      if (__DEV__) {
        console.log(formatLog('PageNode', 'push.prevent', action))
      }
      return
    }
fxy060608's avatar
fxy060608 已提交
122 123 124 125 126 127 128
    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 已提交
129 130 131 132
          createAction[3] = action[2] // parentNodeId
          if (extras) {
            createAction[4] = extras as UniNodeJSON
          }
fxy060608's avatar
fxy060608 已提交
133 134 135 136 137 138 139
        } else {
          if (__DEV__) {
            console.error(formatLog(`Insert`, action, 'not found createAction'))
          }
        }
        break
    }
fxy060608's avatar
fxy060608 已提交
140
    this.updateActions.push(action)
fxy060608's avatar
fxy060608 已提交
141
    queuePostFlushCb(this._update)
fxy060608's avatar
fxy060608 已提交
142 143 144 145 146 147 148 149 150 151
  }
  restore() {
    this.push(this.createAction)
    // TODO restore children
    this.push(this.createdAction)
  }
  setup() {
    this.send([this.createAction])
  }
  update() {
fxy060608's avatar
fxy060608 已提交
152
    const { updateActions, _createActionMap } = this
fxy060608's avatar
fxy060608 已提交
153
    if (__DEV__) {
fxy060608's avatar
fxy060608 已提交
154 155 156 157 158 159 160 161
      console.log(
        formatLog(
          'PageNode',
          'update',
          updateActions.length,
          _createActionMap.size
        )
      )
fxy060608's avatar
fxy060608 已提交
162
    }
fxy060608's avatar
fxy060608 已提交
163
    _createActionMap.clear()
fxy060608's avatar
fxy060608 已提交
164 165 166 167 168
    // 首次
    if (!this._created) {
      this._created = true
      updateActions.push(this.createdAction)
    }
fxy060608's avatar
fxy060608 已提交
169 170 171 172 173 174
    if (updateActions.length) {
      this.send(updateActions)
      updateActions.length = 0
    }
  }
  send(action: PageAction[]) {
fxy060608's avatar
fxy060608 已提交
175
    UniServiceJSBridge.publishHandler(VD_SYNC, action, this.pageId)
fxy060608's avatar
fxy060608 已提交
176
  }
fxy060608's avatar
fxy060608 已提交
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
  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 已提交
199 200 201 202 203 204 205
}

function pushCreateAction(
  pageNode: UniPageNode,
  nodeId: number,
  nodeName: string | number
) {
fxy060608's avatar
fxy060608 已提交
206
  pageNode.push([ACTION_TYPE_CREATE, nodeId, nodeName, -1])
fxy060608's avatar
fxy060608 已提交
207 208 209 210 211 212
}

function pushInsertAction(
  pageNode: UniPageNode,
  newChild: UniBaseNode,
  parentNodeId: number,
fxy060608's avatar
fxy060608 已提交
213
  refChildId: number
fxy060608's avatar
fxy060608 已提交
214
) {
fxy060608's avatar
fxy060608 已提交
215 216 217 218 219
  const nodeJson = newChild.toJSON({ attr: true })
  pageNode.push(
    [ACTION_TYPE_INSERT, newChild.nodeId!, parentNodeId, refChildId],
    Object.keys(nodeJson).length ? nodeJson : undefined
  )
fxy060608's avatar
fxy060608 已提交
220 221
}

fxy060608's avatar
fxy060608 已提交
222 223
function pushRemoveAction(pageNode: UniPageNode, nodeId: number) {
  pageNode.push([ACTION_TYPE_REMOVE, nodeId])
fxy060608's avatar
fxy060608 已提交
224 225
}

fxy060608's avatar
fxy060608 已提交
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
function pushAddEventAction(
  pageNode: UniPageNode,
  nodeId: number,
  name: string,
  value: number
) {
  pageNode.push([ACTION_TYPE_ADD_EVENT, nodeId, name, value])
}

function pushRemoveEventAction(
  pageNode: UniPageNode,
  nodeId: number,
  name: string
) {
  pageNode.push([ACTION_TYPE_REMOVE_EVENT, nodeId, name])
}

fxy060608's avatar
fxy060608 已提交
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
function pushSetAttributeAction(
  pageNode: UniPageNode,
  nodeId: number,
  name: string,
  value: unknown
) {
  pageNode.push([ACTION_TYPE_SET_ATTRIBUTE, nodeId, name, value])
}

function pushRemoveAttributeAction(
  pageNode: UniPageNode,
  nodeId: number,
  name: string
) {
  pageNode.push([ACTION_TYPE_REMOVE_ATTRIBUTE, nodeId, name])
}

function pushSetTextAction(
  pageNode: UniPageNode,
  nodeId: number,
  text: string
) {
  pageNode.push([ACTION_TYPE_SET_TEXT, nodeId, text])
}

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