2025/2/8第一次更新

This commit is contained in:
爱吃咸鱼小猫咪
2025-02-08 18:50:38 +08:00
commit d7af560866
26519 changed files with 5046029 additions and 0 deletions
@@ -0,0 +1,68 @@
import { ZIndex } from '../../../constants'
import { buildProps } from '../../../utils'
import type { ExtractPropTypes } from 'vue'
export interface ActionSheetAction {
/**
* @description 选项文字
*/
text: string
/**
* @description 选项备注
*/
desc?: string
/**
* @description 选项的值
*/
value?: string | number
}
/**
* @description ActionSheet options配置项
*/
export interface ActionSheetOptions {
/**
* @description 选项列表
*/
actions: ActionSheetAction[]
/**
* @description 标题
*/
title?: string
/**
* @description 取消按钮文字,如果为空则不显示取消按钮
*/
cancelText?: string
/**
* @description 是否显示遮罩
*/
mask?: boolean
/**
* @description 点击蒙层是否允许关闭
*/
maskClosable?: boolean
/**
* @description 点击取消按钮触发的回调函数,返回 false 或者返回 Promise 且被 reject 则取消关闭
*/
cancel?: () => (Promise<boolean> | void) | boolean
/**
* @description 点击选项触发的回调函数,返回 false 或者返回 Promise 且被 reject 则取消关闭
*/
select?: (
index: number,
value: string | number
) => (Promise<boolean> | void) | boolean
}
export const actionSheetProps = buildProps({
/**
* @description ZIndex
*/
zIndex: {
type: Number,
default: ZIndex.popup,
},
})
export type ActionSheetProps = ExtractPropTypes<typeof actionSheetProps>
@@ -0,0 +1,87 @@
<script lang="ts" setup>
import { useNamespace } from '../../../hooks'
import TnPopup from '../../popup/src/popup.vue'
import { actionSheetProps } from './action-sheet'
import { useActionSheet } from './composables'
defineProps(actionSheetProps)
const ns = useNamespace('action-sheet')
const {
data,
showTitle,
title,
showCancel,
cancelText,
overlay,
overlayClosable,
openPopup,
showActionSheet,
popupCloseEvent,
actionClickEvent,
} = useActionSheet()
defineExpose({
/**
* @description: 打开/显示 actionSheet 操作菜单
*/
show: showActionSheet,
})
</script>
<template>
<TnPopup
:model-value="openPopup"
open-direction="bottom"
:overlay="overlay"
:z-index="zIndex"
bg-color="transparent"
:safe-area-inset-bottom="false"
:overlay-closeable="overlayClosable"
@overlay-click="popupCloseEvent"
>
<view class="tn-u-safe-area" :class="[ns.b(), ns.is('shadow', !overlay)]">
<!-- 标题 -->
<view v-if="showTitle" :class="[ns.e('title')]">
<slot name="title">
{{ title }}
</slot>
</view>
<!-- 选项 -->
<view :class="[ns.e('actions')]">
<view
v-for="(item, index) in data"
:key="index"
:class="[ns.e('action')]"
hover-class="tn-u-btn-hover"
:hover-stay-time="150"
@tap.stop="actionClickEvent(index)"
>
<!-- 选项显示内容 -->
<view class="text">{{ item.text }}</view>
<!-- 选项描述 -->
<view v-if="item.desc" class="desc">{{ item.desc }}</view>
</view>
</view>
<!-- 取消按钮 -->
<view
v-if="showCancel"
:class="[ns.e('cancel')]"
hover-class="tn-u-btn-hover"
:hover-stay-time="150"
@tap.stop="popupCloseEvent"
>
<slot name="cancel">
{{ cancelText }}
</slot>
</view>
</view>
</TnPopup>
</template>
<style lang="scss" scoped>
@import '../../../theme-chalk/src/action-sheet.scss';
</style>
@@ -0,0 +1 @@
export * from './use-action-sheet'
@@ -0,0 +1,141 @@
import { computed, getCurrentInstance, reactive, ref } from 'vue'
import {
debugWarn,
isBoolean,
isEmptyVariableInDefault,
isPromise,
} from '../../../../utils'
import type { ActionSheetOptions } from '../action-sheet'
export const useActionSheet = () => {
const instance = getCurrentInstance()
if (!instance) {
debugWarn('TnActionSheet', '请在 setup 中使用 useActionSheet')
}
const { slots } = instance!
// 默认配置项
const defaultOptions: ActionSheetOptions = {
actions: [],
title: '',
cancelText: '取 消',
mask: true,
maskClosable: false,
cancel: undefined,
select: undefined,
}
// 配置项
const options = reactive<ActionSheetOptions>({
actions: [],
title: '',
cancelText: '取 消',
mask: true,
cancel: undefined,
select: undefined,
})
// 操作菜单数据
const data = computed(() => options.actions)
// 是否显示标题
const showTitle = computed(() => !!slots?.title || !!options.title)
const title = computed(() => options.title)
// 是否显示取消按钮
const showCancel = computed(() => !!slots?.cancel || !!options.cancelText)
const cancelText = computed(() => options.cancelText)
// 是否显示遮罩
const overlay = computed(() => isEmptyVariableInDefault(options.mask, true))
// 点击遮罩是否允许关闭
const overlayClosable = computed(() =>
isEmptyVariableInDefault(options.maskClosable, false)
)
// 弹出popup弹框
const openPopup = ref<boolean>(false)
// popup弹框关闭事件
const popupCloseEvent = () => {
if (!options.cancel || overlayClosable.value) {
openPopup.value = false
return
}
const shouldCancel = options.cancel()
const isPromiseOrBoolean = [
isPromise(shouldCancel),
isBoolean(shouldCancel),
].includes(true)
if (!isPromiseOrBoolean) {
debugWarn(
'TnActionSheet',
'cancel 函数返回值必须是 Promise 或者 Boolean 类型'
)
return
}
if (isPromise(shouldCancel)) {
shouldCancel.then((res) => {
if (res) {
openPopup.value = false
}
})
} else {
if (shouldCancel) {
openPopup.value = false
}
}
}
// 选项点击事件
const actionClickEvent = (index: number) => {
if (!options.select) {
openPopup.value = false
return
}
const shouldSelect = options.select(index, options.actions[index].value!)
const isPromiseOrBoolean = [
isPromise(shouldSelect),
isBoolean(shouldSelect),
].includes(true)
if (!isPromiseOrBoolean) {
debugWarn(
'TnActionSheet',
'select 函数返回值必须是 Promise 或者 Boolean 类型'
)
return
}
if (isPromise(shouldSelect)) {
shouldSelect.then((res) => {
if (res) {
openPopup.value = false
}
})
} else {
if (shouldSelect) {
openPopup.value = false
}
}
}
const showActionSheet = (_options: ActionSheetOptions) => {
Object.assign(options, defaultOptions, _options)
openPopup.value = true
}
return {
data,
showTitle,
title,
showCancel,
cancelText,
overlay,
overlayClosable,
openPopup,
showActionSheet,
popupCloseEvent,
actionClickEvent,
}
}
@@ -0,0 +1,3 @@
import type ActionSheet from './action-sheet.vue'
export type TnActionSheetInstance = InstanceType<typeof ActionSheet>