# useAppShellMobile

## 使用方法

用在 AppShell 里面，读和控制 AppShell 的移动端导航状态。想做自己的移动端导航按钮、路由变化后关掉抽屉，或者让挨着 AppShell 的移动端界面跟导航用同一个断点，都用它。

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

```vue
<script setup lang="ts">
import { useAppShellMobile } from '@astryx-vue/core'

const { isMobile, isMobileNavEnabled, mobileNavId, openMobileNav } = useAppShellMobile()
</script>

<template>
  <button
    v-if="isMobile && isMobileNavEnabled"
    type="button"
    :aria-controls="mobileNavId"
    @click="openMobileNav"
  >
    打开导航
  </button>
</template>
```

## 建议

| 指引 | 做法 |
| --- | --- |
| 推荐 | 在 AppShell 子树里做自定义移动端导航控件、跟着路由走的导航项，或者需要跟移动端导航同步断点的界面时用它。 |
| 推荐 | 标准汉堡按钮直接用 `MobileNavToggle`；只有要换位置、改样式或者加行为时才用这个 hook。 |
| 推荐 | 自定义的移动端导航项跳完路由后调 `closeMobileNav`，抽屉才能干净地收起来。 |
| 避免 | 界面不在 AppShell 里、也不需要跟 AppShell 移动端导航对齐时，别拿它当通用的响应式工具；改用 `useMediaQuery`。 |
| 避免 | 以为在 AppShell 外面会报错。没有提供者时它返回一组安全的默认值和不做事的空函数。 |

## 示例

常见配置、变体和状态。

### useAppShellMobile — 自定义移动端触发按钮

用 useAppShellMobile 做的自定义移动端导航按钮。它读的是外面那层 AppShell 的上下文，不自己套一层外壳。

```vue
<script setup lang="ts">
import { useAppShellMobile } from '@astryx-vue/core'
import { Button } from '@astryx-vue/core/Button'
import { HStack, VStack } from '@astryx-vue/core/Stack'
import { Text } from '@astryx-vue/core/Text'

const {
  closeMobileNav,
  isMobile,
  isMobileNavEnabled,
  isMobileNavOpen,
  openMobileNav,
} = useAppShellMobile()
</script>

<template>
  <VStack v-if="!isMobileNavEnabled" :gap="2">
    <Button is-disabled label="Open navigation" variant="secondary" />
    <Text color="secondary" type="body">
      No active AppShell mobile navigation context was detected. This hook returns safe defaults outside AppShell, or when the surrounding AppShell has mobile navigation disabled.
    </Text>
  </VStack>
  <VStack v-else-if="!isMobile" :gap="2">
    <Button is-disabled label="Open navigation" variant="secondary" />
    <Text color="secondary" type="body">
      AppShell mobile navigation context is available. Narrow the viewport below the AppShell mobile breakpoint to make the custom trigger active.
    </Text>
  </VStack>
  <VStack v-else :gap="2">
    <HStack :gap="2" align="center">
      <Button
        :label="isMobileNavOpen ? 'Close navigation' : 'Open navigation'"
        variant="secondary"
        @click="isMobileNavOpen ? closeMobileNav() : openMobileNav()"
      />
      <Text color="secondary" type="body">
        {{ isMobileNavOpen ? 'Mobile nav is open' : 'Mobile nav is closed' }}
      </Text>
    </HStack>
    <Text color="secondary" type="body">
      This button controls the nearest AppShell mobile nav from context.
    </Text>
  </VStack>
</template>
```

## 返回值

| 名称 | 类型 | 说明 |
| --- | --- | --- |
| `isMobile` | `boolean` | 当前视口是否小于 AppShell 移动端导航的断点。用它让挨着 AppShell 的移动端界面跟移动端导航踩同一个断点。 |
| `isMobileNavOpen` | `boolean` | AppShell 管的那个移动端导航抽屉是否打开。 |
| `mobileNavId` | `string \| undefined` | 移动端导航抽屉的 DOM id，由 AppShell 设置。自定义按钮把它填进 `aria-controls`，读屏用户就知道这个按钮展开的是哪一块。不在管理抽屉的 AppShell 里时是 undefined。 |
| `toggleMobileNav` | `() => void` | 切换 AppShell 管的移动端导航抽屉。移动端导航停用时不做任何事。 |
| `openMobileNav` | `() => void` | 打开 AppShell 管的移动端导航抽屉。移动端导航停用时不做任何事。 |
| `closeMobileNav` | `() => void` | 关闭 AppShell 管的移动端导航抽屉。 |
| `isMobileNavEnabled` | `boolean` | 移动端导航是否已启用、并由 AppShell 管理。以下情况为 false：`mobileNav` 传了 `false`、没有导航内容、或者整个抽屉由自定义的 `mobileNav` 插槽负责。 |
| `hasAutoToggle` | `boolean` | AppShell 的自动切换按钮是否启用。`mobileNav.hasToggle` 传 `false` 时为 false。自己画按钮之前，先和 `isMobile`、`isMobileNavEnabled` 一起判断。 |
| `hasSideNav` | `boolean` | AppShell 有没有 `sideNav` 插槽。只有存在导航内容时才会托管移动端导航。 |

返回的对象是稳定的、响应式的。在模板或计算属性里读这些字段，视口变化时它们会跟着更新。
