Initial commit of akmon project

This commit is contained in:
2026-01-20 08:04:15 +08:00
commit 77a2bab985
1309 changed files with 343305 additions and 0 deletions

View File

@@ -0,0 +1,201 @@
<template>
<l-overlay
:visible="innerValue"
:zIndex="overlayZIndex"
:appear="true"
:preventScrollThrough="preventScrollThrough"
:l-style="overlayStyle"
@click="handleOverlayClick"
v-if="destroyOnClose ? display && overlay : overlay">
</l-overlay>
<view class="l-popup"
ref="popupRef"
v-if="destroyOnClose ? display : inited"
:class="rootClass"
:style="[styles, lStyle]"
@transitionend="finished">
<slot></slot>
<view class="l-popup__close" v-if="closeable" @click="handleClose">
<slot name="close-btn">
<l-icon class="l-popup__close-icon" :name="closeIcon" size="27px" :color="iconColor" />
</slot>
</view>
</view>
</template>
<script lang="uts" setup>
/**
* Popup 弹出层组件
* @description 提供多种位置的弹窗展示能力,支持自定义内容和动画效果
* <br>插件类型LPopupComponentPublicInstance
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-popup
*
* @property {boolean} closeable 显示关闭按钮默认false
* @property {boolean} closeOnClickOverlay 点击遮罩关闭默认true
* @property {boolean} destroyOnClose 关闭时销毁内容默认false
* @property {string} overlayStyle 遮罩层样式支持CSS字符串
* @property {'top' | 'left' | 'right' | 'bottom' | 'center' | ''} position 弹出位置
* @value top 从顶部滑入
* @value bottom 从底部滑入
* @value left 从左侧滑入
* @value right 从右侧滑入
* @value center 居中显示(默认)
* @property {boolean} preventScrollThrough 阻止滚动穿透默认true
* @property {boolean} overlay 显示遮罩层默认true
* @property {string} transitionName 自定义动画名称配合transition使用
* @property {string|number|Array} radius 圆角 可以是字符,数值,数组
* @property {boolean} visible 控制显示/隐藏支持v-model
* @property {number} zIndex 组件层级默认999
* @property {number} duration 动画时长单位ms默认300
* @property {string} bgColor 内容区域背景色(默认:#ffffff
* @property {string} closeIcon 关闭图标名称/路径(默认:'close'
* @property {string} iconColor 关闭图标颜色(默认:#333
* @property {string} lStyle 自定义内容区样式支持CSS字符串
* @property {boolean} safeAreaInsetBottom 适配底部安全区域默认true
* @property {boolean} safeAreaInsetTop 适配顶部安全区域默认true
* @event {Function} close 关闭时触发(返回触发来源:'close-btn' | 'overlay'
* @event {Function} change 切换时触发
* @event {Function} click-overlay 点击遮罩触发
* @event {Function} click-close 点击关闭触发
* @event {Function} open 打开触发
* @event {Function} opened 打开完成触发
* @event {Function} closed 关闭完成触发
* @event {Function} before-enter
* @event {Function} enter
* @event {Function} after-enter
* @event {Function} before-leave
* @event {Function} leave
* @event {Function} after-leave
*/
import { useTransition, UseTransitionOptions, TransitionEmitStatus } from '@/uni_modules/lime-transition';
import { convertRadius } from './utils'
import { PopupProps } from './type';
const emit = defineEmits(['change', 'click-overlay', 'click-close', 'open', 'opened','close','closed', 'before-enter', 'enter', 'after-enter', 'before-leave', 'leave', 'after-leave'])
const props = withDefaults(defineProps<PopupProps>(),{
closeable: false,
overlay: true,
closeOnClickOverlay: true,
preventScrollThrough: true,
destroyOnClose: false,
safeAreaInsetBottom: true,
safeAreaInsetTop: false,
position: 'center',
zIndex: 999,
duration: 300,
closeIcon: 'close'
})
const modelValue = defineModel({type: Boolean});
const innerValue = computed({
set(value: boolean) {
modelValue.value = value;
emit('change', value)
},
get():boolean {
// #ifdef APP-ANDROID
return (props.visible ?? false) || modelValue.value// ?? false
// #endif
// #ifndef APP-ANDROID
return props.visible || modelValue.value
// #endif
}
} as WritableComputedOptions<boolean>)
const status = ref<TransitionEmitStatus>('before-enter')
const {inited, display, classes, finished} = useTransition({
defaultName: props.transitionName ?? 'popup-fade',
appear: innerValue.value,
emits: (name:TransitionEmitStatus) => {
status.value = name
if(name == 'before-enter') {
emit('open')
} else if(name == 'after-enter') {
emit('opened')
} else if(name == 'before-leave') {
emit('close')
} else if(name == 'after-leave') {
emit('closed')
}
emit(name)
},
visible: (): boolean => innerValue.value,
duration: props.duration,
} as UseTransitionOptions)
const overlayZIndex = computed(():number => props.zIndex > 0 ? props.zIndex - 1: 998);
const rootClass = computed(():string=>{
const safe = props.safeAreaInsetTop && props.position == 'top'
? 'l-popup--safe-top'
: props.safeAreaInsetBottom && props.position == 'bottom'
? 'l-popup--safe-bottom'
: ''
return `l-popup--${props.position} ${safe} ${classes.value}`
})
const {safeAreaInsets} = uni.getWindowInfo()
const styles = computed<Map<string,any>>(():Map<string,any> => {
const style = new Map<string,any>();
// #ifdef APP-ANDROID || APP-IOS || APP-HARMONY
style.set('transition-duration', (['after-leave', 'before-enter'].includes(status.value) ? 0 : props.duration) + 'ms')
// #endif
// #ifndef APP-ANDROID || APP-IOS || APP-HARMONY
style.set('transition-duration', props.duration + 'ms')
// #endif
if (props.bgColor != null) {
style.set("background", props.bgColor!)
}
if (props.zIndex > 0) {
style.set("z-index", props.zIndex)
}
if(props.safeAreaInsetBottom && props.position == 'bottom') {
style.set('padding-bottom', safeAreaInsets.bottom + 'px')
}
if(props.safeAreaInsetTop && props.position == 'top') {
style.set('padding-top', safeAreaInsets.top + 'px')
}
if(props.radius != null) {
const values = convertRadius(props.radius!)
style.set('border-top-left-radius', values[0])
style.set('border-top-right-radius', values[1])
style.set('border-bottom-right-radius', values[2])
style.set('border-bottom-left-radius', values[3])
}
// #ifndef APP
if (!display.value) {
style.set("display", "none")
}
// #endif
return style
})
const handleOverlayClick = () => {
if(props.closeOnClickOverlay) {
innerValue.value = false;
emit('click-overlay')
}
}
const handleClose = () => {
innerValue.value = false;
emit('click-close')
}
// #ifdef APP
const popupRef = ref<UniElement|null>(null)
watchEffect(()=>{
if(!display.value) {
popupRef.value?.style.setProperty('display', 'none')
} else {
popupRef.value?.style.setProperty('display', 'flex')
}
})
// #endif
</script>
<style lang="scss">
@import "./index-u";
</style>