Koa & Mongoose & Vue實現先後端分離--06前端登陸&註冊

上節回顧

  • 荷載的解析
  • 服務端註冊&登陸邏輯
  • 數據庫的存儲 & 查詢

工做內容

  • 初始化前端環境
  • 建立前端路由
  • axios請求接口

準備工做

  • 全局安裝依賴 // 以便經過vue/cli初始化項目

├── @vue/cli@4.1.2css

├── @vue/cli-init@4.1.2前端

  • vue init webpack ./ // 先切換到/client目錄下

回答初始化問題

  • npm i -S axios // 先切換到/client目錄下

頁面邏輯

  • npm run start查看頁面是否能正常訪問localhost:8080

技術選型

本身的項目,沒特殊要求,選擇本身熟悉的element-uiUI庫、scss預編譯語言快速搭建頁面。vue

初始化頁面

// 更新文件:/client/src/App.vue
<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>
// 更新文件:/client/src/router/index.js
// 順便刪除文件:/client/src/components/Helloworld.vue
import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/views/login'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      redirect: '/login'
    },
    {
      path: '/login',
      name: 'login',
      component: Login
    }
  ]
})
// 新建文件: /client/src/views/login/index.vue
<template>
  <div>
    Login
  </div>
</template>

展現效果 //更新不及時,能夠重啓前端服務
Loginnode

引入element-uiscss

  • 安裝依賴:npm i -S element-ui node-scss sass-loader@7 // sass-loader安裝7.版本,目前最新版8.編譯失敗
  • 完整引入Element
// 更新文件:/client/src/main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import App from './App'
import router from './router'

Vue.config.productionTip = false
Vue.use(ElementUI)
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})
  • 測試可用性
// 更新文件:/client/src/views/login/index.vue
<template>
  <div>
    <el-button type="primary">Login</el-button>
    <p class="red">這是scss</p>
  </div>
</template>
<style lang="scss" scoped>
$color: red;
.red {
  color: $color;
}
</style>
  • 測試結果

Element

快速搭建頁面

爲了省事,直接從Element官網 > 組件 > Form表單,拷貝一份帶校驗的示例改改webpack

// 更新文件:/client/src/views/login/index.vue
<template>
  <div class="page-login">
    <el-form :ref="formName" class="form-login" :model="form" :rules="rules">
      <el-form-item label="賬號" prop="account">
        <el-input v-model="form.account" placeholder="請輸出賬號"></el-input>
      </el-form-item>
      <el-form-item label="密碼" prop="password">
        <el-input type="password" v-model="form.password" placeholder="請輸出密碼"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onLogin">登錄</el-button>
        <el-button type="primary" @click="onRegister">註冊</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
export default {
  name: 'Login',
  data () {
    return {
      formName: 'LoginForm',
      form: {
        account: '',
        password: ''
      },
      rules: {
        account: [
          { required: true, message: '請輸入賬號', trigger: 'blur' },
          { min: 5, message: '長度至少5個字符', trigger: 'blur' }
        ],
        password: [
          { required: true, message: '請輸入密碼', trigger: 'blur' },
          { min: 3, message: '長度至少3個字符', trigger: 'blur' }
        ]
      }
    }
  },
  methods: {
    async onLogin () {
      console.log('login')
    },
    async onRegister () {
      console.log('register')
    }
  }
}
</script>

<style lang="scss" scoped>
@import './index.scss';
</style>
// 新建文件:client/src/views/login/index.scss
.form-login {
  width: 600px;
  margin: 0 auto;
}
  • 頁面展現

Login頁面展現

添加http請求

在準備工做時,已經npm i -S axios安裝axiosios

// 新建配置文件:client/src/config/http.js
export const BASE_URL = 'http://localhost:3000/'
export const TIMEOUT = 15000
// 新建axios實例文件:client/src/utils/http.js
import axios from 'axios'
import { BASE_URL, TIMEOUT } from '@/config/http'

const instance = axios.create({
  baseURL: BASE_URL,
  timeout: TIMEOUT,
  validateStatus: function (status) {
    // return status >= 200 && status < 300; // default
    return status >= 200 // 可攔截狀態碼>=200的請求響應
  }
})

export default instance

注意:axios默認只返回Http Code爲2**請求的響應nginx

測試Http請求

//更新文件:server/control/users.js
async function list (ctx) {
  try {
    const users = await userModel.find(); //查出所有用戶
    ctx.body = {
      code: '200',
      data: users,
      msg: '查詢成功'
    }
  } catch (err) {
    ctx.body = {
      code: '403',
      data: null,
      msg: err.message
    }
  }
}
//更新文件:client/src/views/login/index.vue
...
<script>
import http from '@/utils/http'
...
  methods: {
    async onLogin () {
      console.log('register')
    },
    async onRegister () {
      console.log('register')
    }
  },
  async created () {
    const res = await http.get('/users')
    console.log(res)
  }
...
</script>
...
  • 效果展現

cors
發生跨域請求,這裏咱們切換到/server/目錄下,安裝依賴npm i -S koa2-cors(線上的話,可使用nginx作代理)git

// 更新文件:server/app.js
const koa = require('koa');
const bodyParser = require('koa-body');
const cors = require('koa2-cors');

const routes = require('./router');

const app = new koa();
app.use(cors());
...

重啓後端服務,便可在頁面http://localhost:8080/#/login看到請求結果
users請求github

過濾返回結果

從返回接口能夠看出,請求服務端成功時,只須要res.data便可,使用instance.interceptors對返回數據進行過濾。web

// 更新文件:client/src/utils/http.js
...
// Add a response interceptor
instance.interceptors.response.use(
  async res => {
    if (/^20./.test(res.status)) {
      return res.data
    }
    console.log('------response=======', res)
    return res
  },
  error => {
    return Promise.reject(error)
  }
)

export default instance

請求結果
interceptor

登陸邏輯

//更新文件:client/src/views/login/index.vue
...
    async onLogin () {
      try {
        const valid = await this.$refs[this.formName].validate()
        if (valid) {
          const { account, password } = this.form
          const res = await http.post(
            '/users?action=login',
            {
              account,
              password,
            }
          )
          console.log(res)
          if (res && res.code === '200') {
            this.$router.replace('/home')
          } else {
            this.$message({ // 沒有使用this.$message.error('')
              type: 'error',
              message: res.msg
            })
          }
        }
      } catch (err) {
        console.error(err)
      }
    },
...
  • this.$message({}),而沒有使用this.$message.error(),由於發現若是res沒有返回的話,會報Element的錯誤,形成信息誤導。

更新路由文件,使登陸成功跳轉到Home組件

// 更新路由文件:
import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/views/login'
import Home from '@/views/home'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      redirect: '/login'
    },
    {
      path: '/login',
      name: 'login',
      component: Login
    },
    {
      path: '/home',
      name: 'home',
      component: Home
    }
  ]
})
// 新建文件:client/src/views/home/index.vue
<template>
  <div>Home</div>
</template>

使用上節經過Postman建立的admin帳戶登陸,結果展現
admin登陸
緩慢的動圖以下:
login.gif

註冊邏輯

//更新文件:client/src/views/login/index.vue
...
    async onRegister () {
      try {
        const valid = await this.$refs[this.formName].validate()
        if (valid) {
          const { account, password } = this.form
          const res = await http.post(
            '/users?action=register',
            {
              account,
              password
            }
          )
          if (res.code === '200') {
            this.$refs[this.formName].resetFields()
            this.$message({
              type: 'success',
              message: '註冊成功'
            })
          } else {
            this.$message({
              type: 'error',
              message: res.msg
            })
          }
        }
      } catch (err) {
        console.error(err)
      }
    }
...

測試失敗結果
失敗
測試成功結果
成功
可使用新建立的賬號登陸,發現能夠成功/查看數據庫,是否成功新增用戶

參考文檔

element-ui
vue-router
axios

相關文章
相關標籤/搜索