Ir al contenido

pt —— fusión de atributos de passthrough

Un componente tiene varios elementos en su interior (el <button> del botón y el <span> que contiene; el <input> del campo de entrada y el icono delantero <i>): ¿cómo hacer cuando alguien quiere ajustar uno de ellos desde fuera? La respuesta de lh-ui es el paquete de atributos PT (PassThrough): el componente expone una prop pt que transmite class / style / attrs por separado, según el nombre del elemento interior. mergePt se encarga de fusionarlo con los nombres de clase propios del componente.

  • En el interior de la biblioteca de componentes: cada elemento interior llama a mergePt(props.pt?.icon, 'lh-button__icon') y obtiene el class / style / attrs que le toca.
  • Desde el lado de quien usa el componente, para un ajuste fino de un elemento interior concreto a través de la prop pt, sin necesidad de perforar con :deep().

Cuándo no usarlo: personalización a nivel de tema (usar themeVars); añadir un simple nombre de clase (usar la prop class).

import { mergePt, type LhPtAttrs } from '@lh-ui/share/core/shared/pt'
export interface LhPtAttrs {
class?: string | string[] | Record<string, boolean>
style?: Record<string, string>
attrs?: Record<string, any>
}
Función Firma Acción
mergePt (pt: LhPtAttrs | undefined, baseClass: string) => { class: string[]; style: Record<string, string>; attrs: Record<string, any> } Fusiona los atributos PT con el nombre de clase base

baseClass va siempre el primero del arreglo y el class del usuario detrás:

mergePt({ class: 'my-icon' }, 'lh-button__icon')
// { class: ['lh-button__icon', 'my-icon'], style: {}, attrs: {} }
mergePt({ class: ['a', 'b'] }, 'lh-button__icon')
// class: ['lh-button__icon', 'a', 'b']
mergePt({ class: { active: true, disabled: false } }, 'lh-button__icon')
// class: ['lh-button__icon', 'active'] —— del objeto solo se toman las claves con valor verdadero
mergePt({ class: 'a b ' }, 'lh-button__icon')
// class: ['lh-button__icon', 'a', 'b'] —— la cadena se corta por espacios y se filtran las vacías

Por qué baseClass va primero: la especificidad del nombre de clase base BEM no debe quedar por debajo de la del class del usuario (siendo ambos nombres simples, el que se escribe después prevalece sobre el primero). El modificador --primary del componente debe poder seguir cubriendo el my-icon del usuario.

mergePt(undefined, 'lh-button__icon')
// { class: ['lh-button__icon'], style: {}, attrs: {} } —— con pt vacío, todo vacío
mergePt({ style: { color: 'red' }, attrs: { 'data-x': '1' } }, 'lh-button__icon')
// { class: ['lh-button__icon'], style: { color: 'red' }, attrs: { 'data-x': '1' } }

Nota: style / attrs pasan por referencia, sin copia. La capa UI puede hacer directamente v-bind="merged.attrs" / :style="merged.style"; no mute el valor de retorno dentro del componente.

Interior del componente (el elemento icono del botón)

Sección titulada «Interior del componente (el elemento icono del botón)»
// Componente button
const iconPt = computed(() => mergePt(props.pt?.icon, 'lh-button__icon'))
<template>
<button class="lh-button">
<i v-if="icon" v-bind="iconPt.attrs" :class="iconPt.class" :style="iconPt.style" />
<span><slot /></span>
</button>
</template>
<lh-button
:pt="{
icon: { class: 'text-lg', style: { marginRight: '4px' } },
$root: { attrs: { 'data-test': 'submit' } },
}"
>
Enviar
</lh-button>
const iconPt = mergePt(pt?.icon, 'lh-button__icon')
return (
<button className="lh-button">
{icon && <i className={iconPt.class.join(' ')} style={iconPt.style} {...iconPt.attrs} />}
</button>
)
  • Fusión superficial, sin deepMerge: class se concatena a nivel de arreglo; style / attrs se sustituyen enteros. Aquí una fusión profunda no tendría semántica (class es una lista, no un árbol).
  • Con pt vacío devuelve un objeto totalmente vacío: la capa UI puede desestructurar sin más, sin comprobación de nulos.
  • El class devuelto es un arreglo: el :class de Vue admite arreglos; React necesita .join(' ').
  • El nombre de clase base no puede omitirse: mergePt(pt, '') devolvería un arreglo cuyo primer elemento es la cadena vacía: el nombre de clase base BEM es el anclaje del estilo y cada elemento interior debe tener el suyo.
@lh-ui/share/core/pt → mergePt( )
返回值
(填好参数后点运行)

Copyright © 2024-2026 FengMo WenXue