測試平台開發(二) 高逼格登錄頁面


怎么樣?哎喲,不錯哦。本文就帶大家一起用 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 初始化之后的項目結構,並對程序執行邏輯進行了分析,梳理出來了主要幾個文件的調用流程,最后分別對各文件的代碼進行了分析。


免責聲明!

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



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