Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(x): 处理子组件继承父组件样式 #77

Merged
merged 1 commit into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions packages/runtime-x/src/helpers/node.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { Element as UniXElement } from '@dcloudio/uni-app-x/types/native'

import type { NVueStyle } from './useCssStyles'
// 样式相关
const NODE_EXT_STYLES = 'styles' // node 中存储的可用样式表
const NODE_EXT_PARENT_STYLES = 'parentStyles' // node 中存储的父组件可用样式表
const NODE_EXT_CLASS_STYLE = 'classStyle' // node 中存储的 classStyle
const NODE_EXT_STYLE = 'style' // node 中存储的 style

Expand All @@ -19,22 +20,27 @@ export function getNodeExtraData(el: UniXElement, name: string): any | null {
return el.ext.get(name)
}

export function getExtraStyles(
el: UniXElement,
): Record<string, Record<string, Record<string, unknown>>> | null {
// get/set extraStyles
export function getExtraStyles(el: UniXElement): NVueStyle | null {
return getNodeExtraData(el, NODE_EXT_STYLES) as Record<
string,
Record<string, Record<string, unknown>>
> | null
}

export function setExtraStyles(
el: UniXElement,
styles: Record<string, Record<string, Record<string, any>>>,
) {
export function setExtraStyles(el: UniXElement, styles: NVueStyle) {
setNodeExtraData(el, NODE_EXT_STYLES, styles)
}

// get/set extraParentStyles
export function getExtraParentStyles(el: UniXElement): Array<NVueStyle> | null {
return getNodeExtraData(el, NODE_EXT_PARENT_STYLES) as Array<NVueStyle> | null
}

export function setExtraParentStyles(el: UniXElement, styles: NVueStyle[]) {
setNodeExtraData(el, NODE_EXT_PARENT_STYLES, styles)
}

export function getExtraClassStyle(el: UniXElement): Map<string, any> | null {
return getNodeExtraData(el, NODE_EXT_CLASS_STYLE) as Map<string, any> | null
}
Expand Down
47 changes: 36 additions & 11 deletions packages/runtime-x/src/helpers/useCssStyles.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { UniElement as UniXElement } from '@dcloudio/uni-app-x/types/native'
import type { ComponentInternalInstance } from '@vue/runtime-core'
import { hasOwn, isArray } from '@vue/shared'
import { getExtraStyle, getExtraStyles } from './node'
import { getExtraParentStyles, getExtraStyle, getExtraStyles } from './node'

type NVueStyle = Record<string, Record<string, Record<string, unknown>>>
export type NVueStyle = Record<string, Record<string, Record<string, unknown>>>

interface NVueComponent {
mpType: 'page' | 'app'
Expand Down Expand Up @@ -119,41 +119,66 @@ function parseClassName(
})
}

interface ParseStyleContext {
class ParseStyleContext {
styles: Map<string, unknown>
weights: Record<string, number>

constructor() {
this.styles = new Map()
this.weights = {}
}
}

function parseClassListWithStyleSheet(
classList: string[],
stylesheet: NVueStyle | null,
parentStylesheet: NVueStyle[] | null,
el: UniXElement | null = null,
) {
const context: ParseStyleContext = {
styles: new Map(),
weights: {},
}
): ParseStyleContext {
const context: ParseStyleContext = new ParseStyleContext()
classList.forEach(className => {
const parentStyles = stylesheet && stylesheet[className]
if (parentStyles) {
parseClassName(context, parentStyles, el)
}
})

// 自定义组件根节点class需要访问父组件的样式
if (parentStylesheet != null) {
classList.forEach(className => {
// 和 android 是 map,ios 是 array []
const parentStyles = (parentStylesheet ?? []).find(
style => style[className] !== null,
)?.[className]
if (parentStyles != null) {
parseClassName(context, parentStyles!, el)
}
})
}
return context
}

export function parseClassStyles(el: UniXElement) {
const styles = getExtraStyles(el)
return parseClassListWithStyleSheet(el.classList, styles, el)
const parentStyles = getExtraParentStyles(el)
if ((styles == null && parentStyles == null) || el.classList.length == 0) {
return new ParseStyleContext()
}

return parseClassListWithStyleSheet(el.classList, styles, parentStyles, el)
}

export function parseClassList(
classList: string[],
instance: ComponentInternalInstance,
el: UniXElement | null = null,
) {
return parseClassListWithStyleSheet(classList, parseStyleSheet(instance), el)
.styles
return parseClassListWithStyleSheet(
classList,
parseStyleSheet(instance),
null,
el,
).styles
}

export function parseStyleSheet({
Expand Down
11 changes: 10 additions & 1 deletion packages/runtime-x/src/modules/class.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Element as UniXElement } from '@dcloudio/uni-app-x/types/native'
import type { ComponentInternalInstance } from '@vue/runtime-core'
import {
type NVueStyle,
parseClassStyles,
parseStyleSheet,
toStyle,
Expand All @@ -9,6 +10,7 @@ import {
getExtraClassStyle,
isCommentNode,
setExtraClassStyle,
setExtraParentStyles,
setExtraStyles,
} from '../helpers/node'

Expand All @@ -24,7 +26,14 @@ export function patchClass(
const classList = next ? next.split(' ') : []
el.classList = classList
setExtraStyles(el, parseStyleSheet(instance))
// TODO 如果当前元素是组件根节点(非页面)
// 如果当前元素是组件根节点(非页面)
// todo 和安卓有差异 el === instance.subTree.el
if (instance.parent != null && instance !== instance.root) {
setExtraParentStyles(
el,
(instance.parent!.type as any).styles as NVueStyle[],
)
}
updateClassStyles(el)
}

Expand Down