소스 검색

```
feat(App): 添加登录和注册按钮及登录弹框组件

在顶部导航栏中添加了“登录”文本按钮和“注册”主按钮,并引入了登录弹框组件。
新增 `LoginDialog` 组件,通过 `v-model` 控制显示状态,并提供登录成功回调处理函数。
同时增加了相关响应式数据和方法用于控制弹框的打开与交互逻辑。
```

zhangningning 2 주 전
부모
커밋
8b7c2aaf02
4개의 변경된 파일695개의 추가작업 그리고 0개의 파일을 삭제
  1. 20 0
      src/App.vue
  2. BIN
      src/assets/imgs/QQ.png
  3. BIN
      src/assets/imgs/WeChat.png
  4. 675 0
      src/components/LoginDialog.vue

+ 20 - 0
src/App.vue

@@ -32,6 +32,9 @@
                 </el-dropdown-menu>
               </template>
             </el-dropdown>
+            <!-- 打开登录弹框 -->
+            <el-button type="text" @click="openLoginDialog">登录</el-button>  
+            <el-button type="primary">注册</el-button>
             <LangSwitch />
           </div>
         </div>
@@ -48,11 +51,14 @@
         </div>
       </el-footer>
     </el-container>
+    <!-- 登录弹框组件 -->
+    <LoginDialog v-model="showLoginDialog" ref="loginDialogRef" @login-success="handleLoginSuccess" />
     </ElConfigProvider>
   </div>
 </template>
 
 <script setup>
+import LoginDialog from './components/LoginDialog.vue'
 import { computed,ref } from 'vue'
 import LangSwitch from './components/LangSwitch.vue'
 import { ElConfigProvider } from 'element-plus'
@@ -69,7 +75,21 @@ langStore.updateDynamicTitle()
 const route = useRoute()
 const router = useRouter()
 
+// 登录弹框引用
+const loginDialogRef = ref(null)
+// 登录弹框显示状态
+const showLoginDialog = ref(false)
 
+// 打开登录弹框
+const openLoginDialog = () => {
+  showLoginDialog.value = true;
+}
+// 处理登录成功
+const handleLoginSuccess = () => {
+  console.log('登录成功')
+  // 可以在这里处理登录后的逻辑,比如更新用户信息、刷新页面等
+}
+//
 function goMyLearning() {
   router.push('/my-learning')
 };

BIN
src/assets/imgs/QQ.png


BIN
src/assets/imgs/WeChat.png


+ 675 - 0
src/components/LoginDialog.vue

@@ -0,0 +1,675 @@
+<template>
+  <el-dialog
+    v-model="dialogVisible"
+    :title="''"
+    width="420px"
+    center
+    custom-class="login-dialog"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+  >
+    <!-- 登录标题 -->
+    <div class="login-header">
+      <h2 class="login-title">欢迎回来</h2>
+      <p class="login-subtitle">请登录您的账号</p>
+    </div>
+    
+    <el-tabs v-model="activeTab" @tab-change="handleTabChange" class="login-tabs">
+      <el-tab-pane label="账号密码登录" name="password">
+        <el-form ref="passwordFormRef" :model="passwordForm" :rules="passwordRules" label-width="0">
+          <el-form-item prop="username" class="login-form-item">
+            <el-input
+              v-model="passwordForm.username"
+              placeholder="请输入账号"
+              prefix-icon="User"
+              clearable
+              class="login-input"
+            />
+          </el-form-item>
+          <el-form-item prop="password" class="login-form-item">
+            <el-input
+              v-model="passwordForm.password"
+              type="password"
+              placeholder="请输入密码"
+              prefix-icon="Lock"
+              show-password
+              class="login-input"
+            />
+          </el-form-item>
+          <el-form-item class="login-form-item remember-item">
+            <el-checkbox v-model="passwordForm.remember" class="remember-checkbox">
+              <span class="remember-text">记住密码</span>
+            </el-checkbox>
+            <el-link type="primary" href="#" :underline="false" class="forgot-link">忘记密码?</el-link>
+          </el-form-item>
+          <el-form-item class="login-form-item">
+            <el-button 
+              type="primary" 
+              @click="handlePasswordLogin" 
+              :loading="loading" 
+              class="login-button"
+              size="large"
+            >
+              登录
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </el-tab-pane>
+      
+      <el-tab-pane label="短信登录" name="sms">
+        <el-form ref="smsFormRef" :model="smsForm" :rules="smsRules" label-width="0">
+          <el-form-item prop="phone" class="login-form-item">
+            <el-input
+              v-model="smsForm.phone"
+              placeholder="请输入手机号"
+              prefix-icon="Mobile"
+              clearable
+              class="login-input"
+            />
+          </el-form-item>
+          <el-form-item prop="smsCode" class="login-form-item">
+            <el-input
+              v-model="smsForm.smsCode"
+              placeholder="请输入验证码"
+              prefix-icon="Message"
+              clearable
+              class="login-input"
+            >
+              <template #append>
+                <el-button
+                  type="primary"
+                  :disabled="smsCountdown > 0"
+                  @click="sendSmsCode"
+                  :class="{'countdown-btn': smsCountdown > 0}"
+                  size="small"
+                >
+                  {{ smsCountdown > 0 ? `${smsCountdown}s` : '发送验证码' }}
+                </el-button>
+              </template>
+            </el-input>
+          </el-form-item>
+          <el-form-item class="login-form-item">
+            <el-button 
+              type="primary" 
+              @click="handleSmsLogin" 
+              :loading="loading" 
+              class="login-button"
+              size="large"
+            >
+              登录
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </el-tab-pane>
+      
+      <el-tab-pane label="邮箱登录" name="email">
+        <el-form ref="emailFormRef" :model="emailForm" :rules="emailRules" label-width="0">
+          <el-form-item prop="email" class="login-form-item">
+            <el-input
+              v-model="emailForm.email"
+              placeholder="请输入邮箱"
+              prefix-icon="Email"
+              clearable
+              class="login-input"
+            />
+          </el-form-item>
+          <el-form-item prop="emailCode" class="login-form-item">
+            <el-input
+              v-model="emailForm.emailCode"
+              placeholder="请输入验证码"
+              prefix-icon="Message"
+              clearable
+              class="login-input"
+            >
+              <template #append>
+                <el-button
+                  type="primary"
+                  :disabled="emailCountdown > 0"
+                  @click="sendEmailCode"
+                  :class="{'countdown-btn': emailCountdown > 0}"
+                  size="small"
+                >
+                  {{ emailCountdown > 0 ? `${emailCountdown}s` : '发送验证码' }}
+                </el-button>
+              </template>
+            </el-input>
+          </el-form-item>
+          <el-form-item class="login-form-item">
+            <el-button 
+              type="primary" 
+              @click="handleEmailLogin" 
+              :loading="loading" 
+              class="login-button"
+              size="large"
+            >
+              登录
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </el-tab-pane>
+    </el-tabs>
+
+    <!-- 其他登录方式 -->
+    <div class="other-login">
+      <div class="divider">
+        <span class="divider-text">其他登录方式</span>
+      </div>
+      <div class="social-login">
+        <el-button
+          type="default"
+          @click="handleWechatLogin"
+          class="social-btn wechat-btn"
+        >
+          <img :src="WeChatIcon" alt="微信登录" style="width: 24px; height: 24px;">
+        </el-button>
+        <el-button
+          type="default"
+          @click="handleQqLogin"
+          class="social-btn qq-btn"
+        >
+          <img :src="QQIcon" alt="微信登录" style="width: 24px; height: 24px;">
+        </el-button>
+      </div>
+    </div>
+    
+    <!-- 注册链接 -->
+    <div class="register-link">
+      <span>还没有账号?</span>
+      <el-link type="primary" href="#" :underline="false">立即注册</el-link>
+    </div>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, reactive, watch } from 'vue'
+import { ElMessage } from 'element-plus'
+import QQIcon from '@/assets/imgs/QQ.png'
+import WeChatIcon from '@/assets/imgs/WeChat.png'
+
+// 定义props和emit
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false
+  }
+})
+
+const emit = defineEmits(['update:modelValue', 'login-success'])
+
+// 对话框可见性
+const dialogVisible = ref(props.modelValue)
+
+// 监听对话框可见性变化
+watch(() => dialogVisible.value, (newVal) => {
+  emit('update:modelValue', newVal)
+})
+
+// 监听props变化
+watch(() => props.modelValue, (newVal) => {
+  dialogVisible.value = newVal
+})
+
+// 当前激活的标签页
+const activeTab = ref('password')
+
+// 密码登录表单
+const passwordForm = reactive({
+  username: '',
+  password: '',
+  remember: false
+})
+
+// 短信登录表单
+const smsForm = reactive({
+  phone: '',
+  smsCode: ''
+})
+
+// 邮箱登录表单
+const emailForm = reactive({
+  email: '',
+  emailCode: ''
+})
+
+// 表单引用
+const passwordFormRef = ref(null)
+const smsFormRef = ref(null)
+const emailFormRef = ref(null)
+
+// 加载状态
+const loading = ref(false)
+
+// 验证码倒计时
+const smsCountdown = ref(0)
+const emailCountdown = ref(0)
+
+// 表单验证规则
+const passwordRules = reactive({
+  username: [
+    { required: true, message: '请输入账号', trigger: 'blur' }
+  ],
+  password: [
+    { required: true, message: '请输入密码', trigger: 'blur' },
+    { min: 6, message: '密码长度不能少于6个字符', trigger: 'blur' }
+  ]
+})
+
+const smsRules = reactive({
+  phone: [
+    { required: true, message: '请输入手机号', trigger: 'blur' },
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
+  ],
+  smsCode: [
+    { required: true, message: '请输入验证码', trigger: 'blur' },
+    { min: 6, max: 6, message: '验证码长度为6个字符', trigger: 'blur' }
+  ]
+})
+
+const emailRules = reactive({
+  email: [
+    { required: true, message: '请输入邮箱', trigger: 'blur' },
+    { type: 'email', message: '请输入正确的邮箱', trigger: 'blur' }
+  ],
+  emailCode: [
+    { required: true, message: '请输入验证码', trigger: 'blur' },
+    { min: 6, max: 6, message: '验证码长度为6个字符', trigger: 'blur' }
+  ]
+})
+
+// 处理标签页切换
+const handleTabChange = () => {
+  // 切换标签页时重置表单
+  if (activeTab.value === 'password') {
+    passwordFormRef.value?.resetFields()
+  } else if (activeTab.value === 'sms') {
+    smsFormRef.value?.resetFields()
+  } else if (activeTab.value === 'email') {
+    emailFormRef.value?.resetFields()
+  }
+}
+
+// 发送短信验证码
+const sendSmsCode = () => {
+  if (!smsForm.phone) {
+    ElMessage.warning('请先输入手机号')
+    return
+  }
+
+  // 验证手机号格式
+  const phoneRegex = /^1[3-9]\d{9}$/
+  if (!phoneRegex.test(smsForm.phone)) {
+    ElMessage.warning('请输入正确的手机号')
+    return
+  }
+
+  // 模拟发送验证码
+  ElMessage.success('验证码发送成功')
+  
+  // 开始倒计时
+  smsCountdown.value = 60
+  const timer = setInterval(() => {
+    smsCountdown.value--
+    if (smsCountdown.value <= 0) {
+      clearInterval(timer)
+    }
+  }, 1000)
+}
+
+// 发送邮箱验证码
+const sendEmailCode = () => {
+  if (!emailForm.email) {
+    ElMessage.warning('请先输入邮箱')
+    return
+  }
+
+  // 模拟发送验证码
+  ElMessage.success('验证码发送成功')
+  
+  // 开始倒计时
+  emailCountdown.value = 60
+  const timer = setInterval(() => {
+    emailCountdown.value--
+    if (emailCountdown.value <= 0) {
+      clearInterval(timer)
+    }
+  }, 1000)
+}
+
+// 密码登录
+const handlePasswordLogin = () => {
+  passwordFormRef.value?.validate((valid) => {
+    if (valid) {
+      loading.value = true
+      // 模拟登录请求
+      setTimeout(() => {
+        loading.value = false
+        ElMessage.success('登录成功')
+        emit('login-success', { type: 'password', userInfo: passwordForm })
+        dialogVisible.value = false
+      }, 1500)
+    }
+  })
+}
+
+// 短信登录
+const handleSmsLogin = () => {
+  smsFormRef.value?.validate((valid) => {
+    if (valid) {
+      loading.value = true
+      // 模拟登录请求
+      setTimeout(() => {
+        loading.value = false
+        ElMessage.success('登录成功')
+        emit('login-success', { type: 'sms', userInfo: smsForm })
+        dialogVisible.value = false
+      }, 1500)
+    }
+  })
+}
+
+// 邮箱登录
+const handleEmailLogin = () => {
+  emailFormRef.value?.validate((valid) => {
+    if (valid) {
+      loading.value = true
+      // 模拟登录请求
+      setTimeout(() => {
+        loading.value = false
+        ElMessage.success('登录成功')
+        emit('login-success', { type: 'email', userInfo: emailForm })
+        dialogVisible.value = false
+      }, 1500)
+    }
+  })
+}
+
+// 微信登录
+const handleWechatLogin = () => {
+  ElMessage.info('微信登录功能开发中')
+}
+
+// QQ登录
+const handleQqLogin = () => {
+  ElMessage.info('QQ登录功能开发中')
+}
+</script>
+
+<style scoped lang="scss">
+/* 登录对话框容器 */
+.login-dialog {
+  .el-dialog__header {
+    padding: 0;
+  }
+  
+  .el-dialog__body {
+    padding: 20px 30px 30px;
+  }
+  
+  .el-dialog__footer {
+    display: none;
+  }
+}
+
+/* 登录标题 */
+.login-header {
+  text-align: center;
+  margin-bottom: 30px;
+}
+
+.login-title {
+  font-size: 24px;
+  font-weight: 600;
+  color: #303133;
+  margin-bottom: 8px;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+  background-clip: text;
+}
+
+.login-subtitle {
+  font-size: 14px;
+  color: #909399;
+}
+
+/* 标签页 */
+.login-tabs {
+  margin-bottom: 20px;
+  
+  .el-tabs__nav {
+    justify-content: center;
+  }
+  
+  .el-tabs__item {
+    font-size: 15px;
+    color: #606266;
+    padding: 0 20px;
+  }
+  
+  .el-tabs__item.is-active {
+    color: #667eea;
+    font-weight: 500;
+  }
+  
+  .el-tabs__active-bar {
+    background-color: #667eea;
+    height: 3px;
+  }
+}
+
+/* 表单样式 */
+.login-form-item {
+  margin-bottom: 20px;
+}
+
+/* 输入框样式 */
+.login-input {
+  height: 48px;
+  border-radius: 24px;
+  // border: 1px solid #e4e7ed;
+  transition: all 0.3s ease;
+  font-size: 15px;
+  
+  &:hover {
+    // border-color: #667eea;
+    // box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1);
+  }
+  
+  &.is-focus {
+    // border-color: #667eea;
+    // box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2);
+  }
+  
+  .el-input__wrapper {
+    box-shadow: none;
+    background-color: #fafafa;
+    border-radius: 24px;
+  }
+  
+  .el-input__inner {
+    background-color: transparent;
+    border: none;
+    height: 48px;
+    line-height: 48px;
+  }
+}
+
+/* 记住密码和忘记密码 */
+.remember-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 25px;
+}
+
+.remember-checkbox {
+  .el-checkbox__input.is-checked .el-checkbox__inner {
+    background-color: #667eea;
+    border-color: #667eea;
+  }
+  
+  .el-checkbox__input.is-checked + .el-checkbox__label {
+    color: #667eea;
+  }
+}
+
+.remember-text {
+  font-size: 14px;
+  color: #606266;
+}
+
+.forgot-link {
+  font-size: 14px;
+  color: #667eea;
+  transition: color 0.3s ease;
+  
+  &:hover {
+    color: #5366d1;
+  }
+}
+
+/* 登录按钮 */
+.login-button {
+  width: 100%;
+  height: 48px;
+  border-radius: 24px;
+  font-size: 16px;
+  font-weight: 500;
+  border: none;
+  transition: all 0.3s ease;
+  
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
+  }
+  
+  &:active {
+    transform: translateY(0);
+  }
+}
+
+/* 其他登录方式 */
+.other-login {
+  margin-top: 30px;
+}
+
+.divider {
+  position: relative;
+  text-align: center;
+  margin-bottom: 20px;
+  
+  &::before, &::after {
+    content: '';
+    position: absolute;
+    top: 50%;
+    width: 40%;
+    height: 1px;
+    background-color: #ebeef5;
+  }
+  
+  &::before {
+    left: 0;
+  }
+  
+  &::after {
+    right: 0;
+  }
+}
+
+.divider-text {
+  display: inline-block;
+  padding: 0 20px;
+  font-size: 13px;
+  color: #909399;
+  background-color: #fff;
+}
+
+/* 社交登录按钮 */
+.social-login {
+  display: flex;
+  justify-content: center;
+  gap: 20px;
+}
+
+.social-btn {
+  width: 44px;
+  height: 44px;
+  border-radius: 50%;
+  transition: all 0.3s ease;
+  border: 1px solid #e4e7ed;
+  
+  &:hover {
+    transform: translateY(-3px);
+    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
+  }
+}
+
+.wechat-btn {
+  color: #67c23a;
+  
+  &:hover {
+    border-color: #67c23a;
+    background-color: rgba(103, 194, 58, 0.05);
+  }
+}
+
+.qq-btn {
+  color: #409eff;
+  
+  &:hover {
+    border-color: #409eff;
+    background-color: rgba(64, 158, 255, 0.05);
+  }
+}
+
+/* 注册链接 */
+.register-link {
+  text-align: center;
+  margin-top: 25px;
+  font-size: 14px;
+  color: #606266;
+  
+  .el-link {
+    margin-left: 5px;
+    color: #667eea;
+    font-weight: 500;
+    
+    &:hover {
+      color: #5366d1;
+    }
+  }
+}
+
+/* 验证码按钮 */
+.countdown-btn {
+  background-color: #f5f7fa;
+  color: #909399;
+  border-color: #e4e7ed;
+  
+  &:hover {
+    background-color: #e4e7ed;
+    border-color: #dcdfe6;
+  }
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .login-dialog {
+    width: 90% !important;
+    margin: 0 auto;
+    
+    .el-dialog__body {
+      padding: 20px;
+    }
+  }
+  
+  .login-title {
+    font-size: 22px;
+  }
+  
+  .login-input,
+  .login-button {
+    height: 44px;
+  }
+}
+</style>