
怎么樣?哎喲,不錯哦。本文就帶大家一起用 Vue + Element-UI 把這個不錯的登錄頁面開發出來。
項目結構分析
在使用 Vue-CLI 創建 2.x 的腳手架項目后,會生成如下目錄文件:

針對這個目錄文件我寫了一個腦圖進行說明:
(文字稍微有點多,趕時間的同學看紅色部分就可以了)

紅色最多的是 src 文件夾,寫的代碼大部分都是放在這個文件夾下面。
重要提示,一下就刷到這里,只看文字不看圖的同學,還是把圖多看幾秒哦,看不清楚,可以放大看,哈哈哈。
程序執行流程
按照我自己對 Vue 的理解,畫了一張幾個主要文件之間程序調用執行的流程圖:
(水平有限,有錯誤請指正)

圖中簡單描繪了 index.html、main.js、App.vue、store\index.js、router\index.js、views\login\index.vue 這幾個文件之間的調用邏輯。暫時沒有用到 components,因為登錄界面不涉及到功能組件,只是個頁面,代碼放在 views 文件夾下即可。
哈哈我又來提醒了,只看文字不看圖的同學,多看幾眼,看不清楚,請放大!
源碼
本文接下來會對這些文件逐個進行代碼解析,為了不讓文章變得冗長,只貼部分代碼,完整代碼請到 GitHub 獲取:
https://github.com/dongfanger/sprint-frontend
如果想把這個項目復原出來,只看我寫的文章是不夠的,git clone
,順手點個 star,學習效果更好哦。
index.html
index.html 是項目中唯一的 html 文件。
因為 Vue 實現的是單頁面應用。單頁面應用,簡單理解就是只有一個頁面,其他頁面都是通過組件的形式掛載到這個頁面上的,這樣頁面切換就會更快速,如桌面應用一般絲滑順暢。
其他頁面的掛載點其實就是一個 div,其他頁面都在放在這個 div 里面的:
<div id="app"></div>
views\login\index.vue
本項目是基於 Element-UI 的,需要使用 npm 安裝一下
npm i element-ui -S
.vue 文件是 Vue 框架的代碼文件,分為3個部分
<template>
html 模板
</template>
<script>
javascript 腳本
</script>
<style lang="scss" scoped>
css 樣式
</style>
為了文章簡潔,本文不展示 css 樣式的代碼。
template html 模板代碼如下,實現了用戶名、密碼、登錄等輸入框和按鈕:
<template>
<div class="loginbody" :style="`background-image: url(${appInfo.backgroundImageUrl})`">
<div class="login-box">
<div class="login-title">
<img class="login-logo" :src="appInfo.loginLogoUrl" alt="logo" />
<p>{{ appInfo.title }}</p>
</div>
<div class="login-info">
<el-form ref="form" class="form-box" :model="form" :rules="formRules">
<el-form-item :label="'用戶名'" prop="username">
<el-input v-model="form.username" placeholder="請輸入用戶名" @keyup.enter.native="login" ref="username-input">
</el-input>
</el-form-item>
<el-form-item :label="'密碼'" prop="password">
<el-input
v-model="form.password"
placeholder="請輸入密碼"
type="password"
show-password
@keyup.enter.native="login"
></el-input>
</el-form-item>
<el-form-item>
<div class="clear">
<el-checkbox
v-model="form.rememberMe"
:value="true"
:label="'記住密碼'"
name="type"
class="remember-checkbox"
></el-checkbox>
<span class="self-right forgetPwd" @click="forgetPwd">忘記密碼?</span>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="login" class="login-btn" :loading="isLoging">
{{ "登錄" }}
</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
其中頁面背景圖、logo 圖、頁面標題是通過 Vuex 來存取的。
Vuex 是 Vue 的狀態管理工具。Vue 組件之間數據傳遞一般是通過 export 和 import 的方式,但是對於全局數據,這種方式很難管理和維護。Vuex 作為中間媒介,幫助組件之間更好的傳遞數據。
javascript 腳本代碼如下,給 template 模板填充數據,定義元素行為:
<script>
import { mapGetters } from "vuex";
export default {
data() {
return {
form: {
username: "",
password: "",
rememberMe: true
},
formRules: {
username: [
{ required: true, message: "請輸入用戶名", trigger: "blur" },
{
trigger: "blur",
},
],
password: [{ required: true, message: "請輸入密碼", trigger: "blur" }],
},
isLoging: false,
};
},
created() {
},
mounted() {
let autofocusElement = this.$refs["username-input"];
if (autofocusElement) {
autofocusElement.focus();
}
},
methods: {
login() {
},
forgetPwd() {
this.$alert("請聯系管理員!", "提示", {
confirmButtonText: "確定",
callback: action => {
this.$message({
type: "info",
message: `action: ${action}`,
});
},
});
},
},
computed: {
...mapGetters(["appInfo"]),
},
};
</script>
其中最后幾行的 appInfo 就是定義的全局變量,使用 Vuex 來傳遞數據。
store\index.js
appInfo 的實現代碼放在 store\index.js 文件中:
import Vue from 'vue'
import Vuex from 'vuex'
const navBarLogoUrl = require("@/assets/image/logo.png");
const loginLogoUrl = require("@/assets/image/logo@2x.png");
const backgroundImageUrl = require("@/assets/image/login-bg.png");
const favicon = require("@/assets/image/favicon.png");
Vue.use(Vuex)
export default new Vuex.Store({
state: {
appInfo: null,
},
getters: {
appInfo: state => {
if (state.appInfo) {
return state.appInfo;
}
let localAppInfo = localStorage.getItem("AppInfo");
if (localAppInfo) {
return JSON.parse(localAppInfo);
}
return {
dsp: "這是公眾號“測試老樹”開發的測試平台。",
navBarLogoUrl,
loginLogoUrl,
backgroundImageUrl,
faviconUrl: favicon,
title: "測試平台",
};
},
},
mutations: {
commitAppInfo(state, appInfo) {
state.appInfo = appInfo;
},
},
actions: {
setAppInfo({ commit }, appInfo) {
let info = {
dsp: appInfo.dsp,
title: appInfo.title || "測試平台",
navBarLogoUrl: appInfo.navBarLogoUrl || navBarLogoUrl,
loginLogoUrl: appInfo.loginLogoUrl || loginLogoUrl,
backgroundImageUrl: appInfo.backgroundImageUrl || backgroundImageUrl,
faviconUrl: appInfo.faviconUrl || favicon,
};
commit("commitAppInfo", info);
localStorage.setItem("AppInfo", JSON.stringify(info));
let { faviconUrl, title } = info;
let iconElement = document.querySelector("#t-icon");
iconElement.href = faviconUrl;
document.title = title;
},
},
modules: {},
});
App.vue
App.vue 是根組件,適合做一些初始化工作。
從“程序執行流程”小節的邏輯圖中可以看到,數據存儲的操作就是在 App.vue 調用的,代碼如下:
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
import { mapActions } from "vuex";
export default {
name: "App",
data() {
return {};
},
created() {
},
methods: {
...mapActions(["setAppInfo"]),
},
};
</script>
methods 調用了 setAppInfo 方法,給 appInfo 賦值。
router\index.js
到這里,登錄頁面的代碼就已經擼完了。是嗎?是的!
但是還無法訪問,因為還沒有給它配置路由,瀏覽器還不知道怎么才能跳轉到這個登錄頁面。
路由就是訪問路徑,讓瀏覽器知道輸入一個 url 該把哪個頁面展示給你看。在以前,頁面跳轉路由都是放到后端來做的,前端請求后端,后端把渲染好的 html 返回給前端。現在時代不同了,前端直接控制了路由,前后端傳遞的數據變少了,訪問體驗也更佳。比如以前地址欄 URL 跳轉可能會白屏,現在不會了。
路由配置代碼是放在 router\index.js 文件中的,默認 / 展示 Home 頁面,訪問 /login 展示 login 頁面:
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import login from "../views/login"
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home,
meta: {
requireAuth: true,
},
},
{
path: "/login",
meta: {
title: "測試平台登錄",
},
name: "login",
component: login,
},
]
const router = new VueRouter({
routes
})
但是首頁不能直接就給別人看呀,得先登錄!所以需要編寫一個攔截器,必須登錄后,才可以訪問首頁,否則跳轉到登錄頁面:
router.beforeEach((to, from, next) => {
if (to.matched.some(auth => auth.meta.requireAuth)) {
let token = localStorage.getItem("token");
if (token) {
next();
} else {
next({
path: "/login",
});
}
} else {
next();
}
});
main.js
main.js 是程序執行入口,以上所有代碼都需要在 main.js 中聲明一下:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import Element from "element-ui"
import "./assets/style/global.scss";
Vue.config.productionTip = false
Vue.use(Element)
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
vue.config.js
vue.config.js 是 Vue 項目配置文件。比如 index.html 中,頁面 title 是通過 <title><%= htmlWebpackPlugin.options.title %></title>
來定義的,可以在配置文件中添加自定義,為 “sprint”:
const path = require("path");
function resolve(dir) {
return path.join(__dirname, dir);
}
module.exports = {
publicPath: process.env.NODE_ENV === "development" ? "./" : "/frontend/",
chainWebpack: config => {
config.plugin("html").tap(args => {
args[0].title = "sprint";
return args;
});
},
};
簡要回顧
本文首先展示了登錄頁面的效果,接着介紹了 Vue-CLI 初始化之后的項目結構,並對程序執行邏輯進行了分析,梳理出來了主要幾個文件的調用流程,最后分別對各文件的代碼進行了分析。