Bläddra i källkod

cl-popup 添加 teleport 支持

icssoa 7 månader sedan
förälder
incheckning
73b0192c4e

+ 21 - 0
pages/demo/form/select.uvue

@@ -30,6 +30,25 @@
 				></cl-select>
 			</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('自定义')">
 				<cl-text
 					:pt="{
@@ -359,4 +378,6 @@ function openSelect2() {
 		});
 	});
 }
+
+const visible3 = ref(false);
 </script>

+ 1 - 1
uni_modules/cool-ui/components/cl-button/cl-button.uvue

@@ -548,7 +548,7 @@ function onTouchCancel() {
 }
 
 .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;
 	overflow: visible;
 	transition-duration: 0.3s;

+ 107 - 90
uni_modules/cool-ui/components/cl-popup/cl-popup.uvue

@@ -1,106 +1,123 @@
 <template>
-	<view
-		class="cl-popup-wrapper"
-		:class="[`cl-popup-wrapper--${direction}`]"
-		: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
-			class="cl-popup"
-			:class="[
-				{
-					'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"
-		>
+	<!-- #ifdef H5 -->
+	<teleport to="#app">
+		<!-- #endif -->
+
+		<!-- #ifdef MP -->
+		<root-portal>
+			<!-- #endif -->
 			<view
-				class="cl-popup__inner"
-				:class="[
-					{
-						'is-dark': isDark
-					},
-					pt.inner?.className
-				]"
+				class="cl-popup-wrapper"
+				:class="[`cl-popup-wrapper--${direction}`]"
 				:style="{
-					paddingBottom
+					zIndex,
+					pointerEvents
 				}"
+				v-show="visible"
+				v-if="keepAlive ? true : visible"
+				@touchmove.stop.prevent
 			>
 				<view
-					class="cl-popup__draw"
+					class="cl-popup-mask"
 					: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 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
+					class="cl-popup"
+					:class="[
+						{
+							'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>
+			<!-- #ifdef MP -->
+		</root-portal>
+		<!-- #endif -->
+		<!-- #ifdef H5 -->
+	</teleport>
+	<!-- #endif -->
 </template>
 
 <script lang="ts" setup>
 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 { isDark, router } from "@/cool";
 import { config } from "../../config";
@@ -543,7 +560,7 @@ defineExpose({
 		.cl-popup {
 			@apply left-0 top-0;
 
-			&__inner {
+			.cl-popup__inner {
 				@apply rounded-b-2xl;
 			}
 
@@ -554,7 +571,7 @@ defineExpose({
 	&--left,
 	&--right,
 	&--top {
-		.cl-popup {
+		& > .cl-popup {
 			// #ifdef H5
 			top: 44px;
 			// #endif
@@ -567,7 +584,7 @@ defineExpose({
 
 	&--left,
 	&--right {
-		.cl-popup {
+		& > .cl-popup {
 			// #ifdef H5
 			height: calc(100% - 44px) !important;
 			// #endif
@@ -575,11 +592,11 @@ defineExpose({
 	}
 
 	&--bottom {
-		.cl-popup {
+		& > .cl-popup {
 			@apply left-0 bottom-0;
 			transform: translateY(100%);
 
-			&__inner {
+			.cl-popup__inner {
 				@apply rounded-t-2xl;
 			}
 		}
@@ -588,11 +605,11 @@ defineExpose({
 	&--center {
 		@apply flex flex-col items-center justify-center;
 
-		.cl-popup {
+		& > .cl-popup {
 			transform: scale(1.3);
 			opacity: 0;
 
-			&__inner {
+			.cl-popup__inner {
 				@apply rounded-2xl;
 			}
 		}

+ 1 - 1
uni_modules/cool-ui/components/cl-select-trigger/cl-select-trigger.uvue

@@ -148,7 +148,7 @@ function open() {
 
 <style lang="scss" scoped>
 .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;
 	height: 66rpx;
 	padding: 0 20rpx;