cl-popup 添加 teleport 支持

This commit is contained in:
icssoa
2025-08-22 16:44:22 +08:00
parent adacc78bdc
commit 73b0192c4e
4 changed files with 129 additions and 91 deletions

View File

@@ -30,6 +30,25 @@
></cl-select> ></cl-select>
</demo-item> </demo-item>
<demo-item :label="t('弹窗中使用')">
<cl-button @tap="visible3 = true">打开</cl-button>
<cl-popup v-model="visible3" direction="center" size="80%" :title="t('选择地区')">
<view class="p-3 pt-0">
<demo-tips>
H5 和 APP 端通过 teleport 实现弹窗内的选择器使用,小程序端则通过
root-portal 实现。
</demo-tips>
<cl-select
v-model="form.selected3"
:options="options3"
:column-count="3"
></cl-select>
</view>
</cl-popup>
</demo-item>
<demo-item :label="t('自定义')"> <demo-item :label="t('自定义')">
<cl-text <cl-text
:pt="{ :pt="{
@@ -359,4 +378,6 @@ function openSelect2() {
}); });
}); });
} }
const visible3 = ref(false);
</script> </script>

View File

@@ -548,7 +548,7 @@ function onTouchCancel() {
} }
.cl-button { .cl-button {
@apply flex flex-row items-center justify-center relative; @apply flex flex-row items-center justify-center relative box-border;
@apply border border-transparent border-solid; @apply border border-transparent border-solid;
overflow: visible; overflow: visible;
transition-duration: 0.3s; transition-duration: 0.3s;

View File

@@ -1,106 +1,123 @@
<template> <template>
<view <!-- #ifdef H5 -->
class="cl-popup-wrapper" <teleport to="#app">
:class="[`cl-popup-wrapper--${direction}`]" <!-- #endif -->
:style="{
zIndex,
pointerEvents
}"
v-show="visible"
v-if="keepAlive ? true : visible"
@touchmove.stop.prevent
>
<view
class="cl-popup-mask"
:class="[
{
'is-open': status == 1,
'is-close': status == 2
},
pt.mask?.className
]"
@tap="maskClose"
v-if="showMask"
></view>
<view <!-- #ifdef MP -->
class="cl-popup" <root-portal>
:class="[ <!-- #endif -->
{
'is-open': status == 1,
'is-close': status == 2,
'is-custom-navbar': router.isCustomNavbarPage(),
'stop-transition': swipe.isTouch
},
pt.className
]"
:style="popupStyle"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
@touchcancel="onTouchEnd"
>
<view <view
class="cl-popup__inner" class="cl-popup-wrapper"
:class="[ :class="[`cl-popup-wrapper--${direction}`]"
{
'is-dark': isDark
},
pt.inner?.className
]"
:style="{ :style="{
paddingBottom zIndex,
pointerEvents
}" }"
v-show="visible"
v-if="keepAlive ? true : visible"
@touchmove.stop.prevent
> >
<view <view
class="cl-popup__draw" class="cl-popup-mask"
:class="[ :class="[
{ {
'!bg-surface-400': swipe.isMove 'is-open': status == 1,
'is-close': status == 2
}, },
pt.draw?.className pt.mask?.className
]" ]"
v-if="isSwipeClose" @tap="maskClose"
v-if="showMask"
></view> ></view>
<view class="cl-popup__header" :class="[pt.header?.className]" v-if="showHeader">
<slot name="header">
<cl-text
:pt="{
className: `text-lg font-bold ${pt.header?.text?.className}`
}"
>{{ title }}</cl-text
>
</slot>
<cl-icon
name="close-circle-fill"
:size="40"
:pt="{
className:
'absolute right-[24rpx] !text-surface-400 dark:!text-surface-50'
}"
@tap="close"
@touchmove.stop
v-if="isOpen && showClose"
></cl-icon>
</view>
<view <view
class="cl-popup__container" class="cl-popup"
:class="[pt.container?.className]" :class="[
@touchmove.stop {
'is-open': status == 1,
'is-close': status == 2,
'is-custom-navbar': router.isCustomNavbarPage(),
'stop-transition': swipe.isTouch
},
pt.className
]"
:style="popupStyle"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
@touchcancel="onTouchEnd"
> >
<slot></slot> <view
class="cl-popup__inner"
:class="[
{
'is-dark': isDark
},
pt.inner?.className
]"
:style="{
paddingBottom
}"
>
<view
class="cl-popup__draw"
:class="[
{
'!bg-surface-400': swipe.isMove
},
pt.draw?.className
]"
v-if="isSwipeClose"
></view>
<view
class="cl-popup__header"
:class="[pt.header?.className]"
v-if="showHeader"
>
<slot name="header">
<cl-text
:pt="{
className: `text-lg font-bold ${pt.header?.text?.className}`
}"
>{{ title }}</cl-text
>
</slot>
<cl-icon
name="close-circle-fill"
:size="40"
:pt="{
className:
'absolute right-[24rpx] !text-surface-400 dark:!text-surface-50'
}"
@tap="close"
@touchmove.stop
v-if="isOpen && showClose"
></cl-icon>
</view>
<view
class="cl-popup__container"
:class="[pt.container?.className]"
@touchmove.stop
>
<slot></slot>
</view>
</view>
</view> </view>
</view> </view>
</view> <!-- #ifdef MP -->
</view> </root-portal>
<!-- #endif -->
<!-- #ifdef H5 -->
</teleport>
<!-- #endif -->
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, reactive, ref, watch, type PropType } from "vue"; import { computed, reactive, ref, watch, type PropType } from "vue";
import { getSafeAreaHeight, getTabBarHeight, hasCustomTabBar, parsePt, parseRpx } from "@/cool"; import { getSafeAreaHeight, parsePt, parseRpx } from "@/cool";
import type { ClPopupDirection, PassThroughProps } from "../../types"; import type { ClPopupDirection, PassThroughProps } from "../../types";
import { isDark, router } from "@/cool"; import { isDark, router } from "@/cool";
import { config } from "../../config"; import { config } from "../../config";
@@ -543,7 +560,7 @@ defineExpose({
.cl-popup { .cl-popup {
@apply left-0 top-0; @apply left-0 top-0;
&__inner { .cl-popup__inner {
@apply rounded-b-2xl; @apply rounded-b-2xl;
} }
@@ -554,7 +571,7 @@ defineExpose({
&--left, &--left,
&--right, &--right,
&--top { &--top {
.cl-popup { & > .cl-popup {
// #ifdef H5 // #ifdef H5
top: 44px; top: 44px;
// #endif // #endif
@@ -567,7 +584,7 @@ defineExpose({
&--left, &--left,
&--right { &--right {
.cl-popup { & > .cl-popup {
// #ifdef H5 // #ifdef H5
height: calc(100% - 44px) !important; height: calc(100% - 44px) !important;
// #endif // #endif
@@ -575,11 +592,11 @@ defineExpose({
} }
&--bottom { &--bottom {
.cl-popup { & > .cl-popup {
@apply left-0 bottom-0; @apply left-0 bottom-0;
transform: translateY(100%); transform: translateY(100%);
&__inner { .cl-popup__inner {
@apply rounded-t-2xl; @apply rounded-t-2xl;
} }
} }
@@ -588,11 +605,11 @@ defineExpose({
&--center { &--center {
@apply flex flex-col items-center justify-center; @apply flex flex-col items-center justify-center;
.cl-popup { & > .cl-popup {
transform: scale(1.3); transform: scale(1.3);
opacity: 0; opacity: 0;
&__inner { .cl-popup__inner {
@apply rounded-2xl; @apply rounded-2xl;
} }
} }

View File

@@ -148,7 +148,7 @@ function open() {
<style lang="scss" scoped> <style lang="scss" scoped>
.cl-select-trigger { .cl-select-trigger {
@apply flex flex-row items-center w-full; @apply flex flex-row items-center w-full box-border;
@apply border border-solid border-surface-200 rounded-lg bg-white; @apply border border-solid border-surface-200 rounded-lg bg-white;
height: 66rpx; height: 66rpx;
padding: 0 20rpx; padding: 0 20rpx;