Skip to content
API 风格:

Popover (fenêtre contextuelle) ​

Couche flottante à contenu riche : elle transporte plus d'informations qu'un Tooltip (titre, corps, boutons d'action). Le déclencheur est enveloppé dans le slot par défaut, tandis que le contenu flottant est transmis via le slot content. Lors d'un déclenchement par clic, la couche flottante a role="dialog" et piège le focus ; lors d'un déclenchement par survol, elle se contente d'afficher le contenu sans interrompre le flux clavier.

Utilisation de base ​

Déclenchement au clic
vue
<script setup lang="ts">
</script>

<template>
  <LhPopover title="Astuce encre de Chine" placement="top">
    <LhButton>Afficher au clic</LhButton>
    <template #content>
      <p>Ceci est un contenu riche, dans lequel vous pouvez placer n'importe quel markup.</p>
    </template>
  </LhPopover>
</template>
vue
<script>
export default {}
</script>

<template>
  <LhPopover title="Astuce encre de Chine" placement="top">
    <LhButton>Afficher au clic</LhButton>
    <template #content>
      <p>Ceci est un contenu riche, dans lequel vous pouvez placer n'importe quel markup.</p>
    </template>
  </LhPopover>
</template>

Modes de déclenchement ​

hover / focus / manual
vue
<template>
  <!-- Déclenchement au survol -->
  <LhPopover trigger="hover" title="Déclenchement au survol" :show-after="0">
    <LhButton>Survolez-moi</LhButton>
    <template #content><p>Déplacer le pointeur à l'intérieur de la couche flottante ne la ferme pas.</p></template>
  </LhPopover>
  <!-- Déclenchement au focus -->
  <LhPopover trigger="focus" title="Déclenchement au focus" :show-after="0">
    <LhInput placeholder="Champ de saisie" />
    <template #content><p>Affiché lorsque le champ reçoit le focus.</p></template>
  </LhPopover>
  <!-- Contrôle manuel -->
  <LhPopover v-model:visible="manualVisible" trigger="manual" title="Contrôle manuel">
    <LhButton @click="manualVisible = !manualVisible">Commutateur externe</LhButton>
    <template #content><p>L'affichage est entièrement contrôlé par le v-model externe.</p></template>
  </LhPopover>
</template>

<script setup lang="ts">
import { ref } from 'vue'
const manualVisible = ref(false)
</script>
vue
<template>
  <!-- Déclenchement au survol -->
  <LhPopover trigger="hover" title="Déclenchement au survol" :show-after="0">
    <LhButton>Survolez-moi</LhButton>
    <template #content><p>Déplacer le pointeur à l'intérieur de la couche flottante ne la ferme pas.</p></template>
  </LhPopover>
  <!-- Déclenchement au focus -->
  <LhPopover trigger="focus" title="Déclenchement au focus" :show-after="0">
    <LhInput placeholder="Champ de saisie" />
    <template #content><p>Affiché lorsque le champ reçoit le focus.</p></template>
  </LhPopover>
  <!-- Contrôle manuel -->
  <LhPopover v-model:visible="manualVisible" trigger="manual" title="Contrôle manuel">
    <LhButton @click="manualVisible = !manualVisible">Commutateur externe</LhButton>
    <template #content><p>L'affichage est entièrement contrôlé par le v-model externe.</p></template>
  </LhPopover>
</template>

<script>
export default {
  data() {
    return { manualVisible: false }
  },
}
</script>

Douze orientations ​

placement
vue
<template>
  <LhPopover
    v-for="p in placements"
    :key="p"
    :placement="p"
    :title="p"
    trigger="hover"
    :show-after="0"
  >
    <LhButton size="small">{{ p }}</LhButton>
    <template #content><p>Orientation : {{ p }}</p></template>
  </LhPopover>
</template>

<script setup lang="ts">
const placements = [
  'top', 'top-start', 'top-end',
  'bottom', 'bottom-start', 'bottom-end',
  'left', 'left-start', 'left-end',
  'right', 'right-start', 'right-end',
] as const
</script>
vue
<template>
  <LhPopover
    v-for="p in placements"
    :key="p"
    :placement="p"
    :title="p"
    trigger="hover"
    :show-after="0"
  >
    <LhButton size="small">{{ p }}</LhButton>
    <template #content><p>Orientation : {{ p }}</p></template>
  </LhPopover>
</template>

<script>
export default {
  data() {
    return {
      placements: [
        'top', 'top-start', 'top-end',
        'bottom', 'bottom-start', 'bottom-end',
        'left', 'left-start', 'left-end',
        'right', 'right-start', 'right-end',
      ],
    }
  },
}
</script>

En cas d'espace insuffisant dans la fenêtre, la couche flottante retourne automatiquement (flip) et se recentre sur l'axe secondaire (shift) ; la position de la flèche s'adapte en conséquence.

Contenu interactif imbriqué ​

Exemple de formulaire
vue
<template>
  <LhPopover placement="right" title="Note rapide">
    <LhButton>Ajouter une note</LhButton>
    <template #content>
      <div class="demo-popover-form">
        <LhInput v-model="note" placeholder="Saisir le contenu de la note" />
        <LhButton type="primary" @click="saveNote">Enregistrer</LhButton>
      </div>
    </template>
  </LhPopover>
</template>

<script setup lang="ts">
import { ref } from 'vue'
const note = ref('')
const saved = ref('')
function saveNote() {
  saved.value = note.value
  note.value = ''
}
</script>
vue
<template>
  <LhPopover placement="right" title="Note rapide">
    <LhButton>Ajouter une note</LhButton>
    <template #content>
      <div class="demo-popover-form">
        <LhInput v-model="note" placeholder="Saisir le contenu de la note" />
        <LhButton type="primary" @click="saveNote">Enregistrer</LhButton>
      </div>
    </template>
  </LhPopover>
</template>

<script>
export default {
  data() {
    return { note: '', saved: '' }
  },
  methods: {
    saveNote() {
      this.saved = this.note
      this.note = ''
    },
  },
}
</script>

Autres propriétés ​

disabled / arrow / width / hideAfter / popperClass / teleportTarget
Conteneur Teleport (#demo-popover-host)
vue
<script setup lang="ts">
</script>

<template>
  <!-- Désactivé -->
  <LhPopover disabled title="Désactivé">
    <LhButton disabled>Déclencheur désactivé</LhButton>
    <template #content><p>Lorsque disabled est actif, le déclencheur et la couche flottante ne réagissent plus.</p></template>
  </LhPopover>
  <!-- Sans flèche -->
  <LhPopover title="Sans flèche" :arrow="false" :show-after="0">
    <LhButton>Sans flèche</LhButton>
    <template #content><p>Lorsque arrow vaut false, la flèche directionnelle n'est pas rendue.</p></template>
  </LhPopover>
  <!-- Largeur fixe -->
  <LhPopover title="Largeur fixe" width="240" :show-after="0">
    <LhButton>Largeur fixe</LhButton>
    <template #content><p>La largeur de la couche flottante est définie via width, ici 240px.</p></template>
  </LhPopover>
  <!-- Masquage différé -->
  <LhPopover title="Masquage différé" :hide-after="800" :show-after="0">
    <LhButton>Masquage différé</LhButton>
    <template #content><p>Le repli n'intervient que 800 ms après la sortie du déclencheur.</p></template>
  </LhPopover>
  <!-- Classe personnalisée -->
  <LhPopover title="Classe personnalisée" popper-class="demo-popper-accent" :show-after="0">
    <LhButton>Classe personnalisée</LhButton>
    <template #content><p>popperClass est ajouté à l'élément racine de la couche flottante, afin de personnaliser les styles.</p></template>
  </LhPopover>
  <!-- Cible de téléportation -->
  <LhPopover title="Cible de téléportation" teleport-target="#demo-popover-host" :show-after="0">
    <LhButton>Conteneur Teleport</LhButton>
    <template #content><p>La couche flottante est téléportée dans le conteneur ci-dessous et non dans body.</p></template>
  </LhPopover>
</template>
vue
<script>
export default {}
</script>

<template>
  <!-- Désactivé -->
  <LhPopover disabled title="Désactivé">
    <LhButton disabled>Déclencheur désactivé</LhButton>
    <template #content><p>Lorsque disabled est actif, le déclencheur et la couche flottante ne réagissent plus.</p></template>
  </LhPopover>
  <!-- Sans flèche -->
  <LhPopover title="Sans flèche" :arrow="false" :show-after="0">
    <LhButton>Sans flèche</LhButton>
    <template #content><p>Lorsque arrow vaut false, la flèche directionnelle n'est pas rendue.</p></template>
  </LhPopover>
  <!-- Largeur fixe -->
  <LhPopover title="Largeur fixe" width="240" :show-after="0">
    <LhButton>Largeur fixe</LhButton>
    <template #content><p>La largeur de la couche flottante est définie via width, ici 240px.</p></template>
  </LhPopover>
  <!-- Masquage différé -->
  <LhPopover title="Masquage différé" :hide-after="800" :show-after="0">
    <LhButton>Masquage différé</LhButton>
    <template #content><p>Le repli n'intervient que 800 ms après la sortie du déclencheur.</p></template>
  </LhPopover>
  <!-- Classe personnalisée -->
  <LhPopover title="Classe personnalisée" popper-class="demo-popper-accent" :show-after="0">
    <LhButton>Classe personnalisée</LhButton>
    <template #content><p>popperClass est ajouté à l'élément racine de la couche flottante, afin de personnaliser les styles.</p></template>
  </LhPopover>
  <!-- Cible de téléportation -->
  <LhPopover title="Cible de téléportation" teleport-target="#demo-popover-host" :show-after="0">
    <LhButton>Conteneur Teleport</LhButton>
    <template #content><p>La couche flottante est téléportée dans le conteneur ci-dessous et non dans body.</p></template>
  </LhPopover>
</template>

Affichage contrôlé ​

v-model:visible contrôle manuellement l'affichage de la couche flottante.

Affichage contrôlé
vue
<script setup lang="ts">
import { ref } from 'vue'
const popVisible = ref(false)
</script>

<template>
  <LhPopover v-model:visible="popVisible" title="Couche flottante contrôlée" trigger="manual">
    <LhButton>{{ popVisible ? 'Replier' : 'Déplier' }}</LhButton>
  </LhPopover>
</template>
vue
<script>
export default {
  data() {
    return { popVisible: false }
  },
}
</script>

<template>
  <LhPopover v-model:visible="popVisible" title="Couche flottante contrôlée" trigger="manual">
    <LhButton>{{ popVisible ? 'Replier' : 'Déplier' }}</LhButton>
  </LhPopover>
</template>

API Popover ​

Props ​

PropDescriptionTypeValeur par défaut
placementPosition d'affichage"top" | "top-start" | "top-end" | "bottom" | "bottom-start" | "bottom-end" | "left" | "left-start" | "left-end" | "right" | "right-start" | "right-end"'top'
triggerMode de déclenchement"click" | "hover" | "focus" | "manual"'click'
titleTitre (le slot title fonctionne aussi)string—
visibleÉtat d'affichage contrôlé manuellement (v-model:visible)boolean—
disabledDésactivéboolean—
arrowAfficher la flèchebooleantrue
widthLargeur de la couche flottantestring | number—
popperClassNom de classe personnalisé de la couche flottantestring—
teleportTargetCible du Teleport (sélecteur ou élément)string | HTMLElement'body'
showAfterDélai d'affichage (ms)number—
hideAfterDélai de masquage (ms)number—
themeVarsVariables de thème au niveau du composant, prime sur la configuration de ConfigProvider{ [x: string]: string; }—
bgPatternMotif d'arrière-plan au niveau du composant, prime sur la configuration de ConfigProviderstring—
sxProps de mise en page sx (appliquées à l'élément racine du déclencheur)LhSxProps—

Events ​

ÉvénementDescriptionParamètre
update:visibleChangement d'affichage(value: boolean)
showÉmis après l'affichage—
hideÉmis après le masquage—

Slots ​

SlotDescription
defaultContenu du déclencheur
titleTitre personnalisé
contentContenu flottant

Methods ​

MéthodeDescription
showAffichage programmatique
hideMasquage programmatique
toggleBasculement programmatique

Accessibilité ​

  • Lors d'un déclenchement par clic, la couche flottante a role="dialog" + aria-modal="true" ; le déclencheur porte aria-haspopup / aria-expanded
  • Le déclenchement par clic déplace le focus vers le premier élément focalisable de la couche flottante, Tab boucle à l'intérieur de celle-ci et, à la fermeture, le focus est rendu au déclencheur
  • Lors d'un déclenchement par survol / focus, le focus n'est pas déplacé, afin de ne pas interrompre la navigation clavier
  • Escape ferme la couche, ainsi qu'un clic à l'extérieur ; en présence d'un titre, celui-ci est lié via aria-labelledby
  • Le moteur de positionnement est développé en interne sous forme de fonctions pures (flip/shift anti-débordement), sans aucune dépendance runtime tierce

Repli lorsque le déclencheur sort de la fenêtre : la couche flottante est positionnée en fixed ; une fois le déclencheur hors de la fenêtre, elle ne le suit plus et reste suspendue au-dessus du contenu de la page avec un z-index élevé. C'est pourquoi, quel que soit le mode de déclenchement (y compris le mode contrôlé manual), lorsque le déclencheur sort entièrement de la fenêtre, le panneau se replie et émet update:visible pour synchroniser l'état externe.

Définitions de types ​

Ce composant exporte les structures de types TypeScript suivantes (extraites automatiquement de packages/components/popover/src/types.ts et des sources @lh-ui/share/core/* ; cliquez sur chaque entrée pour déplier la définition complète ; la description des props se trouve dans le tableau Props ci-dessus) :

LhPopoverProps
ts
/**
 * Props du composant Popover
 */
export interface LhPopoverProps {
  /** Position d'affichage */
  placement?: LhPlacement
  /** Mode de déclenchement */
  trigger?: LhPopoverTrigger
  /** Titre */
  title?: string
  /** État d'affichage contrôlé manuellement (v-model:visible) */
  visible?: boolean
  /** Désactivé */
  disabled?: boolean
  /** Afficher la flèche */
  arrow?: boolean
  /** Largeur de la couche flottante */
  width?: string | number
  /** Nom de classe personnalisé de la couche flottante */
  popperClass?: string
  /** Cible du Teleport (sélecteur ou élément, body par défaut) */
  teleportTarget?: string | HTMLElement
  /** Délai d'affichage (ms) */
  showAfter?: number
  /** Délai de masquage (ms) */
  hideAfter?: number
  /** Variables de thème au niveau du composant, prime sur la configuration de ConfigProvider */
  themeVars?: Record<string, string>
  /** Motif d'arrière-plan au niveau du composant, prime sur la configuration de ConfigProvider */
  bgPattern?: string
  /** Props de mise en page sx (appliquées à l'élément racine du déclencheur) */
  sx?: LhSxProps
}
LhPopoverPlacement (provenant de @lh-ui/share/core/shared/popper)
ts
/**
 * Moteur de positionnement Popper (fonctions pures, sans dépendance framework)
 *
 * Calculs géométriques partagés par les couches flottantes
 * (Tooltip / Popover / Popconfirm / Dropdown, etc.) :
 * positionnement selon 12 placements, retournement sur l'axe principal en cas de
 * débordement (flip), recentrage sur l'axe secondaire (shift).
 * Tous les paramètres sont des littéraux rect, sans toucher au DOM,
 * directement testables par tests unitaires.
 */

/** Orientation de la couche flottante (direction + alignement) */
export type LhPlacement =
  | 'top'
  | 'top-start'
  | 'top-end'
  | 'bottom'
  | 'bottom-start'
  | 'bottom-end'
  | 'left'
  | 'left-start'
  | 'left-end'
  | 'right'
  | 'right-start'
  | 'right-end'
LhPopoverTrigger (provenant de @lh-ui/share/core/popover (logic.ts))
ts
/** Mode de déclenchement */
export type LhPopoverTrigger = 'click' | 'hover' | 'focus' | 'manual'

La beauté de la tradition, la fondation du code