# Composables(组合式函数)

Composables 是 Vue 3 中用来组织和复用组件逻辑的一种机制。将组件中可复用的逻辑抽取到独立的函数中,可以在多个组件间共享。

## 全局使用方法

本项目提供了三种方式来全局复用 `compositions` 文件夹下的功能方法:

### 方式 1: 在模板中使用 `$filters`(推荐用于模板)

通过全局属性,可以在任何组件的模板中直接使用:

```vue
<template>
  <div>
    <!-- 格式化日期 -->
    <p>{{ $filters.formatDate(date, 'yyyy-MM-dd') }}</p>

    <!-- 格式化手机号 -->
    <p>{{ $filters.mobile('13812345678') }}</p>

    <!-- 格式化数字 -->
    <p>{{ $filters.num(12345.67, '0,000.00') }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const date = ref(new Date())
</script>
```

### 方式 2: 在 `<script setup>` 中使用 composable(推荐用于逻辑)

```vue
<script setup>
import { useFilters } from '@/composables/useFilters'
import { ref, computed } from 'vue'

// 方式 2.1: 使用 useFilters 获取所有函数
const filters = useFilters()
const formattedDate = computed(() => filters.formatDate(date.value, 'yyyy-MM-dd'))

// 方式 2.2: 按需引入单个函数(推荐,更清晰)
import { formatDate, mobile, num } from '@/composables/useFilters'

const date = ref(new Date())
const displayDate = computed(() => formatDate(date.value, 'yyyy-MM-dd hh:mm:ss'))
const phone = ref('13812345678')
const maskedPhone = computed(() => mobile(phone.value))
</script>
```

---

## 自定义指令使用方法

### 1. 全局使用指令(已配置)

所有自定义指令已自动注册,可以在任何组件中直接使用。

#### v-motion 转场动画指令

用于实现从按钮位置展开到全屏的转场动画效果。

```vue
<template>
  <!-- 触发按钮 -->
  <v-btn v-motion:contentArea="isOpen" @click="isOpen = !isOpen">
    {{ isOpen ? '关闭' : '打开' }}
  </v-btn>

  <!-- 转场内容区域 -->
  <div id="contentArea">
    <h3>这是转场展开的内容</h3>
    <v-btn v-motion:contentArea="isOpen" @click="isOpen = false">
      关闭
    </v-btn>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const isOpen = ref(false)
</script>
```

**使用说明:**
- `v-motion:targetId` - targetId 是要展开的目标元素的 id
- `="isOpen"` - 布尔值,true 表示展开,false 表示收起
- 需要配合 @click 事件切换状态

### 2. 局部注册指令(可选)

如果只想在特定组件中使用指令:

```vue
<script setup>
import { motion } from '@/composables/useDirectives'

// 在 script setup 中,需要使用 vMotion 命名约定
const vMotion = motion
</script>

<template>
  <div v-motion:target="isActive">
    使用局部注册的指令
  </div>
</template>
```

---

## 可用的过滤器函数

### 时间格式化
- `date(val, fmt)` - 格式化时间
- `formatDate(value, fmt)` - 格式化日期
- `days(val, day, text)` - 计算天数差

### 数字格式化
- `num(val, fmt)` - 数字格式化,如 `'0,000.00'`
- `abs(val)` - 取绝对值
- `age(val)` - 根据生日计算年龄

### 文本处理
- `txt(val, len)` - 文本超长截断
- `mobile(val)` - 手机号脱敏
- `idcard(val)` - 身份证号脱敏

## 注意事项

1. Vue 3 已移除 `Vue.filter`,请使用上述三种方式替代
2. 推荐在模板中使用 `$filters`,在逻辑中按需引入函数
3. 按需引入可以获得更好的类型提示和代码提示
4. 自定义指令已从 Vue 2 迁移到 Vue 3,钩子函数名称有所变化:
   - `bind` → `beforeMount`
   - `inserted` → `mounted`
   - `unbind` → `unmounted`

## 可用的自定义指令

### v-motion
转场动画指令,实现从触发元素位置展开到全屏的过渡效果。

## 示例页面

- [过滤器示例](../views/FilterDemo.vue) - 查看所有过滤器的使用示例
- [指令示例](../views/MotionDemo.vue) - 查看 v-motion 指令的使用示例
