diff --git a/packages/taro-runtime/src/constants.ts b/packages/taro-runtime/src/constants.ts index a7690b228eaf..b2354565a425 100644 --- a/packages/taro-runtime/src/constants.ts +++ b/packages/taro-runtime/src/constants.ts @@ -2,3 +2,4 @@ export const PROPERTY_THRESHOLD = 2046 export const TARO_RUNTIME = 'Taro runtime' export const SET_DATA = '小程序 setData' export const PAGE_INIT = '页面初始化' +export const SPECIAL_NODES = ['view', 'text', 'image'] diff --git a/packages/taro-runtime/src/dom/element.ts b/packages/taro-runtime/src/dom/element.ts index 71f050a706ea..174f16607a08 100644 --- a/packages/taro-runtime/src/dom/element.ts +++ b/packages/taro-runtime/src/dom/element.ts @@ -3,9 +3,9 @@ import { isArray, isUndefined, Shortcuts, EMPTY_OBJ, warn, isString, toCamelCase import { TaroNode } from './node' import { NodeType } from './node_types' import { TaroEvent, eventSource } from './event' -import { isElement } from '../utils' +import { isElement, isHasExtractProp } from '../utils' import { Style } from './style' -import { PROPERTY_THRESHOLD } from '../constants' +import { PROPERTY_THRESHOLD, SPECIAL_NODES } from '../constants' import { CurrentReconciler } from '../reconciler' import { treeToArray } from './tree' import { ClassList } from './class-list' @@ -93,16 +93,21 @@ export class TaroElement extends TaroNode { eventSource.set(value as string, this) qualifiedName = 'uid' } else { - this.props[qualifiedName] = value as string if (qualifiedName === 'class') { qualifiedName = Shortcuts.Class - } - if (qualifiedName.startsWith('data-')) { + } else if (qualifiedName.startsWith('data-')) { if (this.dataset === EMPTY_OBJ) { this.dataset = Object.create(null) } this.dataset[toCamelCase(qualifiedName.replace(/^data-/, ''))] = value + } else if (this.nodeName === 'view' && !isHasExtractProp(this) && !this.isAnyEventBinded()) { + // pure-view => static-view + this.enqueueUpdate({ + path: `${this._path}.${Shortcuts.NodeName}`, + value: 'static-view' + }) } + this.props[qualifiedName] = value as string } CurrentReconciler.setAttribute?.(this, qualifiedName, value) @@ -126,6 +131,14 @@ export class TaroElement extends TaroNode { path: `${this._path}.${toCamelCase(qualifiedName)}`, value: '' }) + + if (this.nodeName === 'view' && !isHasExtractProp(this) && !this.isAnyEventBinded()) { + // static-view => pure-view + this.enqueueUpdate({ + path: `${this._path}.${Shortcuts.NodeName}`, + value: 'pure-view' + }) + } } public getAttribute (qualifiedName: string): string { @@ -217,4 +230,28 @@ export class TaroElement extends TaroNode { } } } + + public addEventListener (type, handler, options) { + const name = this.nodeName + if (!this.isAnyEventBinded() && SPECIAL_NODES.indexOf(name) > -1) { + this.enqueueUpdate({ + path: `${this._path}.${Shortcuts.NodeName}`, + value: name + }) + } + + super.addEventListener(type, handler, options) + } + + public removeEventListener (type, handler) { + super.removeEventListener(type, handler) + + const name = this.nodeName + if (!this.isAnyEventBinded() && SPECIAL_NODES.indexOf(name) > -1) { + this.enqueueUpdate({ + path: `${this._path}.${Shortcuts.NodeName}`, + value: isHasExtractProp(this) ? `static-${name}` : `pure-${name}` + }) + } + } } diff --git a/packages/taro-runtime/src/hydrate.ts b/packages/taro-runtime/src/hydrate.ts index 8d0986c01ac5..d04d9b6b2433 100644 --- a/packages/taro-runtime/src/hydrate.ts +++ b/packages/taro-runtime/src/hydrate.ts @@ -1,6 +1,7 @@ -import { isText } from './utils' +import { isText, isHasExtractProp } from './utils' import { TaroElement } from './dom/element' import { TaroText } from './dom/text' +import { SPECIAL_NODES } from './constants' import { Shortcuts, toCamelCase } from '@tarojs/shared' import type { PageConfig } from '@tarojs/taro' @@ -40,35 +41,25 @@ export type HydratedData = () => MiniData | MiniData[] * it's a vnode traverser and modifier: that's exactly what Taro's doing in here. */ export function hydrate (node: TaroElement | TaroText): MiniData { + const nodeName = node.nodeName + if (isText(node)) { return { [Shortcuts.Text]: node.nodeValue, - [Shortcuts.NodeName]: node.nodeName + [Shortcuts.NodeName]: nodeName } } const data: MiniElementData = { - [Shortcuts.NodeName]: node.nodeName, + [Shortcuts.NodeName]: nodeName, uid: node.uid } const { props, childNodes } = node - if (!node.isAnyEventBinded()) { - if (node.nodeName === 'view') { - const isExtractProp = Object.keys(props).find(prop => { - return !(/class|style|id/.test(prop) || prop.startsWith('data-')) - }) - if (isExtractProp) { - data[Shortcuts.NodeName] = 'static-view' - } else { - data[Shortcuts.NodeName] = 'pure-view' - } - } - if (node.nodeName === 'text') { - data[Shortcuts.NodeName] = 'static-text' - } - if (node.nodeName === 'image') { - data[Shortcuts.NodeName] = 'static-image' + if (!node.isAnyEventBinded() && SPECIAL_NODES.indexOf(nodeName) > -1) { + data[Shortcuts.NodeName] = `static-${nodeName}` + if (nodeName === 'view' && !isHasExtractProp(node)) { + data[Shortcuts.NodeName] = 'pure-view' } } @@ -83,7 +74,7 @@ export function hydrate (node: TaroElement | TaroText): MiniData { ) { data[propInCamelCase] = props[prop] } - if (node.nodeName === 'view' && propInCamelCase === 'catchMove' && props[prop] !== 'false') { + if (nodeName === 'view' && propInCamelCase === 'catchMove' && props[prop] !== 'false') { data[Shortcuts.NodeName] = 'catch-view' } } @@ -96,7 +87,7 @@ export function hydrate (node: TaroElement | TaroText): MiniData { data[Shortcuts.Class] = node.className } - if (node.cssText !== '' && node.nodeName !== 'swiper-item') { + if (node.cssText !== '' && nodeName !== 'swiper-item') { data[Shortcuts.Style] = node.cssText } diff --git a/packages/taro-runtime/src/utils/index.ts b/packages/taro-runtime/src/utils/index.ts index 91daabb17e59..243720274b33 100644 --- a/packages/taro-runtime/src/utils/index.ts +++ b/packages/taro-runtime/src/utils/index.ts @@ -15,3 +15,10 @@ export function isElement (node: TaroNode): node is TaroElement { export function isText (node: TaroNode): node is TaroText { return node.nodeType === NodeType.TEXT_NODE } + +export function isHasExtractProp (el: TaroElement): boolean { + const res = Object.keys(el.props).find(prop => { + return !(/class|style|id/.test(prop) || prop.startsWith('data-')) + }) + return Boolean(res) +}