怎麼樣?哎喲,不錯哦。本文就帶大家一起用 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 初始化之後的專案結構,並對程式執行邏輯進行了分析,梳理出來了主要幾個檔案的呼叫流程,最後分別對各檔案的程式碼進行了分析。