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,2 @@
export * from './popup-custom'
export * from './use-popup'
@@ -0,0 +1,121 @@
import { computed, toRef } from 'vue'
import { useComponentColor, useNamespace } from '../../../../hooks'
import { formatDomSizeValue } from '../../../../utils'
import type { CSSProperties } from 'vue'
import type { PopupProps } from '../popup'
export const usePopupCustomStyle = (props: PopupProps) => {
const ns = useNamespace('popup')
// 当前模态框的zIndex
const zIndex = computed(() => Number(props.zIndex))
// 遮罩层的zIndex
const overlayZIndex = computed(() => zIndex.value - 1)
// 内容背景颜色
const [contentBgColorClass, contentBgColorStyle] = useComponentColor(
toRef(props, 'bgColor'),
'bg'
)
// 内容所属类
const popupContentClass = computed<string>(() => {
const cls: string[] = [ns.e('content')]
// 内容弹出位置
if (props.openDirection) cls.push(ns.em('content', props.openDirection))
// 如果是底部弹出,是否开启安全区域
if (props.openDirection === 'bottom' && props.safeAreaInsetBottom) {
cls.push('tn-u-safe-area')
}
// 内容背景颜色
if (contentBgColorClass.value) cls.push(contentBgColorClass.value)
return cls.join(' ')
})
// 内容所属样式
const popupContentStyle = computed<CSSProperties>(() => {
const style: CSSProperties = {}
// 设置背景颜色
if (contentBgColorStyle.value)
style.backgroundColor = contentBgColorStyle.value
// 设置圆角
if (props.radius) {
// 如果有设置圆角则条件overflow:hidden
style.overflow = 'hidden'
// 根据不同的弹出位置设置圆角
if (props.openDirection === 'center') {
style.borderRadius = formatDomSizeValue(props.radius)
}
if (props.openDirection === 'top') {
style.borderBottomLeftRadius = formatDomSizeValue(props.radius)
style.borderBottomRightRadius = formatDomSizeValue(props.radius)
}
if (props.openDirection === 'left') {
style.borderTopRightRadius = formatDomSizeValue(props.radius)
style.borderBottomRightRadius = formatDomSizeValue(props.radius)
}
if (props.openDirection === 'right') {
style.borderTopLeftRadius = formatDomSizeValue(props.radius)
style.borderBottomLeftRadius = formatDomSizeValue(props.radius)
}
if (props.openDirection === 'bottom') {
style.borderTopLeftRadius = formatDomSizeValue(props.radius)
style.borderTopRightRadius = formatDomSizeValue(props.radius)
}
}
// 设置距离顶部的距离
if (
props.top &&
(props.openDirection === 'top' ||
props.openDirection === 'left' ||
props.openDirection === 'right')
) {
style.top = formatDomSizeValue(props.top, 'px')
}
// 根据不同的位置设置不同的宽度或高度
if (
props.width &&
(props.openDirection === 'left' ||
props.openDirection === 'right' ||
props.openDirection === 'center')
) {
style.width = formatDomSizeValue(props.width)
}
if (
props.height &&
(props.openDirection === 'top' ||
props.openDirection === 'bottom' ||
props.openDirection === 'center')
) {
style.height = formatDomSizeValue(props.height)
}
if (props.openDirection === 'left' || props.openDirection === 'right') {
if (props.top)
style.height = `calc(100% - ${formatDomSizeValue(props.top, 'px')})`
}
// 设置zIndex
style.zIndex = zIndex.value
return style
})
return {
ns,
zIndex,
overlayZIndex,
popupContentClass,
popupContentStyle,
}
}
@@ -0,0 +1,79 @@
import { computed, getCurrentInstance, ref, watch } from 'vue'
import { UPDATE_MODEL_EVENT } from '../../../../constants'
import type { PopupProps } from '../popup'
export const usePopup = (props: PopupProps) => {
const { emit } = getCurrentInstance()!
const iosDevice = computed<boolean>(() => {
const systemInfo = uni.getSystemInfoSync()
return systemInfo.osName === 'ios' || systemInfo.osName === 'macos'
})
// 是否显示遮罩层
const showOverlay = ref(false)
// 是否显示弹框
const showPopup = ref(false)
const visiblePopup = ref(false)
let initPopupModelValue = false
watch(
() => props.modelValue,
(value) => {
if (value) {
visiblePopup.value = true
if (iosDevice.value) {
setTimeout(() => {
showPopup.value = true
if (props.overlay) showOverlay.value = true
initPopupModelValue && emit('open')
}, 0)
} else {
showPopup.value = true
if (props.overlay) showOverlay.value = true
initPopupModelValue && emit('open')
}
} else {
showPopup.value = false
showOverlay.value = false
setTimeout(() => {
visiblePopup.value = false
}, 250)
initPopupModelValue && emit('close')
}
initPopupModelValue = true
},
{
immediate: true,
}
)
// 更新模态框的状态
const updateModelValue = (value: boolean) => {
emit(UPDATE_MODEL_EVENT, value)
}
// 点击关闭按钮
const onClickCloseBtn = () => {
updateModelValue(false)
emit('close')
}
// 点击遮罩层关闭模态框
const onClickOverlay = () => {
if (props.overlayCloseable) {
updateModelValue(false)
emit('close')
emit('overlay-click')
}
}
return {
iosDevice,
showOverlay,
showPopup,
visiblePopup,
updateModelValue,
onClickCloseBtn,
onClickOverlay,
}
}
@@ -0,0 +1,3 @@
import type Popup from './popup.vue'
export type TnPopupInstance = InstanceType<typeof Popup>
+122
View File
@@ -0,0 +1,122 @@
import { UPDATE_MODEL_EVENT, ZIndex } from '../../../constants'
import { buildProps, isBoolean } from '../../../utils'
import { useComponentSafeAreaInsetBottomProp } from '../../base/composables/use-component-common-props'
import { overlayProps } from '../../overlay'
import type { ExtractPropTypes } from 'vue'
export const popupOpenDirection = [
'top',
'bottom',
'left',
'right',
'center',
] as const
export const popupCloseBtnPosition = [
'left-top',
'right-top',
'left-bottom',
'right-bottom',
] as const
export const popupProps = buildProps({
/**
* @description 控制弹框是否显示
*/
modelValue: Boolean,
/**
* @description 弹框打开的方向
*/
openDirection: {
type: String,
values: popupOpenDirection,
default: 'center',
},
/**
* @description 弹窗的宽度,在 openDirection 为 left 或 right 或 center 时生效
*/
width: {
type: [String, Number],
},
/**
* @description 弹窗的高度,在 openDirection 为 top 或 bottom 或 center 时生效
*/
height: {
type: [String, Number],
},
/**
* @description 弹框的内容的背景颜色
*/
bgColor: {
type: String,
default: '#fff',
},
/**
* @description 弹框的内容的圆角
*/
radius: {
type: [String, Number],
default: 15,
},
/**
* @description 是否显示overlay遮罩层
*/
overlay: {
type: Boolean,
default: true,
},
/**
* @description overlay遮罩层的透明度
*/
overlayOpacity: overlayProps['opacity'],
/**
* @description 点击overlay关闭弹框
*/
overlayCloseable: {
type: Boolean,
default: true,
},
/**
* @description 是否显示关闭按钮
*/
closeBtn: Boolean,
/**
* @description 关闭按钮的位置
*/
closeBtnPosition: {
type: String,
values: popupCloseBtnPosition,
default: 'right-top',
},
/**
* @description 底部是否开启安全区域
*/
safeAreaInsetBottom: useComponentSafeAreaInsetBottomProp,
/**
* @description zIndex
*/
zIndex: {
type: Number,
default: ZIndex.popup,
},
/**
* @description 距离顶部的距离,在 openDirection 为 top 或 left 或 right 时生效,默认单位为`px`
*/
top: {
type: [String, Number],
},
})
export const popupEmits = {
[UPDATE_MODEL_EVENT]: (value: boolean) => isBoolean(value),
open: () => true,
close: () => true,
['overlay-click']: () => true,
}
export type PopupProps = ExtractPropTypes<typeof popupProps>
export type PopupEmits = typeof popupEmits
export type PopupOpenDirection = (typeof popupOpenDirection)[number]
export type PopupCloseBtnPosition = (typeof popupCloseBtnPosition)[number]
+58
View File
@@ -0,0 +1,58 @@
<script lang="ts" setup>
import TnOverlay from '../../overlay/src/overlay.vue'
import TnIcon from '../../icon/src/icon.vue'
import { popupEmits, popupProps } from './popup'
import { usePopup, usePopupCustomStyle } from './composables'
const props = defineProps(popupProps)
defineEmits(popupEmits)
const {
iosDevice,
showOverlay,
showPopup,
visiblePopup,
onClickCloseBtn,
onClickOverlay,
} = usePopup(props)
const { ns, overlayZIndex, zIndex, popupContentClass, popupContentStyle } =
usePopupCustomStyle(props)
</script>
<template>
<view
v-if="!iosDevice || (iosDevice && visiblePopup)"
:class="[ns.b(), ns.is('show', showPopup), ns.is('visible', visiblePopup)]"
:style="{
zIndex,
}"
>
<!-- 遮罩层 -->
<TnOverlay
:show="showOverlay"
:z-index="overlayZIndex"
:opacity="overlayOpacity"
@click="onClickOverlay"
/>
<!-- 弹框内容 -->
<view :class="[popupContentClass]" :style="popupContentStyle">
<slot />
<!-- 关闭按钮 -->
<view
v-if="closeBtn"
:class="[ns.e('close-btn'), ns.em('close-btn', closeBtnPosition)]"
@tap.stop="onClickCloseBtn"
>
<slot name="closeBtn">
<TnIcon name="close" />
</slot>
</view>
</view>
</view>
</template>
<style lang="scss" scoped>
@import '../../../theme-chalk/src/popup.scss';
</style>