| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- <template>
- <Teleport to="body">
- <!-- 遮罩层 -->
- <transition name="fade">
- <div class="modal-mask" v-if="visible" @click="close"></div>
- </transition>
- <!-- 底部弹窗面板 -->
- <transition name="slide-up">
- <div class="modal-panel" v-if="visible">
- <!-- 顶部小灰条 -->
- <div class="panel-handle"></div>
- <!-- 标题 -->
- <div class="panel-header">
- <h3 class="panel-title">设置自动锁定时间</h3>
- </div>
- <!-- 选项列表 -->
- <div class="option-list">
- <div
- class="option-item"
- v-for="item in options"
- :key="item"
- @click="selectItem(item)"
- >
- <span class="option-text">{{ item }}</span>
- <!-- 选中状态显示的红色对勾图标 -->
- <div class="check-icon" v-if="localSelected === item">
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
- <circle cx="12" cy="12" r="10" fill="#E02F44"/> <!-- 红色圆底 -->
- <path d="M7 12L10 15L17 8" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
- </svg>
- </div>
- </div>
- </div>
- <!-- 底部按钮 -->
- <div class="footer-action">
- <button class="confirm-btn" @click="handleConfirm">确认</button>
- </div>
- <!-- 底部安全区 -->
- <div class="safe-area-bottom"></div>
- </div>
- </transition>
- </Teleport>
- </template>
- <script setup>
- import { ref, watch } from 'vue';
- const props = defineProps({
- visible: Boolean,
- currentValue: String // 接收父组件当前的值
- });
- const emit = defineEmits(['update:visible', 'confirm']);
- // 选项数据
- const options = ['立即', '5分钟', '10分钟'];
- // 内部维护一个选中状态,用于显示对勾
- const localSelected = ref('');
- // 每次打开弹窗时,把父组件传来的值赋给内部状态
- watch(() => props.visible, (val) => {
- if (val) {
- localSelected.value = props.currentValue;
- }
- });
- const close = () => {
- emit('update:visible', false);
- };
- // 点击列表项(只更新 UI,不提交)
- const selectItem = (item) => {
- localSelected.value = item;
- };
- // 点击确认按钮(提交数据并关闭)
- const handleConfirm = () => {
- emit('confirm', localSelected.value);
- close();
- };
- </script>
- <style scoped>
- .modal-mask {
- position: fixed; top: 0; left: 0; right: 0; bottom: 0;
- background: rgba(0,0,0,0.5); z-index: 998;
- }
- .modal-panel {
- position: fixed; left: 0; right: 0; bottom: 0;
- background: #fff;
- z-index: 999;
- border-radius: 16px 16px 0 0;
- padding-bottom: 20px;
- }
- .panel-handle {
- width: 36px; height: 4px; background: #E0E0E0;
- border-radius: 2px; margin: 10px auto;
- }
- .panel-header {
- padding: 10px 20px 20px;
- }
- .panel-title {
- font-size: 18px; font-weight: 600; color: #333;
- }
- .option-list {
- padding: 0 20px 20px;
- }
- .option-item {
- display: flex; justify-content: space-between; align-items: center;
- height: 50px;
- font-size: 16px; color: #333;
- /* border-bottom: 1px solid #f5f5f5; 可选分割线 */
- cursor: pointer;
- }
- /* 底部按钮区 */
- .footer-action {
- padding: 10px 20px;
- }
- .confirm-btn {
- width: 100%; height: 48px;
- background: #E02F44; /* 截图中的红色 */
- color: #fff; border: none; border-radius: 24px;
- font-size: 16px; font-weight: 600;
- }
- .confirm-btn:active { opacity: 0.9; }
- .safe-area-bottom { height: env(safe-area-inset-bottom); }
- /* 动画 */
- .fade-enter-active, .fade-leave-active { transition: opacity 0.3s; }
- .fade-enter-from, .fade-leave-to { opacity: 0; }
- .slide-up-enter-active, .slide-up-leave-active { transition: transform 0.3s; }
- .slide-up-enter-from, .slide-up-leave-to { transform: translateY(100%); }
- </style>
|