Vue實戰系列(一) - 最簡化登錄頁面


1. 創建項目骨架

# 1. 利用Vue-CLI創建項目
vue create vue-login

#2. 添加依賴框架

# 進入到項目根目錄
cd vue-login

# 添加 element,一個 element 風格的 UI 框架
vue add element

# 安裝 axios,用於網絡請求
npm install axios

# 安裝 Vuex,用於管理狀態
npm install vuex --save

# 安裝 路由,用於實現兩個 Vue 頁面的跳轉
npm install vue-router

 

2. 創建相應功能的目錄結構,進行分層開發

- api (網絡請求接口包)
- router (路由配置包)
- store (Vuex 狀態管理包)
- utils (工具包)
- views (vue 視圖包,存放所有 vue 代碼,可根據功能模塊進行相應分包)

 

3. 運行項目
npm run serve

在瀏覽器輸入:http://localhost:8080/

 

 4. View 層代碼編寫

編寫三個 vue 文件:
login.vue(登錄頁面)
success.vue(登錄成功頁面)
error.vue(登錄失敗頁面)

 

login.vue

<template>
  <div>
    <el-card class="login-form-layout">
      <el-form
        autocomplete="on"
        :model="loginForm"
        ref="loginForm"
        label-position="left"
      >
        <div style="text-align: center">
          <svg-icon icon-class="login-mall" style="width: 56px;height: 56px;color: #409EFF"></svg-icon>
        </div>
        <h2 class="login-title color-main">登錄頁面</h2>
        <el-form-item prop="username">
          <el-input
            name="username"
            type="text"
            v-model="loginForm.username"
            autocomplete="on"
            placeholder="請輸入用戶名"
          >
            <span slot="prefix">
              <svg-icon icon-class="user" class="color-main"></svg-icon>
            </span>
          </el-input>
        </el-form-item>
        <el-form-item prop="password">
          <el-input
            name="password"
            :type="pwdType"
            @keyup.enter.native="handleLogin"
            v-model="loginForm.password"
            autocomplete="on"
            placeholder="請輸入密碼"
          >
            <span slot="prefix">
              <svg-icon icon-class="password" class="color-main"></svg-icon>
            </span>
            <span slot="suffix" @click="showPwd">
              <svg-icon icon-class="eye" class="color-main"></svg-icon>
            </span>
          </el-input>
        </el-form-item>
        <el-form-item style="margin-bottom: 60px">
          <el-button
            style="width: 100%"
            type="primary"
            :loading="loading"
            @click.native.prevent="handleLogin"
          >登錄</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<script>
export default {
  name: "login",
  data() {
    return {
      loginForm: {
        username: "admin",
        password: "123456"
      },
      loading: false,
      pwdType: "password",
    };
  },
  methods: {
    showPwd() {
      if (this.pwdType === "password") {
        this.pwdType = "";
      } else {
        this.pwdType = "password";
      }
    },
    handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true;
          this.$store
            .dispatch("Login", this.loginForm)
            .then(response => {
              this.loading = false;
              let code = response.data.code;
              if (code == 200) {
                this.$router.push({
                  path: "/success",
                  query: { data: response.data.data }
                });
              } else {
                this.$router.push({
                  path: "/error",
                  query: { message: response.data.message }
                });
              }
            })
            .catch(() => {
              this.loading = false;
            });
        } else {
          // eslint-disable-next-line no-console
          console.log("參數驗證不合法!");
          return false;
        }
      });
    }
  }
};
</script>

<style scoped>
.login-form-layout {
  position: absolute;
  left: 0;
  right: 0;
  width: 360px;
  margin: 140px auto;
  border-top: 10px solid #409eff;
}

.login-title {
  text-align: center;
}

.login-center-layout {
  background: #409eff;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  margin-top: 200px;
}
</style>

 

success.vue

<template>
  <div>
    <h1>Welcome!{{msg}}</h1>
  </div>
</template>
<script>
export default {
  data() {
    return {
      msg: this.$route.query.data
    };
  },
//   data() { //這種方式也可以
//     return {
//       msg: null
//     };
//   },
  // created() {
  //   this.msg = this.$route.query.data;
  // }
}
</script>

 

error.vue

<template>
  <div>
    <h1>登錄錯誤:{{msg}}</h1>
  </div>
</template>
<script>
export default {
  // data() {
  //   return {
  //     msg: this.$route.query.data
  //   };
  // }, //使用這種方式也可以顯示 msg
  data() {
    return {
      msg: null
    };
  },
  created() {
    this.msg = this.$route.query.message;
  }
};

 

5. 路由

頁面寫好了,我們需要依次顯示這三個頁面,這里我們統一使用路由來管理顯示頁面。

     5-1) 創建路由配置文件

     在router 文件夾下創建一個 index.js 文件,內容如下:

import Vue from 'vue' //引入 Vue
import VueRouter from 'vue-router' //引入 Vue 路由

Vue.use(VueRouter); //安裝插件

export const constantRouterMap = [
    //配置默認的路徑,默認顯示登錄頁
    { path: '/', component: () => import('@/views/login')},

    //配置登錄成功頁面,使用時需要使用 path 路徑來實現跳轉
    { path: '/success', component: () => import('@/views/success')},

    //配置登錄失敗頁面,使用時需要使用 path 路徑來實現跳轉
    { path: '/error', component: () => import('@/views/error'), hidden: true }
]

export default new VueRouter({
    // mode: 'history', //后端支持可開
    scrollBehavior: () => ({ y: 0 }),
    routes: constantRouterMap //指定路由列表

 

5-2) 將路由添加到程序入口

路由配置文件寫好,我們需要把他引入到 main.js 中。
在項目的 src 目錄根節點下,找到 main.js。

 

import Vue from 'vue'
import App from './App.vue'
import './plugins/element.js'
import router from './router' //引入路由配置
 
Vue.config.productionTip = false
 
new Vue({
  render: h => h(App),
  router, //使用路由配置
}).$mount('#app')

 

5-3) 配置路由的出入口

現在路由已經完全引入到項目了,但是路由還需要一個出入口,
這個出入口用來告訴路由將路由的內容顯示在這里。

修改 App.vue 內容如下:
<template>
  <div id="app">
    <!-- 路由的出入口,路由的內容將被顯示在這里 -->
    <router-view/>
  </div>
</template>
 
<script>
  export default {
    name: 'App'
  }
</script>

 

現在運行程序, 界面如下:

 

5-4) 路由跳轉

this.$router.push({path: "路徑"})
在 login.vue 中可以使用 this.$router.push({path: "路徑"}) 來跳轉到指定路徑的路由組件中,

路由跳轉核心代碼如下:
this.$router.push({path: "/success"}); //跳轉到成功頁

this.$router.push({path: "/error"}); //跳轉到失敗頁

完整代碼如下
login.vue

handleLogin() {
  this.$refs.loginForm.validate(valid => {
    if (valid) {
      this.loading = true;
      this.$store
        .dispatch("Login", this.loginForm)
        .then(response => {
          this.loading = false;
          let code = response.data.code;
          if (code == 200) {
            this.$router.push({
              path: "/success",
              query: { data: response.data.data }
            });
          } else {
            this.$router.push({
              path: "/error",
              query: { message: response.data.message }
            });
          }
        })
        .catch(() => {
          this.loading = false;
        });
    } else {
      // eslint-disable-next-line no-console
      console.log("參數驗證不合法!");
      return false;
    }
  });
}

 

6. 使用 Vuex + Axios 方式進行網絡請求

6-1) 利用Axios封裝請求

axios 是一個網絡請求構架,官方推薦使用這種方式進行 http 的請求。

a) 在 utils 包下封裝一個請求工具類 request.js
import axios from 'axios' //引入 axios
import baseUrl from '../api/baseUrl' //使用環境變量 + 模式的方式定義基礎URL
 
// 創建 axios 實例
const service = axios.create({
  baseURL: baseUrl, // api 的 base_url
  timeout: 15000, // 請求超時時間
})
 
export default service

 注: 這里的 baseUrl 涉及 Vue CLI3 的環境變量與模式的概念,見:Vue 環境變量和模式(設置通用baseUrl)

b) 登錄請求接口 API

在 api 文件夾下,創建一個登錄API文件
login.js
import request from '@/utils/request' //引入封裝好的 axios 請求
 
export function login(username, password) { //登錄接口
  return request({ //使用封裝好的 axios 進行網絡請求
    url: '/admin/login',
    method: 'post',
    data: { //提交的數據
      username,
      password
    }
  })
}
 
        
6-2) 使用 Vuex 封裝 axios

Vuex 是一個狀態管理構架。

a)封裝 Vuex 中的 module

在 store 文件夾下創建一個 modules 文件夾,然后在此文件夾下創建一個 user.js 文件
import { login } from '@/api/login'//引入登錄 api 接口
 
const user = {
  actions: {
    // 登錄
    Login({ commit }, userInfo) { //定義 Login 方法,在組件中使用 this.$store.dispatch("Login") 調用
      const username = userInfo.username.trim()
      return new Promise((resolve, reject) => { //封裝一個 Promise
        login(username, userInfo.password).then(response => { //使用 login 接口進行網絡請求
          commit('') //提交一個 mutation,通知狀態改變
          resolve(response) //將結果封裝進 Promise
        }).catch(error => {
          reject(error)
        })
      })
    },
  }
}
export default user

 

上面的代碼值得解釋一下:

1. 引接口 
引入 login 接口,之后使用登錄接口進行網絡請求。

2. 定義action 
定義一個 名為 Login 的 action 方法,方便Vue 組件通過 this.$store.dispatch("Login") 調用。

3. 封裝Promise
Promise,這個類很有意思,官方的解釋是“store.dispatch 可以處理被觸發的 action 的處理函數返回的 Promise,
並且 store.dispatch 仍舊返回 Promise”。
這話的意思組件中的 dispatch 返回的仍是一個 Promise 類。
因此Promise 中的兩個方法 resolve() 與 reject() 分別對應 dispatch 中的 then 與 catch

 

b) 創建 Vuex

在 store 文件夾下創建一個 index.js 文件
import Vue from 'vue' //引入 Vue
import Vuex from 'vuex' //引入 Vuex
import user from './modules/user' //引入 user module
 
Vue.use(Vuex)
 
const store = new Vuex.Store({
  modules: {
    user //使用 user.js 中的 action
  }
})
 
export default store

 

c) 將 Vuex 添加到 main.js 文件

修改之前的 main.js 文件如下:

import Vue from 'vue'
import App from './App.vue'
import './plugins/element.js'
import router from './router' //引入路由配置
import store from './store' //引入 Vuex 狀態管理
 
Vue.config.productionTip = false
 
new Vue({
  render: h => h(App),
  router, //使用路由配置
  store //使用 Vuex 進行狀態管理
}).$mount('#app')

 

7. 服務端接口

 

由於這是一篇主要講Vue的文章, 所以服務端接口這里我就一筆帶過了。

可以寫一個簡易的不帶數據庫的登錄接口(Java)如下:

@RestController
public class LoginController {
 
    @RequestMapping(value = "/admin/login", method = RequestMethod.POST)
    public CommonResult login(@RequestBody User user) {
        if (user.getUsername().equals("admin") && user.getPassword().equals("123456"))
            return CommonResult.success("admin");
        else
            return CommonResult.validateFailed();
    }
}

 

再次訪問頁面, 效果如下:

登錄成功

 

 

登錄失敗

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM