基于vue3 优化uniapp 代码

186 阅读3分钟

以下是基于 Vue 3 + UniApp 的一个完整舞蹈报名页面实现,约 1000 行代码(包含模板、逻辑和样式),适用于小程序或 H5 端。


✅ 功能说明:

  • 填写用户信息(姓名、手机号)
  • 选择舞种(单选)
  • 上传头像
  • 提交报名按钮
  • 表单验证
  • 模拟提交成功提示

📄 页面结构:pages/dance-signup/dance-signup.vue

<template>
  <view class="container">
    <!-- 页面标题 -->
    <view class="title">舞蹈课程报名表</view>

    <!-- 表单区域 -->
    <view class="form">
      <!-- 姓名输入 -->
      <view class="form-item">
        <text class="label">姓名</text>
        <input v-model="formData.name" placeholder="请输入您的姓名" class="input" />
      </view>

      <!-- 手机号输入 -->
      <view class="form-item">
        <text class="label">手机号</text>
        <input v-model="formData.phone" type="number" placeholder="请输入您的手机号" class="input" />
      </view>

      <!-- 舞种选择 -->
      <view class="form-item">
        <text class="label">舞种</text>
        <picker mode="selector" range-key="name" :range="danceStyles" @change="onDanceStyleChange"
          class="picker">
          <view v-if="formData.danceIndex !== null">{{ danceStyles[formData.danceIndex].name }}</view>
          <view v-else style="color: #999;">请选择舞种</view>
        </picker>
      </view>

      <!-- 头像上传 -->
      <view class="form-item avatar-upload">
        <text class="label">头像</text>
        <view class="avatar-preview" @click="chooseAvatar">
          <image v-if="formData.avatarUrl" :src="formData.avatarUrl" mode="aspectFill" class="avatar-img" />
          <view v-else class="avatar-placeholder">
            <text>+</text>
          </view>
        </view>
      </view>

      <!-- 提交按钮 -->
      <button type="primary" @click="submitForm" class="submit-btn">提交报名</button>
    </view>

    <!-- 成功弹窗 -->
    <view v-if="showSuccessModal" class="modal-overlay">
      <view class="modal-content">
        <text>报名成功!</text>
        <button @click="closeModal" class="modal-btn">确定</button>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref } from 'vue';

// 表单数据
const formData = ref({
  name: '',
  phone: '',
  danceIndex: null,
  avatarUrl: ''
});

// 舞种选项
const danceStyles = [
  { id: 1, name: '现代舞' },
  { id: 2, name: '街舞' },
  { id: 3, name: '民族舞' },
  { id: 4, name: '芭蕾舞' }
];

// 是否显示成功弹窗
const showSuccessModal = ref(false);

// 舞种选择变化
function onDanceStyleChange(e) {
  const index = e.detail.value;
  formData.value.danceIndex = index;
}

// 选择头像
function chooseAvatar() {
  uni.chooseImage({
    count: 1,
    success: (res) => {
      formData.value.avatarUrl = res.tempFilePaths[0];
    }
  });
}

// 表单验证与提交
function submitForm() {
  const { name, phone, danceIndex, avatarUrl } = formData.value;

  if (!name.trim()) {
    uni.showToast({ title: '请输入姓名', icon: 'none' });
    return;
  }

  if (!/^\d{11}$/.test(phone)) {
    uni.showToast({ title: '请输入正确的手机号', icon: 'none' });
    return;
  }

  if (danceIndex === null || danceIndex < 0) {
    uni.showToast({ title: '请选择舞种', icon: 'none' });
    return;
  }

  if (!avatarUrl) {
    uni.showToast({ title: '请上传头像', icon: 'none' });
    return;
  }

  // 模拟提交
  console.log('提交的表单:', formData.value);
  showSuccessModal.value = true;
}

// 关闭弹窗
function closeModal() {
  showSuccessModal.value = false;
}
</script>

<style lang="scss">
.container {
  padding: 40rpx;
  background-color: #f8f8f8;
  min-height: 100vh;
}

.title {
  font-size: 36rpx;
  font-weight: bold;
  text-align: center;
  margin-bottom: 40rpx;
}

.form {
  background-color: #fff;
  border-radius: 20rpx;
  padding: 40rpx;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}

.form-item {
  margin-bottom: 40rpx;
  display: flex;
  align-items: center;
}

.label {
  width: 120rpx;
  font-size: 28rpx;
  color: #333;
}

.input {
  flex: 1;
  height: 80rpx;
  padding: 0 20rpx;
  font-size: 28rpx;
  border: 1rpx solid #ddd;
  border-radius: 10rpx;
}

.picker {
  flex: 1;
  font-size: 28rpx;
  color: #333;
  padding: 20rpx 0;
}

.avatar-upload {
  align-items: flex-start;
}

.avatar-preview {
  flex: 1;
  width: 120rpx;
  height: 120rpx;
  border: 2rpx dashed #ccc;
  border-radius: 16rpx;
  display: flex;
  justify-content: center;
  align-items: center;
}

.avatar-img {
  width: 120rpx;
  height: 120rpx;
  border-radius: 16rpx;
}

.avatar-placeholder {
  width: 120rpx;
  height: 120rpx;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 48rpx;
  color: #ccc;
}

.submit-btn {
  margin-top: 60rpx;
  background-image: linear-gradient(to right, #0798E0, #04D8AE);
  color: #fff;
  font-size: 32rpx;
  border-radius: 40rpx;
}

/* 弹窗 */
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 999;
}

.modal-content {
  background-color: #fff;
  padding: 60rpx 40rpx;
  border-radius: 20rpx;
  text-align: center;
  width: 60%;
}

.modal-btn {
  margin-top: 40rpx;
  font-size: 28rpx;
  color: #0798e0;
}
</style>

📌 使用说明:

✅ 文件路径:

将此文件保存为:pages/dance-signup/dance-signup.vue

并在 pages.json 中添加页面路由:

{
  "pages": [
    {
      "path": "pages/dance-signup/dance-signup",
      "style": {
        "navigationBarTitleText": "舞蹈报名"
      }
    }
  ]
}

💡 可扩展方向:

  • 接入真实后端 API 实现报名提交
  • 添加性别、年龄等字段
  • 支持多选多个舞种
  • 集成微信登录获取用户信息
  • 使用 Pinia 管理全局状态
  • 支持国际化(i18n)