效果

image.png
image.png
image.png

2-1 修改登录页

添加数据效验和绑定

src/views/login/index.vue

  1. <template>
  2. <div class="login-container">
  3. <el-form
  4. class="login-form"
  5. :model="loginForm"
  6. :rules="loginRules"
  7. ref="loginFormRef"
  8. >
  9. <div class="admin-logo">
  10. <img class="logo" src="../../assets/logo.png" alt="logo">
  11. <h1 class="name">Vue3 Admin</h1>
  12. </div>
  13. <el-form-item prop="username">
  14. <span class="svg-container">
  15. <svg-icon icon-class="user"></svg-icon>
  16. </span>
  17. <el-input
  18. ref="usernameRef"
  19. placeholder="请输入用户名"
  20. v-model="loginForm.username"
  21. autocomplete="off"
  22. tabindex="1"
  23. />
  24. </el-form-item>
  25. <el-form-item prop="password">
  26. <span class="svg-container">
  27. <svg-icon icon-class="password"></svg-icon>
  28. </span>
  29. <el-input
  30. ref="passwordRef"
  31. :class="{
  32. 'no-autofill-pwd': passwordType === 'password'
  33. }"
  34. placeholder="请输入密码"
  35. v-model="loginForm.password"
  36. type="text"
  37. autocomplete="off"
  38. tabindex="2"
  39. />
  40. <span class="show-pwd" @click="showPwd">
  41. <svg-icon
  42. :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
  43. </span>
  44. </el-form-item>
  45. <!-- 登录按钮 -->
  46. <el-button
  47. type="primary"
  48. style=" width: 100%; margin-bottom: 30px"
  49. :loading="loading"
  50. @click="handleLogin"
  51. >Login</el-button>
  52. </el-form>
  53. </div>
  54. </template>
  55. <script lang="ts">
  56. import { defineComponent, ref, reactive, toRefs, onMounted } from 'vue'
  57. import { ElForm } from 'element-plus'
  58. type IElFormInstance = InstanceType<typeof ElForm>
  59. export default defineComponent({
  60. name: 'Login',
  61. setup() {
  62. const loading = ref(false) // 登录加载状态
  63. // form ref
  64. const loginFormRef = ref<IElFormInstance | null>(null)
  65. // form username ref
  66. const usernameRef = ref<HTMLInputElement | null>(null)
  67. // form password ref
  68. const passwordRef = ref<HTMLInputElement | null>(null)
  69. const loginState = reactive({
  70. loginForm: {
  71. username: '',
  72. password: ''
  73. },
  74. loginRules: {
  75. username: [
  76. {
  77. required: true,
  78. trigger: 'blur',
  79. message: '请输入用户名!'
  80. }
  81. ],
  82. password: [
  83. {
  84. required: true,
  85. trigger: 'blur',
  86. message: '请输入密码!'
  87. }
  88. ]
  89. },
  90. passwordType: 'password'
  91. })
  92. // 显示密码
  93. const showPwd = () => {
  94. loginState.passwordType = loginState.passwordType === 'password' ? 'text' : 'password'
  95. }
  96. // 登录
  97. const handleLogin = () => {
  98. console.log('login')
  99. ;(loginFormRef.value as IElFormInstance).validate((valid) => {
  100. if (valid) {
  101. console.log(loginState.loginForm)
  102. }
  103. })
  104. }
  105. // 自动获取焦点
  106. onMounted(() => {
  107. if (loginState.loginForm.username === '') {
  108. (usernameRef.value as HTMLInputElement).focus()
  109. } else if (loginState.loginForm.password === '') {
  110. (passwordRef.value as HTMLInputElement).focus()
  111. }
  112. })
  113. return {
  114. loading,
  115. loginFormRef,
  116. handleLogin,
  117. showPwd,
  118. usernameRef,
  119. passwordRef,
  120. ...toRefs(loginState)
  121. }
  122. }
  123. })
  124. </script>
  125. <style lang="scss">
  126. $bg:#283443;
  127. $light_gray:#fff;
  128. $cursor: #fff;
  129. .login-container {
  130. .el-form-item {
  131. border: 1px solid #dcdee2;
  132. border-radius: 5px;
  133. .el-input {
  134. display: inline-block;
  135. height: 40px;
  136. width: 85%;
  137. input {
  138. background: transparent;
  139. border: 0;
  140. -webkit-appearance: none;
  141. border-radius: 0px;
  142. padding: 12px 5px 12px 15px;
  143. height: 40px;
  144. }
  145. }
  146. }
  147. .no-autofill-pwd { // 解决自动填充问题
  148. .el-input__inner { // 模仿密码框原点
  149. -webkit-text-security: disc !important;
  150. }
  151. }
  152. }
  153. </style>
  154. <style lang="scss" scoped>
  155. $bg:#2d3a4b;
  156. $dark_gray:#889aa4;
  157. $light_gray:#eee;
  158. .login-container {
  159. min-height: 100%;
  160. width: 100%;
  161. overflow: hidden;
  162. background-image: url('../../assets/body.svg');
  163. background-repeat: no-repeat;
  164. background-position: 50%;
  165. background-size: 100%;
  166. .login-form {
  167. position: relative;
  168. width: 500px;
  169. max-width: 100%;
  170. margin: 0 auto;
  171. padding: 140px 35px 0;
  172. overflow: hidden;
  173. box-sizing: border-box;
  174. .svg-container {
  175. padding: 0 10px;
  176. }
  177. .show-pwd {
  178. font-size: 16px;
  179. cursor: pointer;
  180. margin-left: 7px;
  181. }
  182. .admin-logo {
  183. display: flex;
  184. align-items: center;
  185. justify-content: center;
  186. margin-bottom: 20px;
  187. .logo {
  188. width: 60px;
  189. height: 60px;
  190. }
  191. .name {
  192. font-weight: normal;
  193. margin-left: 10px;
  194. }
  195. }
  196. }
  197. }
  198. </style>

本节参考源码

https://gitee.com/brolly/vue3-element-admin/commit/189500e2991cda50c44d7d6e16c75c4fa6c5b19c