Vue3+TS硅谷甄选项目(五、登录页的搭建)

 1. 静态页面的搭建

//src/views/login/index.vue

<template>
  <div class="loginContainer">
    <el-row>
      <!-- 两列 -->
       <!-- 左边这一列当视口宽度小于768时不显示 -->
       <el-col :span="12" :xs="0">
       </el-col>
       <!-- 右边这一列要存放表单 -->
       <el-col :span="12" :xs="24">
          <el-form class="loginForm">
            <h1>Hello</h1>
            <h2>欢迎来到硅谷甄选</h2>
            <el-form-item>
              <el-input :prefix-icon="User" v-model="loginForm.username"></el-input>
            </el-form-item>
            <el-form-item>
              <el-input type="password" :prefix-icon="Lock" show-password v-model="loginForm.password"></el-input>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" class="loginBtn">登录</el-button>
            </el-form-item>
          </el-form>
       </el-col>
    </el-row>
  </div>
</template>

<script setup lang="ts">
import { User, Lock } from '@element-plus/icons-vue'
import { reactive } from 'vue';

//收集表单数据
const loginForm = reactive({username: 'admin', password: '111111'})

</script>

<style scoped lang="scss">
  .loginContainer {
    width: 100%;
    height: 100vh;
    background: url('@/assets/images/background.jpg') no-repeat;
    //背景覆盖整个容器
    background-size: cover;
    .loginForm {
      position: relative;
      top: 30vh;
      width: 80%;
      background: url("@/assets/images/login_form.png") no-repeat;
      background-size: cover;
      padding: 60px;
      h1 {
        color: #fff;
        font-size: 40px;
      }
      h2 {
        color: #fff;
        font-size: 20px;
        margin: 20px 0px;
      }
      .loginBtn {
        width: 100%;
      }
    }
  }
</style>

element-plus:

1. <el-row>行

2. <el-col>列,用grid布局,:span说明各站几格,:xs表示当宽度小于768时所占的格子数量

3. <el-form-item>存放表单元素的

4. <el-input>需要双向绑定收集数据,:prefix-icon则是前缀图标(这个图标需要从elementplus插件中引入。type表示这个input框的类型,show-password表示是否展示密码眼睛的空间)


 2. 登录页面业务

登录发请求(让仓库pinia发)

        登录成功,跳转到首页,并提示用户登录信息;

        登录失败,弹出登录失败的信息;

登录成功之后,还需要用token向服务器发请求,要本人的数据

 (1)配置pinia仓库

① 安装插件

pnpm i pinia

② 大仓库src/store/index.ts

//创建大仓库
import { createPinia } from "pinia";
const store = createPinia();
export default store;

③ 在main.ts中引入仓库

//引入仓库
import store from './store';
//注册仓库
app.use(store);

(2)创建存储用户信息的小仓库

//src/s trore/modules/user.ts


import { defineStore } from "pinia";
// import { ref } from "vue";
import { reqLogin } from "@/api/user";
import type { loginForm } from '@/api/user/type'

const useUserStore = defineStore('User', () => {
  //点击登录会发起请求,成功的话要存储token
  let token = localStorage.getItem('TOEKN');

  //发起登录请求
  const login = async (data: loginForm) => {
    //请求会返回一个promise
    const res = await reqLogin(data);
    // 如果请求成功,就得把数据存储起来
    if (res.code === 200) {
      token = res.data.token!;
      //要持久化
      localStorage.setItem('TOKEN', res.data.token!)
      return 'ok';
    } else {
      //请求失败,得返回一个错误
      return Promise.reject(new Error(res.data.message))
    }
  }
  return {
    token,
    login
  }
})

export default useUserStore

(3)用户点击登录发起请求

① /views/login.index.view

首先,为其添加点击事件

<el-form-item>
    <el-button type="primary" class="loginBtn" @click="loginBtnHandler" :loading="loading">登录</el-button>
</el-form-item>

其次,点击事件的回调函数

<script setup lang="ts">
import { User, Lock } from '@element-plus/icons-vue'
import { reactive, ref } from 'vue';
import useUserStore from '@/store/modules/user';
import { useRouter } from 'vue-router';
import { ElNotification } from 'element-plus';
import { getTimeInterval } from '@/utils/getTimeInterval';

//收集表单数据
const loginForm = reactive({username: 'admin', password: '111111'})
const userStore = useUserStore()
// 用户点击按钮后加载效果开启变量
const loading = ref(false);

const router = useRouter();

// //用户点击登录按钮的回调
const loginBtnHandler = async ()=>{
  // 发起请求需要loading
  loading.value = true
  //pinia中action函数会返回一个promise对象
  try {
    await userStore.login(loginForm)
    // 如果请求成功了还需要跳转页面,并提示用户
    router.push('/');
    ElNotification({
      type:'success',
      message: '欢迎回来',
      title: `Hi,${getTimeInterval()}好`
    })
  } catch (error) {
    ElNotification({
      type:'error',
      message: (error as Error).message
    })
  } finally {
    loading.value = false
  }
  
}
</script>

其中,getTimeInterval函数如下

//src/utils/getTimeInterval.ts


//用户获取登录成功之后打招呼的内容
export const getTimeInterval = () => {
  const hour = new Date().getHours()
  let message = ''

  if (hour <= 9) {
    message = '早上'
  } else if (hour <= 12) {
    message = '上午'
  } else if (hour <= 18) {
    message = '下午'
  } else if (hour <= 24) {
    message = '晚上'
  }
  return message
}

1. vue3中,要想跳转则需要引入useRouter,并创建实例router = userRouter(),在使用router.push()进行跳转

2. ElNotification组件和ElMessage组件差不多,都是提示用户的,但前者是侧边栏提示;后者是正中间提示

3. el-button组件上有个loading属性,用于显示加载中

问题1:我在发起请求的时候打印请求结果,发现是undefined,可是在调试面板中请求显示成功了

解决方法:原来是我请求API写错了,箭头函数写了{}就得写return

//登录接口
export const reqLogin = (data: loginForm) => { return request<any, loginRes>({ url: API.LOGIN_URL, method: 'post', data }) }

(4)表单校验

① <el-form>组件上绑定:model和:rules属性

<el-form class="loginForm" :model="loginForm" :rules="rules">

② <el-form-item>上绑定:prop属性'

<el-form-item prop="username">

prop绑定的名字必须和rules对应

rules如下

//表单校验规则
const rules = {
  username: [{require: true, min: 6, max: 10, message: '用户名至少6位,至多10位', trigger: 'change'}],
  password: [{require: true, min: 6, max: 15, message: '密码至少6位,至多15位', trigger: 'change'}]
}

③ 要等整个表单都通过校验后,才能发起请求

所以需要获取到<el-form>组件实例,然后里面有个方法validate,点击按钮就调用该方法进行校验

<el-form class="loginForm" :model="loginForm" :rules="rules" ref="formRef">

<script>
    //获取整个表单实例
    const formRef = ref()
    //用户点击登录按钮的回调
    const loginBtnHandler = async ()=>{
    //整个表单校验通过再发起请求,validate返回的是一个promise
    await formRef.value.validate()
    // 发起请求需要loading
    loading.value = true
    //pinia中action函数会返回一个promise对象
    try {
      await userStore.login(loginForm)
      // 如果请求成功了还需要跳转页面,并提示用户
      router.push('/');
      ElNotification({
        type:'success',
        message: '欢迎回来',
        title: `Hi,${getTimeInterval()}好`
      })
    } catch (error) {
      ElNotification({
        type:'error',
        message: (error as Error).message
      })
    } finally {
      loading.value = false
    }
  }
</script>

由于formRef是ref类型,记住要写.value

④ 自定义校验规则

//校验密码
const validatorPassword = (rule:any, value: any, callback: any)=>{
  if(value.length >= 6 && value.length <= 15) {
    callback()
  } else {
    callback(new Error('密码至少6位,至多15位'))
  }
}

//表单校验规则
const rules = {
  username: [
    // {require: true, min: 6, max: 10, message: '用户名至少6位,至多10位', trigger: 'change'},
    {trigger: 'change', validator: validatorUsername}
  ],
  password: [
    // {require: true, min: 6, max: 15, message: '密码至少6位,至多15位', trigger: 'change'},
    {trigger: 'change', validator: validatorPassword}
  ]
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值