# 链接 Provider

## 使用方法

把应用包一层，让所有 Astryx 组件渲染链接时不再直接用 `<a>`，而是换成框架自己的链接组件，例如 Vue Router 的 `RouterLink`，这样点击走的是前端路由，不会整页刷新。

```ts
import { LinkProvider } from '@astryx-vue/core/LinkProvider'
```

这个组件会同时收到 `href` 和 `to`，路由链接认哪个就用哪个。单个组件自己写的 `as` 优先级更高，仍然会盖掉 provider。自己渲染链接时，可以用 `useLinkComponent()` 读到外层给的那个组件。

## 示例

常见的用法和不同的状态。

### Link Provider — Custom Link Component

把所有 Astryx 链接交给一个自定义组件：它拦住点击，交给框架路由惯用的那个位置处理。点一下链接，看到的是自定义处理函数在跑，而不是整页跳转。

```vue
<script setup lang="ts">
import { Link } from '@astryx-vue/core/Link'
import { LinkProvider } from '@astryx-vue/core/LinkProvider'
import { defineComponent, h, ref } from 'vue'

const intercepted = ref<string | null>(null)

/**
 * A stand-in for a framework router link (Vue Router's `RouterLink`, Nuxt's
 * `NuxtLink`). Instead of a full-page navigation it intercepts the click and
 * hands the destination to its own handler — the same hook real routers use.
 * Here it only reports the destination so the swap is observable.
 */
const RouterLink = defineComponent({
  name: 'RouterLink',
  inheritAttrs: false,
  props: {
    href: { type: String, default: undefined },
    to: { type: String, default: undefined },
  },
  setup(props, { attrs, slots }) {
    return () => h('a', {
      ...attrs,
      href: props.href ?? props.to,
      onClick: (event: MouseEvent) => {
        event.preventDefault()
        ;(attrs.onClick as ((event: MouseEvent) => void) | undefined)?.(event)
        intercepted.value = props.to ?? props.href ?? ''
      },
    }, slots.default?.())
  },
})
</script>

<template>
  <div class="link-provider-preview">
    <LinkProvider :component="RouterLink">
      <Link href="/dashboard" is-standalone>
        Go to dashboard
      </Link>
    </LinkProvider>
    <p class="link-provider-preview__status">
      {{ intercepted ? `RouterLink intercepted navigation to: ${intercepted}` : 'Click the link to try the custom component.' }}
    </p>
  </div>
</template>
```

## 属性

| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `component` | `LinkComponentType` | — | 子树里所有链接元素默认用的组件，例如 `RouterLink`、`NuxtLink`。它会收到 `href` 和 `to`。单个组件自己的 `as` 仍然优先。必填。 |

## 插槽

| 插槽 | 说明 |
| --- | --- |
| `default` | 使用这个链接组件的子树。 |

## 其它导出

| 导出 | 类型 | 说明 |
| --- | --- | --- |
| `useLinkComponent` | `() => ComputedRef` | 读最近一层 provider 给的链接组件，外层没有就是 `undefined`。用的时候写成 `props.as ?? linkComponent.value`，这样自己写的 `as` 依然优先。 |

## 会走 provider 的组件

下面这些组件在没写自己的 `as` 时，链接会交给 provider 里的组件：

- `Link`、`Button`、`Avatar`、`Token`
- `NavItem`、`NavMenuItem`、`NavHeadingMenuItem`、`SideNavHeading`、`TopNavItem`、`TopNavMegaMenuItem`、`TopNavMegaMenuFeaturedCard`
- `BreadcrumbItem`、`Tab`、`Item`（List）
- `DropdownMenuItem`、`ContextMenuItem`、`MoreMenuRow`、`TreeListItem`

不走 provider 的：`AppShell` 的跳转正文链接、`Outline` 的页内锚点、`ClickableCard`（它的可点击控件是一层视觉隐藏的 `<a>`），以及 Markdown 渲染出来的链接。

## 原生属性

组件本身不渲染元素，<code>class</code> 和 <code>style</code> 不会传下去。
