组件/Fusion 交融
通用组件

Fusion 交融

两个元素交融与分开的视觉组件。

该页面由 AI 迁移生成,请谨慎使用

内容已迁移完成,但仍建议结合源码和人工评审结果使用。

Fusion 交融

两个元素交融与分开的视觉组件。

基础用法

Fusion

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

const active = ref(false)
</script>

<template>
  <div style="display: grid; gap: 12px; width: 520px;">
    <div style="display: flex; gap: 8px; align-items: center;">
      <TxButton type="primary" @click="active = !active">
        Toggle
      </TxButton>
      <div style="font-size: 12px; color: var(--tx-text-color-secondary);">
        Click button or hover the fusion area
      </div>
    </div>

    <div
      style="
        height: 320px;
        border-radius: 16px;
        background: radial-gradient(120% 120% at 20% 30%, rgba(20, 90, 130, 0.95), rgba(10, 30, 80, 0.95));
        display: grid;
        place-items: center;
        overflow: hidden;
      "
    >
      <TxFusion v-model="active" trigger="hover" :gap="240" :blur="19" :alpha="29" :alpha-offset="-10">
        <template #a>
          <div
            style="
              width: 260px;
              height: 260px;
              border-radius: 999px;
              background: hsla(256, 65%, 60%, 0.76);
            "
          />
        </template>

        <template #b>
          <div
            style="
              width: 110px;
              height: 110px;
              border-radius: 999px;
              background: hsla(77, 100%, 55%, 0.78);
            "
          />
        </template>
      </TxFusion>
    </div>

    <TxFusion :gap="46" direction="y" trigger="click" :blur="19" :alpha="29" :alpha-offset="-10">
      <template #a>
        <div
          style="
            width: 92px;
            height: 56px;
            border-radius: 999px;
            background: color-mix(in srgb, var(--tx-color-primary, #409eff) 66%, rgba(255, 255, 255, 0.20));
            box-shadow: 0 18px 42px rgba(0, 0, 0, 0.14);
          "
        />
      </template>

      <template #b>
        <div
          style="
            width: 92px;
            height: 56px;
            border-radius: 999px;
            background: color-mix(in srgb, var(--tx-color-success, #67c23a) 66%, rgba(255, 255, 255, 0.20));
            box-shadow: 0 18px 42px rgba(0, 0, 0, 0.14);
          "
        />
      </template>
    </TxFusion>
  </div>
</template>

实际场景

Button + Tooltip Bubble

Fusion ButtonTooltip

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

const active = ref(false)
</script>

<template>
  <div
    style="
      width: 560px;
      border-radius: 16px;
      padding: 18px;
      background:
        linear-gradient(180deg, color-mix(in srgb, var(--tx-bg-color-overlay, #fff) 92%, transparent), color-mix(in srgb, var(--tx-bg-color-overlay, #fff) 84%, transparent));
      border: 1px solid var(--vp-c-divider);
      display: grid;
      gap: 12px;
    "
  >
    <div style="display: flex; gap: 8px; align-items: center;">
      <TxButton size="small" type="primary" @click="active = !active">
        Toggle
      </TxButton>
      <div style="font-size: 12px; color: var(--tx-text-color-secondary);">
        Hover the group or toggle
      </div>
    </div>

    <div style="display: grid; place-items: center; padding: 18px;">
      <TxFusion v-model="active" trigger="hover" :gap="44" direction="y" :duration="260" :blur="19" :alpha="29" :alpha-offset="-10">
        <template #a>
          <div
            style="
              display: inline-flex;
              align-items: center;
              gap: 10px;
              padding: 10px 14px;
              border-radius: 999px;
              background: color-mix(in srgb, var(--tx-color-primary, #409eff) 76%, rgba(255, 255, 255, 0.10));
              color: #fff;
              box-shadow: 0 12px 26px rgba(0, 0, 0, 0.18);
              font-weight: 600;
              letter-spacing: 0.2px;
              user-select: none;
            "
          >
            <span style="font-size: 13px; line-height: 1;">Save</span>
            <span
              style="
                font-size: 11px;
                line-height: 1;
                padding: 4px 8px;
                border-radius: 999px;
                background: rgba(255, 255, 255, 0.16);
                border: 1px solid rgba(255, 255, 255, 0.22);
                opacity: 0.95;
              "
            >
              ⌘S
            </span>
          </div>
        </template>

        <template #b>
          <div
            style="
              padding: 8px 10px;
              border-radius: 999px;
              background: color-mix(in srgb, var(--tx-bg-color-overlay, #fff) 18%, transparent);
              border: 1px solid color-mix(in srgb, var(--tx-border-color-light, #e4e7ed) 70%, transparent);
              backdrop-filter: blur(14px) saturate(160%);
              -webkit-backdrop-filter: blur(14px) saturate(160%);
              color: var(--tx-text-color-primary, #303133);
              font-size: 12px;
              box-shadow: 0 14px 36px rgba(0, 0, 0, 0.12);
              user-select: none;
              white-space: nowrap;
            "
          >
            Saved to drafts
          </div>
        </template>
      </TxFusion>
    </div>
  </div>
</template>

Two Buttons

Fusion TwoButtons

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

type Variant = 'membrane' | 'glass' | 'gummy'

const active = ref<Record<Variant, boolean>>({
  membrane: true,
  glass: true,
  gummy: true,
})

const variants: Array<{ key: Variant, title: string, hint: string }> = [
  { key: 'membrane', title: 'Membrane', hint: 'softer rim / cell-like' },
  { key: 'glass', title: 'Glass', hint: 'ui-ish / translucent' },
  { key: 'gummy', title: 'Gummy', hint: 'strong / candy' },
]
</script>

<template>
  <div
    style="
      width: 560px;
      border-radius: 16px;
      padding: 18px;
      background:
        radial-gradient(140% 120% at 10% 0%, rgba(129, 230, 217, 0.14), transparent 60%),
        radial-gradient(120% 120% at 90% 10%, rgba(250, 204, 21, 0.12), transparent 55%),
        linear-gradient(180deg, rgba(10, 12, 18, 0.92), rgba(10, 12, 18, 0.86));
      border: 1px solid rgba(255, 255, 255, 0.10);
      display: grid;
      gap: 12px;
    "
  >
    <div style="display: flex; gap: 8px; align-items: center; flex-wrap: wrap;">
      <TxButton size="small" @click="active.membrane = !active.membrane">
        Toggle membrane
      </TxButton>
      <TxButton size="small" @click="active.glass = !active.glass">
        Toggle glass
      </TxButton>
      <TxButton size="small" @click="active.gummy = !active.gummy">
        Toggle gummy
      </TxButton>
    </div>

    <div style="display: grid; gap: 14px;">
      <div
        v-for="item in variants"
        :key="item.key"
        style="
          display: grid;
          grid-template-columns: 120px 1fr;
          align-items: center;
          gap: 12px;
          padding: 12px;
          border-radius: 14px;
          background: rgba(255, 255, 255, 0.04);
          border: 1px solid rgba(255, 255, 255, 0.10);
        "
      >
        <div style="display: grid; gap: 4px;">
          <div style="font-size: 12px; font-weight: 700; color: rgba(255, 255, 255, 0.92);">
            {{ item.title }}
          </div>
          <div style="font-size: 11px; color: rgba(255, 255, 255, 0.60);">
            {{ item.hint }}
          </div>
        </div>

        <div style="display: grid; place-items: center;">
          <TxFusion
            v-model="active[item.key]"
            trigger="hover"
            :gap="56"
            direction="x"
            :duration="260"
            :blur="19"
            :alpha="29"
            :alpha-offset="-10"
          >
            <template #a>
              <div
                v-if="item.key === 'membrane'"
                style="
                  padding: 10px 14px;
                  border-radius: 999px;
                  background:
                    radial-gradient(120% 120% at 30% 20%, rgba(255, 255, 255, 0.34), rgba(255, 255, 255, 0.06)),
                    linear-gradient(135deg, rgba(56, 189, 248, 0.78), rgba(167, 139, 250, 0.66));
                  border: 1px solid rgba(255, 255, 255, 0.18);
                  color: rgba(255, 255, 255, 0.92);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.32);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  user-select: none;
                  display: inline-flex;
                  align-items: center;
                  gap: 8px;
                "
              >
                <span style="font-size: 13px; font-weight: 700;">Primary</span>
              </div>

              <div
                v-else-if="item.key === 'glass'"
                style="
                  padding: 10px 14px;
                  border-radius: 999px;
                  background: rgba(255, 255, 255, 0.12);
                  border: 1px solid rgba(255, 255, 255, 0.18);
                  color: rgba(255, 255, 255, 0.92);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.28);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  user-select: none;
                  display: inline-flex;
                  align-items: center;
                  gap: 8px;
                "
              >
                <span style="font-size: 13px; font-weight: 700;">Cancel</span>
              </div>

              <div
                v-else
                style="
                  padding: 10px 14px;
                  border-radius: 999px;
                  background:
                    radial-gradient(120% 120% at 30% 20%, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.02)),
                    linear-gradient(135deg, rgba(34, 197, 94, 0.78), rgba(59, 130, 246, 0.82));
                  color: rgba(255, 255, 255, 0.95);
                  box-shadow: 0 18px 54px rgba(0, 0, 0, 0.36);
                  user-select: none;
                  display: inline-flex;
                  align-items: center;
                  gap: 8px;
                  font-weight: 700;
                "
              >
                Action
              </div>
            </template>

            <template #b>
              <div
                v-if="item.key === 'membrane'"
                style="
                  padding: 10px 14px;
                  border-radius: 999px;
                  background:
                    radial-gradient(120% 120% at 30% 20%, rgba(255, 255, 255, 0.30), rgba(255, 255, 255, 0.06)),
                    linear-gradient(135deg, rgba(14, 165, 233, 0.76), rgba(244, 114, 182, 0.70));
                  border: 1px solid rgba(255, 255, 255, 0.18);
                  color: rgba(255, 255, 255, 0.92);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.32);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  user-select: none;
                  display: inline-flex;
                  align-items: center;
                  gap: 8px;
                "
              >
                <span style="font-size: 13px; font-weight: 700;">Secondary</span>
              </div>

              <div
                v-else-if="item.key === 'glass'"
                style="
                  padding: 10px 14px;
                  border-radius: 999px;
                  background: rgba(255, 255, 255, 0.12);
                  border: 1px solid rgba(255, 255, 255, 0.18);
                  color: rgba(255, 255, 255, 0.92);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.28);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  user-select: none;
                  display: inline-flex;
                  align-items: center;
                  gap: 8px;
                "
              >
                <span style="font-size: 13px; font-weight: 700;">OK</span>
              </div>

              <div
                v-else
                style="
                  padding: 10px 14px;
                  border-radius: 999px;
                  background:
                    radial-gradient(120% 120% at 30% 20%, rgba(255, 255, 255, 0.20), rgba(255, 255, 255, 0.02)),
                    linear-gradient(135deg, rgba(244, 63, 94, 0.80), rgba(249, 115, 22, 0.80));
                  color: rgba(255, 255, 255, 0.95);
                  box-shadow: 0 18px 54px rgba(0, 0, 0, 0.36);
                  user-select: none;
                  display: inline-flex;
                  align-items: center;
                  gap: 8px;
                  font-weight: 700;
                "
              >
                Danger
              </div>
            </template>
          </TxFusion>
        </div>
      </div>
    </div>
  </div>
</template>

Two Options

Fusion TwoOptions

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

type Variant = 'membrane' | 'glass' | 'gummy'

const active = ref<Record<Variant, boolean>>({
  membrane: false,
  glass: false,
  gummy: false,
})

const variants: Array<{ key: Variant, title: string, hint: string }> = [
  { key: 'membrane', title: 'Membrane', hint: 'soft merge between two pills' },
  { key: 'glass', title: 'Glass', hint: 'option group in UI' },
  { key: 'gummy', title: 'Gummy', hint: 'strong / playful' },
]
</script>

<template>
  <div
    style="
      width: 560px;
      border-radius: 16px;
      padding: 18px;
      background:
        radial-gradient(140% 120% at 10% 0%, rgba(129, 230, 217, 0.14), transparent 60%),
        radial-gradient(120% 120% at 90% 10%, rgba(250, 204, 21, 0.12), transparent 55%),
        linear-gradient(180deg, rgba(10, 12, 18, 0.92), rgba(10, 12, 18, 0.86));
      border: 1px solid rgba(255, 255, 255, 0.10);
      display: grid;
      gap: 12px;
    "
  >
    <div style="display: flex; gap: 8px; align-items: center; flex-wrap: wrap;">
      <TxButton size="small" @click="active.membrane = !active.membrane">
        Toggle membrane
      </TxButton>
      <TxButton size="small" @click="active.glass = !active.glass">
        Toggle glass
      </TxButton>
      <TxButton size="small" @click="active.gummy = !active.gummy">
        Toggle gummy
      </TxButton>
    </div>

    <div style="display: grid; gap: 14px;">
      <div
        v-for="item in variants"
        :key="item.key"
        style="
          display: grid;
          grid-template-columns: 120px 1fr;
          align-items: center;
          gap: 12px;
          padding: 12px;
          border-radius: 14px;
          background: rgba(255, 255, 255, 0.04);
          border: 1px solid rgba(255, 255, 255, 0.10);
        "
      >
        <div style="display: grid; gap: 4px;">
          <div style="font-size: 12px; font-weight: 700; color: rgba(255, 255, 255, 0.92);">
            {{ item.title }}
          </div>
          <div style="font-size: 11px; color: rgba(255, 255, 255, 0.60);">
            {{ item.hint }}
          </div>
        </div>

        <div style="display: grid; place-items: center;">
          <TxFusion
            v-model="active[item.key]"
            trigger="hover"
            :gap="62"
            direction="x"
            :duration="260"
            :blur="19"
            :alpha="29"
            :alpha-offset="-10"
          >
            <template #a>
              <div
                v-if="item.key === 'membrane'"
                style="
                  width: 156px;
                  height: 42px;
                  border-radius: 999px;
                  background:
                    radial-gradient(120% 120% at 30% 20%, rgba(255, 255, 255, 0.34), rgba(255, 255, 255, 0.06)),
                    linear-gradient(135deg, rgba(56, 189, 248, 0.78), rgba(167, 139, 250, 0.66));
                  border: 1px solid rgba(255, 255, 255, 0.18);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.32);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  display: grid;
                  place-items: center;
                  color: rgba(255, 255, 255, 0.92);
                  font-size: 12px;
                  font-weight: 800;
                  user-select: none;
                "
              >
                Option A
              </div>

              <div
                v-else-if="item.key === 'glass'"
                style="
                  width: 156px;
                  height: 42px;
                  border-radius: 999px;
                  background: rgba(255, 255, 255, 0.12);
                  border: 1px solid rgba(255, 255, 255, 0.18);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.28);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  display: grid;
                  place-items: center;
                  color: rgba(255, 255, 255, 0.92);
                  font-size: 12px;
                  font-weight: 800;
                  user-select: none;
                "
              >
                Light
              </div>

              <div
                v-else
                style="
                  width: 156px;
                  height: 42px;
                  border-radius: 999px;
                  background:
                    radial-gradient(120% 120% at 30% 20%, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.02)),
                    linear-gradient(135deg, rgba(34, 197, 94, 0.78), rgba(59, 130, 246, 0.82));
                  box-shadow: 0 18px 54px rgba(0, 0, 0, 0.36);
                  display: grid;
                  place-items: center;
                  color: rgba(255, 255, 255, 0.95);
                  font-size: 12px;
                  font-weight: 900;
                  user-select: none;
                "
              >
                Monthly
              </div>
            </template>

            <template #b>
              <div
                v-if="item.key === 'membrane'"
                style="
                  width: 156px;
                  height: 42px;
                  border-radius: 999px;
                  background:
                    radial-gradient(120% 120% at 30% 20%, rgba(255, 255, 255, 0.30), rgba(255, 255, 255, 0.06)),
                    linear-gradient(135deg, rgba(14, 165, 233, 0.76), rgba(244, 114, 182, 0.70));
                  border: 1px solid rgba(255, 255, 255, 0.18);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.32);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  display: grid;
                  place-items: center;
                  color: rgba(255, 255, 255, 0.92);
                  font-size: 12px;
                  font-weight: 800;
                  user-select: none;
                "
              >
                Option B
              </div>

              <div
                v-else-if="item.key === 'glass'"
                style="
                  width: 156px;
                  height: 42px;
                  border-radius: 999px;
                  background: rgba(255, 255, 255, 0.12);
                  border: 1px solid rgba(255, 255, 255, 0.18);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.28);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  display: grid;
                  place-items: center;
                  color: rgba(255, 255, 255, 0.92);
                  font-size: 12px;
                  font-weight: 800;
                  user-select: none;
                "
              >
                Dark
              </div>

              <div
                v-else
                style="
                  width: 156px;
                  height: 42px;
                  border-radius: 999px;
                  background:
                    radial-gradient(120% 120% at 30% 20%, rgba(255, 255, 255, 0.20), rgba(255, 255, 255, 0.02)),
                    linear-gradient(135deg, rgba(34, 211, 238, 0.78), rgba(99, 102, 241, 0.82));
                  box-shadow: 0 18px 54px rgba(0, 0, 0, 0.36);
                  display: grid;
                  place-items: center;
                  color: rgba(255, 255, 255, 0.95);
                  font-size: 12px;
                  font-weight: 900;
                  user-select: none;
                "
              >
                Yearly
              </div>
            </template>
          </TxFusion>
        </div>
      </div>
    </div>
  </div>
</template>

Two Chips

Fusion TwoChips

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

type Variant = 'membrane' | 'glass' | 'gummy'

const active = ref<Record<Variant, boolean>>({
  membrane: true,
  glass: true,
  gummy: true,
})

const variants: Array<{ key: Variant, title: string, hint: string }> = [
  { key: 'membrane', title: 'Membrane', hint: 'tag pair / segmented filter' },
  { key: 'glass', title: 'Glass', hint: 'ui-ish / premium' },
  { key: 'gummy', title: 'Gummy', hint: 'strong / playful' },
]
</script>

<template>
  <div
    style="
      width: 560px;
      border-radius: 16px;
      padding: 18px;
      background:
        radial-gradient(140% 120% at 10% 0%, rgba(129, 230, 217, 0.14), transparent 60%),
        radial-gradient(120% 120% at 90% 10%, rgba(250, 204, 21, 0.12), transparent 55%),
        linear-gradient(180deg, rgba(10, 12, 18, 0.92), rgba(10, 12, 18, 0.86));
      border: 1px solid rgba(255, 255, 255, 0.10);
      display: grid;
      gap: 12px;
    "
  >
    <div style="display: flex; gap: 8px; align-items: center; flex-wrap: wrap;">
      <TxButton size="small" @click="active.membrane = !active.membrane">
        Toggle membrane
      </TxButton>
      <TxButton size="small" @click="active.glass = !active.glass">
        Toggle glass
      </TxButton>
      <TxButton size="small" @click="active.gummy = !active.gummy">
        Toggle gummy
      </TxButton>
    </div>

    <div style="display: grid; gap: 14px;">
      <div
        v-for="item in variants"
        :key="item.key"
        style="
          display: grid;
          grid-template-columns: 120px 1fr;
          align-items: center;
          gap: 12px;
          padding: 12px;
          border-radius: 14px;
          background: rgba(255, 255, 255, 0.04);
          border: 1px solid rgba(255, 255, 255, 0.10);
        "
      >
        <div style="display: grid; gap: 4px;">
          <div style="font-size: 12px; font-weight: 700; color: rgba(255, 255, 255, 0.92);">
            {{ item.title }}
          </div>
          <div style="font-size: 11px; color: rgba(255, 255, 255, 0.60);">
            {{ item.hint }}
          </div>
        </div>

        <div style="display: grid; place-items: center;">
          <TxFusion
            v-model="active[item.key]"
            trigger="hover"
            :gap="72"
            direction="x"
            :duration="260"
            :blur="19"
            :alpha="29"
            :alpha-offset="-10"
          >
            <template #a>
              <div
                v-if="item.key === 'membrane'"
                style="
                  height: 34px;
                  padding: 0 12px;
                  border-radius: 999px;
                  background:
                    radial-gradient(120% 120% at 30% 20%, rgba(255, 255, 255, 0.34), rgba(255, 255, 255, 0.06)),
                    linear-gradient(135deg, rgba(56, 189, 248, 0.72), rgba(167, 139, 250, 0.60));
                  border: 1px solid rgba(255, 255, 255, 0.18);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.30);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  display: inline-flex;
                  align-items: center;
                  gap: 8px;
                  color: rgba(255, 255, 255, 0.92);
                  font-size: 12px;
                  font-weight: 800;
                  user-select: none;
                "
              >
                iOS
              </div>

              <div
                v-else-if="item.key === 'glass'"
                style="
                  height: 34px;
                  padding: 0 12px;
                  border-radius: 999px;
                  background: rgba(255, 255, 255, 0.12);
                  border: 1px solid rgba(255, 255, 255, 0.18);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.28);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  display: inline-flex;
                  align-items: center;
                  gap: 8px;
                  color: rgba(255, 255, 255, 0.92);
                  font-size: 12px;
                  font-weight: 800;
                  user-select: none;
                "
              >
                Feature
              </div>

              <div
                v-else
                style="
                  height: 34px;
                  padding: 0 12px;
                  border-radius: 999px;
                  background:
                    radial-gradient(120% 120% at 30% 20%, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.02)),
                    linear-gradient(135deg, rgba(34, 197, 94, 0.76), rgba(59, 130, 246, 0.80));
                  box-shadow: 0 18px 54px rgba(0, 0, 0, 0.34);
                  display: inline-flex;
                  align-items: center;
                  color: rgba(255, 255, 255, 0.95);
                  font-size: 12px;
                  font-weight: 900;
                  user-select: none;
                "
              >
                Stable
              </div>
            </template>

            <template #b>
              <div
                v-if="item.key === 'membrane'"
                style="
                  height: 34px;
                  padding: 0 12px;
                  border-radius: 999px;
                  background:
                    radial-gradient(120% 120% at 30% 20%, rgba(255, 255, 255, 0.30), rgba(255, 255, 255, 0.06)),
                    linear-gradient(135deg, rgba(14, 165, 233, 0.70), rgba(244, 114, 182, 0.64));
                  border: 1px solid rgba(255, 255, 255, 0.18);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.30);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  display: inline-flex;
                  align-items: center;
                  gap: 8px;
                  color: rgba(255, 255, 255, 0.92);
                  font-size: 12px;
                  font-weight: 800;
                  user-select: none;
                "
              >
                Android
              </div>

              <div
                v-else-if="item.key === 'glass'"
                style="
                  height: 34px;
                  padding: 0 12px;
                  border-radius: 999px;
                  background: rgba(255, 255, 255, 0.12);
                  border: 1px solid rgba(255, 255, 255, 0.18);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.28);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  display: inline-flex;
                  align-items: center;
                  gap: 8px;
                  color: rgba(255, 255, 255, 0.92);
                  font-size: 12px;
                  font-weight: 800;
                  user-select: none;
                "
              >
                Bugfix
              </div>

              <div
                v-else
                style="
                  height: 34px;
                  padding: 0 12px;
                  border-radius: 999px;
                  background:
                    radial-gradient(120% 120% at 30% 20%, rgba(255, 255, 255, 0.20), rgba(255, 255, 255, 0.02)),
                    linear-gradient(135deg, rgba(244, 63, 94, 0.80), rgba(249, 115, 22, 0.80));
                  box-shadow: 0 18px 54px rgba(0, 0, 0, 0.34);
                  display: inline-flex;
                  align-items: center;
                  color: rgba(255, 255, 255, 0.95);
                  font-size: 12px;
                  font-weight: 900;
                  user-select: none;
                "
              >
                Beta
              </div>
            </template>
          </TxFusion>
        </div>
      </div>
    </div>
  </div>
</template>

Two Status Dots

Fusion TwoStatusDots

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

type Variant = 'membrane' | 'glass' | 'gummy'

const active = ref<Record<Variant, boolean>>({
  membrane: true,
  glass: true,
  gummy: true,
})

const variants: Array<{ key: Variant, title: string, hint: string }> = [
  { key: 'membrane', title: 'Membrane', hint: 'status dots + labels' },
  { key: 'glass', title: 'Glass', hint: 'ui-ish / subtle' },
  { key: 'gummy', title: 'Gummy', hint: 'strong / playful' },
]
</script>

<template>
  <div
    style="
      width: 560px;
      border-radius: 16px;
      padding: 18px;
      background:
        radial-gradient(140% 120% at 10% 0%, rgba(129, 230, 217, 0.14), transparent 60%),
        radial-gradient(120% 120% at 90% 10%, rgba(250, 204, 21, 0.12), transparent 55%),
        linear-gradient(180deg, rgba(10, 12, 18, 0.92), rgba(10, 12, 18, 0.86));
      border: 1px solid rgba(255, 255, 255, 0.10);
      display: grid;
      gap: 12px;
    "
  >
    <div style="display: flex; gap: 8px; align-items: center; flex-wrap: wrap;">
      <TxButton size="small" @click="active.membrane = !active.membrane">
        Toggle membrane
      </TxButton>
      <TxButton size="small" @click="active.glass = !active.glass">
        Toggle glass
      </TxButton>
      <TxButton size="small" @click="active.gummy = !active.gummy">
        Toggle gummy
      </TxButton>
    </div>

    <div style="display: grid; gap: 14px;">
      <div
        v-for="item in variants"
        :key="item.key"
        style="
          display: grid;
          grid-template-columns: 120px 1fr;
          align-items: center;
          gap: 12px;
          padding: 12px;
          border-radius: 14px;
          background: rgba(255, 255, 255, 0.04);
          border: 1px solid rgba(255, 255, 255, 0.10);
        "
      >
        <div style="display: grid; gap: 4px;">
          <div style="font-size: 12px; font-weight: 700; color: rgba(255, 255, 255, 0.92);">
            {{ item.title }}
          </div>
          <div style="font-size: 11px; color: rgba(255, 255, 255, 0.60);">
            {{ item.hint }}
          </div>
        </div>

        <div style="display: grid; place-items: center;">
          <TxFusion
            v-model="active[item.key]"
            trigger="hover"
            :gap="68"
            direction="x"
            :duration="260"
            :blur="19"
            :alpha="29"
            :alpha-offset="-10"
          >
            <template #a>
              <div
                style="
                  height: 38px;
                  padding: 0 12px;
                  border-radius: 999px;
                  display: inline-flex;
                  align-items: center;
                  gap: 10px;
                  user-select: none;
                  border: 1px solid rgba(255, 255, 255, 0.16);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.30);
                "
                :style="
                  item.key === 'glass'
                    ? { background: 'rgba(255, 255, 255, 0.12)', color: 'rgba(255, 255, 255, 0.92)' }
                    : item.key === 'membrane'
                      ? { background: 'linear-gradient(135deg, rgba(56, 189, 248, 0.78), rgba(167, 139, 250, 0.66))', color: 'rgba(255, 255, 255, 0.92)' }
                      : { background: 'linear-gradient(135deg, rgba(34, 197, 94, 0.78), rgba(59, 130, 246, 0.82))', color: 'rgba(255, 255, 255, 0.95)' }
                "
              >
                <span
                  style="
                    width: 10px;
                    height: 10px;
                    border-radius: 999px;
                    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.10);
                  "
                  :style="
                    item.key === 'glass'
                      ? { background: 'rgba(255, 255, 255, 0.70)' }
                      : item.key === 'membrane'
                        ? { background: 'rgba(129, 230, 217, 0.95)' }
                        : { background: 'rgba(34, 197, 94, 0.95)' }
                  "
                />
                Online
              </div>
            </template>

            <template #b>
              <div
                style="
                  height: 38px;
                  padding: 0 12px;
                  border-radius: 999px;
                  display: inline-flex;
                  align-items: center;
                  gap: 10px;
                  user-select: none;
                  border: 1px solid rgba(255, 255, 255, 0.16);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.30);
                "
                :style="
                  item.key === 'glass'
                    ? { background: 'rgba(255, 255, 255, 0.12)', color: 'rgba(255, 255, 255, 0.92)' }
                    : item.key === 'membrane'
                      ? { background: 'linear-gradient(135deg, rgba(14, 165, 233, 0.76), rgba(244, 114, 182, 0.70))', color: 'rgba(255, 255, 255, 0.92)' }
                      : { background: 'linear-gradient(135deg, rgba(244, 63, 94, 0.80), rgba(249, 115, 22, 0.80))', color: 'rgba(255, 255, 255, 0.95)' }
                "
              >
                <span
                  style="
                    width: 10px;
                    height: 10px;
                    border-radius: 999px;
                    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.10);
                  "
                  :style="
                    item.key === 'glass'
                      ? { background: 'rgba(255, 255, 255, 0.70)' }
                      : item.key === 'membrane'
                        ? { background: 'rgba(244, 114, 182, 0.95)' }
                        : { background: 'rgba(244, 63, 94, 0.95)' }
                  "
                />
                Offline
              </div>
            </template>
          </TxFusion>
        </div>
      </div>
    </div>
  </div>
</template>

Two Icon Buttons

Fusion TwoIconButtons

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

type Variant = 'membrane' | 'glass' | 'gummy'

const active = ref<Record<Variant, boolean>>({
  membrane: true,
  glass: true,
  gummy: true,
})

const variants: Array<{ key: Variant, title: string, hint: string }> = [
  { key: 'membrane', title: 'Membrane', hint: 'icon buttons (like/save)' },
  { key: 'glass', title: 'Glass', hint: 'ui-ish / subtle' },
  { key: 'gummy', title: 'Gummy', hint: 'strong / playful' },
]
</script>

<template>
  <div
    style="
      width: 560px;
      border-radius: 16px;
      padding: 18px;
      background:
        radial-gradient(140% 120% at 10% 0%, rgba(129, 230, 217, 0.14), transparent 60%),
        radial-gradient(120% 120% at 90% 10%, rgba(250, 204, 21, 0.12), transparent 55%),
        linear-gradient(180deg, rgba(10, 12, 18, 0.92), rgba(10, 12, 18, 0.86));
      border: 1px solid rgba(255, 255, 255, 0.10);
      display: grid;
      gap: 12px;
    "
  >
    <div style="display: flex; gap: 8px; align-items: center; flex-wrap: wrap;">
      <TxButton size="small" @click="active.membrane = !active.membrane">
        Toggle membrane
      </TxButton>
      <TxButton size="small" @click="active.glass = !active.glass">
        Toggle glass
      </TxButton>
      <TxButton size="small" @click="active.gummy = !active.gummy">
        Toggle gummy
      </TxButton>
    </div>

    <div style="display: grid; gap: 14px;">
      <div
        v-for="item in variants"
        :key="item.key"
        style="
          display: grid;
          grid-template-columns: 120px 1fr;
          align-items: center;
          gap: 12px;
          padding: 12px;
          border-radius: 14px;
          background: rgba(255, 255, 255, 0.04);
          border: 1px solid rgba(255, 255, 255, 0.10);
        "
      >
        <div style="display: grid; gap: 4px;">
          <div style="font-size: 12px; font-weight: 700; color: rgba(255, 255, 255, 0.92);">
            {{ item.title }}
          </div>
          <div style="font-size: 11px; color: rgba(255, 255, 255, 0.60);">
            {{ item.hint }}
          </div>
        </div>

        <div style="display: grid; place-items: center;">
          <TxFusion
            v-model="active[item.key]"
            trigger="hover"
            :gap="74"
            direction="x"
            :duration="260"
            :blur="19"
            :alpha="29"
            :alpha-offset="-10"
          >
            <template #a>
              <div
                style="
                  width: 48px;
                  height: 48px;
                  border-radius: 999px;
                  display: grid;
                  place-items: center;
                  user-select: none;
                  border: 1px solid rgba(255, 255, 255, 0.16);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.30);
                  font-weight: 900;
                  font-size: 18px;
                "
                :style="
                  item.key === 'glass'
                    ? { background: 'rgba(255, 255, 255, 0.12)', color: 'rgba(255, 255, 255, 0.92)' }
                    : item.key === 'membrane'
                      ? { background: 'linear-gradient(135deg, rgba(56, 189, 248, 0.78), rgba(167, 139, 250, 0.66))', color: 'rgba(255, 255, 255, 0.92)' }
                      : { background: 'linear-gradient(135deg, rgba(244, 63, 94, 0.82), rgba(249, 115, 22, 0.82))', color: 'rgba(255, 255, 255, 0.95)' }
                "
              >
                ♥
              </div>
            </template>

            <template #b>
              <div
                style="
                  width: 48px;
                  height: 48px;
                  border-radius: 999px;
                  display: grid;
                  place-items: center;
                  user-select: none;
                  border: 1px solid rgba(255, 255, 255, 0.16);
                  backdrop-filter: blur(16px) saturate(160%);
                  -webkit-backdrop-filter: blur(16px) saturate(160%);
                  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.30);
                  font-weight: 900;
                  font-size: 18px;
                "
                :style="
                  item.key === 'glass'
                    ? { background: 'rgba(255, 255, 255, 0.12)', color: 'rgba(255, 255, 255, 0.92)' }
                    : item.key === 'membrane'
                      ? { background: 'linear-gradient(135deg, rgba(14, 165, 233, 0.76), rgba(244, 114, 182, 0.70))', color: 'rgba(255, 255, 255, 0.92)' }
                      : { background: 'linear-gradient(135deg, rgba(34, 197, 94, 0.78), rgba(59, 130, 246, 0.82))', color: 'rgba(255, 255, 255, 0.95)' }
                "
              >
                ⌁
              </div>
            </template>
          </TxFusion>
        </div>
      </div>
    </div>
  </div>
</template>

Avatar + Badge

Fusion AvatarBadge

示例即将加载...
<template>
  <div
    style="
      width: 560px;
      border-radius: 16px;
      padding: 18px;
      background:
        radial-gradient(120% 120% at 20% 20%, color-mix(in srgb, var(--tx-bg-color-overlay, #fff) 92%, transparent), color-mix(in srgb, var(--tx-bg-color-overlay, #fff) 78%, transparent));
      border: 1px solid var(--vp-c-divider);
      display: grid;
      place-items: center;
    "
  >
    <TxFusion trigger="hover" :gap="64" :duration="260" :blur="19" :alpha="29" :alpha-offset="-10">
      <template #a>
        <div
          style="
            width: 84px;
            height: 84px;
            border-radius: 999px;
            background: linear-gradient(135deg, color-mix(in srgb, var(--tx-color-primary, #409eff) 70%, #fff), color-mix(in srgb, var(--tx-color-primary, #409eff) 30%, #000));
            box-shadow: 0 16px 42px rgba(0, 0, 0, 0.16);
            display: grid;
            place-items: center;
            color: rgba(255, 255, 255, 0.92);
            font-weight: 700;
            letter-spacing: 0.4px;
            user-select: none;
          "
        >
          TA
        </div>
      </template>

      <template #b>
        <div
          style="
            width: 34px;
            height: 34px;
            border-radius: 999px;
            background: color-mix(in srgb, var(--tx-color-danger, #f56c6c) 78%, rgba(255, 255, 255, 0.10));
            box-shadow: 0 12px 28px rgba(0, 0, 0, 0.18);
            display: grid;
            place-items: center;
            color: rgba(255, 255, 255, 0.94);
            font-size: 12px;
            font-weight: 700;
            user-select: none;
          "
        >
          8
        </div>
      </template>
    </TxFusion>
  </div>
</template>

Chip + Icon

Fusion ChipIcon

示例即将加载...
<template>
  <div
    style="
      width: 560px;
      border-radius: 16px;
      padding: 18px;
      background:
        linear-gradient(180deg, color-mix(in srgb, var(--tx-bg-color-overlay, #fff) 92%, transparent), color-mix(in srgb, var(--tx-bg-color-overlay, #fff) 86%, transparent));
      border: 1px solid var(--vp-c-divider);
      display: grid;
      place-items: center;
    "
  >
    <TxFusion trigger="hover" :gap="54" :duration="260" :blur="19" :alpha="29" :alpha-offset="-10">
      <template #a>
        <div
          style="
            display: inline-flex;
            align-items: center;
            gap: 10px;
            padding: 10px 14px;
            border-radius: 999px;
            background: color-mix(in srgb, var(--tx-bg-color-overlay, #fff) 26%, transparent);
            border: 1px solid color-mix(in srgb, var(--tx-border-color-light, #e4e7ed) 72%, transparent);
            backdrop-filter: blur(14px) saturate(160%);
            -webkit-backdrop-filter: blur(14px) saturate(160%);
            box-shadow: 0 14px 36px rgba(0, 0, 0, 0.12);
            user-select: none;
          "
        >
          <span
            style="
              width: 22px;
              height: 22px;
              border-radius: 8px;
              background: color-mix(in srgb, var(--tx-color-success, #67c23a) 66%, rgba(255, 255, 255, 0.14));
              box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.22);
            "
          />
          <span style="font-size: 13px; color: var(--tx-text-color-primary, #303133); font-weight: 600;">Synced</span>
        </div>
      </template>

      <template #b>
        <div
          style="
            width: 40px;
            height: 40px;
            border-radius: 999px;
            background: color-mix(in srgb, var(--tx-color-success, #67c23a) 70%, rgba(255, 255, 255, 0.10));
            box-shadow: 0 14px 34px rgba(0, 0, 0, 0.16);
            display: grid;
            place-items: center;
            color: rgba(255, 255, 255, 0.95);
            font-weight: 900;
            user-select: none;
          "
        >
          ✓
        </div>
      </template>
    </TxFusion>
  </div>
</template>

Mini Card + FAB

Fusion MiniCardFab

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

const active = ref(false)
</script>

<template>
  <div
    style="
      width: 560px;
      border-radius: 16px;
      padding: 18px;
      background:
        radial-gradient(120% 120% at 10% 20%, color-mix(in srgb, var(--tx-bg-color-overlay, #fff) 92%, transparent), color-mix(in srgb, var(--tx-bg-color-overlay, #fff) 82%, transparent));
      border: 1px solid var(--vp-c-divider);
      display: grid;
      gap: 12px;
    "
  >
    <div style="display: flex; gap: 8px; align-items: center;">
      <TxButton size="small" @click="active = !active">
        Toggle
      </TxButton>
      <div style="font-size: 12px; color: var(--tx-text-color-secondary);">
        Card + Floating Action
      </div>
    </div>

    <div style="display: grid; place-items: center; padding: 18px;">
      <TxFusion v-model="active" trigger="hover" :gap="92" :duration="260" :blur="19" :alpha="29" :alpha-offset="-10">
        <template #a>
          <div
            style="
              width: 320px;
              height: 108px;
              border-radius: 18px;
              background: color-mix(in srgb, var(--tx-bg-color-overlay, #fff) 22%, transparent);
              border: 1px solid color-mix(in srgb, var(--tx-border-color-light, #e4e7ed) 70%, transparent);
              backdrop-filter: blur(18px) saturate(160%);
              -webkit-backdrop-filter: blur(18px) saturate(160%);
              box-shadow: 0 18px 48px rgba(0, 0, 0, 0.12);
              padding: 14px 16px;
              display: grid;
              gap: 6px;
              align-content: center;
              user-select: none;
            "
          >
            <div style="font-size: 13px; font-weight: 700; color: var(--tx-text-color-primary, #303133);">
              Quick Note
            </div>
            <div style="font-size: 12px; color: var(--tx-text-color-secondary);">
              Hover to merge with the action button
            </div>
          </div>
        </template>

        <template #b>
          <div
            style="
              width: 56px;
              height: 56px;
              border-radius: 999px;
              background: color-mix(in srgb, var(--tx-color-primary, #409eff) 74%, rgba(255, 255, 255, 0.10));
              box-shadow: 0 18px 46px rgba(0, 0, 0, 0.20);
              display: grid;
              place-items: center;
              color: rgba(255, 255, 255, 0.95);
              font-size: 22px;
              font-weight: 900;
              user-select: none;
            "
          >
            +
          </div>
        </template>
      </TxFusion>
    </div>
  </div>
</template>

API

TxFusion Props

属性名类型默认值说明
modelValueboolean | undefinedundefined是否交融(v-model);undefined 时为非受控模式
disabledbooleanfalse是否禁用
trigger'hover' | 'click' | 'manual''hover'触发方式;manual 仅由 v-model 控制
direction'x' | 'y''x'分裂方向
gapnumber40分裂距离
durationnumber260过渡时长(ms)
easingstring'cubic-bezier(0.2, 0.8, 0.2, 1)'easing
blurnumber19gooey blur 强度
alphanumber29gooey 阈值(越大越“粘”)
alphaOffsetnumber-10gooey 偏移

Events

事件名参数说明
change(v: boolean)状态变化
update:modelValue(v: boolean)v-model