Important
本库使用了2025最新的CSS特性,不适合用于生产环境。
This library uses the latest 2025 CSS features and is not suitable for production environments.
本库功能仍有部分功能未完成文档尚未完成。
This library has some features that are not finished yet.
后续将提供机器翻译的英文版。
A machine-translated English version will be provided later.
Tips component for displaying extra info on the interface in Nuogz Web App, based on CSS Anchor Positioning and Vue 3
贴纸用于在界面中显示额外的信息,提供即时的指引或补充说明,以辅助用户理解和使用功能。用于Nuogz Web App,基于CSS Anchor Positioning、Vue3、UnoCSS
经过一系列的迭代,从原来的提示组件vue-tip升级重构为全新的web-app-tip
web-app-tip已弃用tippy.js,改为使用最新的CSS锚点定位(CSS Anchor Positioning)语法作为核心实现。
额外功能与Vue内置的功能进行结合,最大程度地不影响Vue的渲染逻辑
基础示例:
<!-- index.vue -->
<template>
<AppOrbit>...</AppOrbit>
<AppTip />
</template>
<script setup>
import AppTip, { install as installAppTip } from '@nuogz/web-app-tip';
// 需要createApp后通过provide()提供app实例
// 在createApp后立即install也是可以的
const app = inject('app');
installAppTip(app);
</script>贴纸分为两部分,自定义指令v-tip与组件<AppTip>。
v-tip指令通过install函数安装。
<AppTip>组件用于动态渲染展示贴纸所需要的HTML元素。
请将<AppTip>置于app的根元素下
- body
- app (index.vue)
- (module.vue)
- app-tip-box
- app-tip
<teleport-content>(teleport='in-tip'时,模板内容置于app-tip元素中)
<teleport-content>(teleport=true时)- app-tip-shadow (用于自动位置功能的相交检测)
- app-tip
- app (index.vue)
如果app使用天轨Orbit组件,那么DOM结构如下:
- body
- app (index.vue)
- app-moon
- app-main
- (module.vue)
- app-moon
- app-tip-box
- app-tip
<teleport-content>(teleport='in-tip'时,模板内容置于app-tip元素中)
<teleport-content>(teleport=true时)
- app-tip
- app-tip-shadow (用于自动位置功能的相交检测)
- app (index.vue)
注意:相关元素会根据实际调用次数增多,一个指令对应一套元素。并不是单例模式
根据Vue指令的语法设计,我们可以通过三种途径配置app-tip
<button v-tip:[arg].modifier="value">Im a button</button>指定Tip的显示内容。传入的内容最终会在模板中以{{ value }}的形式展示
修饰符用于指定启用/禁用某个特性。具体修饰符的功能请继续查看下面各项功能的说明
利用Vue指令中的动态参数语法,我们可以传入一个TipArg对象来更详细地配置各项tip特性
在Vue的文档和types中,arg的类型一直是string。但经过实测向arg传递object是有效。
不排除以后此途径会失效。届时需要迁移到其他路径
显示额外内容是贴纸的核心基础功能,支持多种来源
基础用法
<button v-tip="'Im a tip'">Im a button</button>通过TipArg.value传入
<template>
<button v-tip:[arg]>Im a button</button>
</template>
<script setup>
const arg = ref({ value: 'Im a tip' });
</script>此功能用于将实时渲染的Vue模板显示为贴纸的内容
为了避免入侵Vue的渲染逻辑,其核心功能将使用Vue内置的<Teleport>组件实现
由于<Teleport>的目标元素必须与<Teleport>在同一个挂载/更新周期内渲染。
要使用该功能,必须向v-tip传递一个TipArg,且TipArg.teleport设置为true或'in-tip'。
当对应的<app-tip-box>渲染后,贴纸会将<app-tip-box>赋值到TipArg.teleportTo中。
在渲染前,仍需向<Teleport>的to属性提供有效值以过渡,如body
当TipArg.teleport是true时,TipArg.teleportTo将会是<app-tip-box>。此时<app-tip-box>不会存在<app-tip>。
当TipArg.teleport是'in-tip'时,TipArg.teleportTo将会是<app-tip>
最佳实践:
<template>
<button v-tip:[arg]>Im a button</button>
<Teleport :to="$tip.teleportTo || 'body'">
<span>Im a template tip</span>
</Teleport>
</template>
<script setup>
const arg = ref({ teleport: true });
</script>在一般情况下,将<Teleport>的to属性短暂地设置为其他过渡用元素(如body)并不会造成闪烁。
但在极端情况下,渲染效率低,待传送的内容仍可能会因为停留在过渡用元素太久,
导致传送内容被渲染到视口中,最后造成产生闪烁。
若过渡用元素本身是隐藏的,则不受影响
此时可以通过对<Teleport>追加disabled和defer属性来避免闪烁:
<Teleport :to="..."
defer :disabled="$tip.teleportTo ? false : true"
>...</Teleport>area 默认值:top center
| 值 | 作用 | 修饰符 |
|---|---|---|
top |
居上 | .top |
bottom |
居下 | .bottom |
center |
居中 | .center |
left |
居左 | .left |
right |
居右 | .right |
位置功能依赖于CSS的position-area。因此area也可以组合地使用span-*,如设置为top span-right。
通常情况下显示的位置是正确的。但是自动位置功能是代码实时检后测调整的,并未对span-*进行完整的兼容,可能会意外的行为。
autoArea 默认值:true
当检测到Tip开始离开视口时,会自动调整Tip位置到新的位置,以尝试完成显示Tip
| 特性 | 作用 | 修饰符 |
|---|---|---|
true |
离开视口时自动调整位置 | - |
false |
什么都不做 | .noAutoArea |
CSS anchor positioning有提供
position-try等属性用于自动调整位置。
但目前相关属性的效果并不理想,因此没有将其纳入此次重构中,转为通过IntersectionObserver实现
hover 默认值:show
| 值 | 作用 | 修饰符 |
|---|---|---|
false |
什么都不做 | .noHoverShow |
show |
显示Tip(离开隐藏) | - |
pin |
显示Tip(离开不隐藏) | .hoverPin |
click 默认值:false
| 特性 | 作用 | 修饰符 |
|---|---|---|
false |
什么都不做 | - |
pin-flip |
切换Tip(离开不隐藏) | .clickPinFlip |
pin |
显示Tip(离开不隐藏) | .clickPin |
show-flip |
切换Tip(离开隐藏) | .clickShowFlip |
show |
显示Tip(离开隐藏) | .clickShow |
click:show-flip|show适用于hover:false的情况,否则行为会被hover:show覆盖
hide$clickGlobal 默认值:true
当Tip固定时,默认全局其他任意元素点击后隐藏Tip,以模拟离开且失焦
- 按下后触发滚动,不会导致解除
- 当点击是目标元素或Tip元素时,不会导致解除
| 特性 | 作用 | 修饰符 |
|---|---|---|
true |
固定后全局任意点击解除固定 | - |
false |
什么都不做 | .noUnpinGlobal |
watchArg 默认值:false
当指令的arg部分传入一个对象,对象内部变化后,不会触发指令的update事件(即使传入的是一个reactive对象)。
在当前的Vue版本中,当指令的参数部分v-tip:[arg]是一个对象时,即使该对象是响应式的,其内部属性的变化也不会触发指令的update钩子函数。
此时可配置watchArg:true或修饰符.watchArg,对arg对象进行深度侦听。
| 特性 | 作用 | 修饰符 |
|---|---|---|
true |
对arg对象进行深度侦听 | .watchArg |
false |
什么都不做 | - |
intangible 默认值:false
| 特性 | 作用 | 修饰符 |
|---|---|---|
false |
什么都不做 | - |
true或tip |
禁止app-tip进行交互 | .intang |
box |
禁止与app-tip-box进行交互 | .intangBox |
可否与内在元素交互
theme 默认值:base
支持自定义主题,通过[theme=主题名]定义。
也可以通过驼峰式的修饰符定义,如base-nowrap主题可用.themeBaseNowrap定义
内置主题基于web-app的通用色彩系统,均支持通过CSS变量--app-tip-text和--app-tip-back来改变贴纸文字和背景的颜色
主题不适用于模板内容,因为使用teleport=true时没有<app-tip>元素。
除非使用teleport='in-tip',此时模板内容传输到<app-tip>元素下
| 特性 | 作用 | 文字颜色 | 背景颜色 | 修饰符 |
|---|---|---|---|---|
base |
默认主题 | var(--gray-text1) |
var(--main-comp2) |
.themeBase |
base-nowrap |
默认主题(不换行) | var(--gray-text1) |
var(--main-comp2) |
.themeBaseNowrap |
prev |
在默认主题基础上,背景颜色向左偏移2色阶 | var(--gray-text1) |
var(--main-comp) |
.themePrev |
prev-nowrap |
在默认主题基础上,背景颜色向左偏移2色阶(不换行) | var(--gray-text1) |
var(--main-comp) |
.themePrevNowrap |
next |
在默认主题基础上,背景颜色向右偏移2色阶 | var(--gray-text1) |
var(--main-line) |
.themeNext |
next-nowrap |
在默认主题基础上,背景颜色向右偏移2色阶(不换行) | var(--gray-text1) |
var(--main-line) |
.themeNextNowrap |
solid |
主题色的高亮主题,通常不受明暗环境影响 | var(--contrast) |
var(--main-solid) |
.themeSolid |
solid-nowrap |
主题色的高亮主题,通常不受明暗环境影响(不换行) | var(--contrast) |
var(--main-solid) |
.themeSolidNowrap |
<template>
<button v-tip:[arg]>Im a button</button>
</template>
<script setup>
const arg = ref({ theme: 'test' });
</script>
<style lang="sass" scoped>
:global(app-tip[theme=test])
@apply p-2 py-1.5 bg-green-4 rounded-lg shadow-d1-md ws-pre
</style>因为贴纸是<app>子元素,所以需要将主题提升到全局。
建议将主题样式放置在全局位置,或者使用足够独特的名字。不要像演示这样在某个单文件组件中定义
offset 默认值:4
贴纸与目标元素的间隔。会位置自动调整间隔的位置
本质是css长度单位。
如果是number类型,会自动补全px单位。
如果是string类型,则不会做任何修改
arrow 默认值:true
在贴纸和目标元素之间显示指向目标元素的三角箭头
已支持在四角位置、span位置显示三角箭头
| 特性 | 作用 | 修饰符 |
|---|---|---|
true |
在贴纸和目标元素之间显示三角箭头 | - |
false |
不显示三角箭头 | .noArrow |
refInstance 默认值:null
在一些需要手动控制贴纸显示的场景下,需要直接访问实例。此时可以TipArg.refInstance传递true或一个回调函数,当实例初始化完毕后,会返回Tip实例:
| 特性 | 回调方式 |
|---|---|
true |
TipArg.instance = tip; |
(tip) => {} |
调用函数 |
mount 默认值:false
默认情况下,贴纸显示的内容会挂载到<AppTip>组件下,像这是特意设计的。
这样做可以避免因为目标的祖先元素设置了限制溢出显示的overflow属性,而导致贴纸无法完整显示的问题。
但在一些极为特殊的场景下,如<dialog>元素的showModal(),显示模态框时,<dialog>中的元素会脱离文档流,导致贴纸找不到锚点。
此时可以通过设置mount属性,将贴纸传送(依旧是是Vue的Teleport功能)到mount属性指定的元素下,如和目标元素处于同一文档流下的某一祖先元素。
从而恢复正常显示
| 特性 | 作用 |
|---|---|
false |
不启用 |
Element |
某个DOM元素 |
贴纸抽象了设计了CSS变量,以方便调整显示
| CSS变量 | 作用 | 默认值 |
|---|---|---|
--app-tip-text |
base主题下的文字颜色 | var(--gray-text1) |
--app-tip-back |
base主题下的背景颜色 | var(--main-comp2) |
--app-tip-arrow-size |
箭头尺寸 | 4px |