手把手Vue3項目(二)——安裝配置 json-server 、 json-server-auth ,模擬后端服務,測試注冊和登錄功能


本文包含:

  1. json-server 的安裝 配置 驗證

  2. json-server-auth 的安裝 配置 驗證

  3. 注冊和登錄頁面

涉及知識點:axios,router,http請求,跨域,vue3,ts 等等

歡迎小伙伴,加入微信群,在文末,如果二維碼過期,可以在公眾號里獲取。

json-server

安裝配置 json-server

安裝

pnpm add json-server -D

配置

// 直接看下面驗證的時候如何使用,以及使用的時候遇到的問題

驗證

一、基本使用大家參考 json-server Github

簡單來說分了三步

  1. 創建一個 json 文件當作你要訪問的數據庫,在你安裝好json-server的時候會默認生成一個db.json,
  2. 啟動 json-server 服務器,直接運行json-server --watch db.json,終端會提示現在這個數據庫存在的資源
  3. 在瀏覽器地址輸入啟動終端中提示你擁有的資源地址,如: http://localhost:3000/posts/1,就可以訪問到一組json數據。這里的數據是真實的數據,可以在開發者工具的 network 中訪問到,不像 mock 的數據會被劫持,在瀏覽器開發者工具中看不到請求的數據。

二、項目中的簡單使用

  1. 准備一個項目放在項目中的 json 文件,作為我們項目的數據庫 database,這里我創建在./src/service/json-server/data.json,下面是我加的測試數據,名字是testdata
{
  "testdata": {
    "status": 200,
    "message": "請求成功!",
    "data": [
      {
        "id": 1,
        "title": "json-server",
        "author": "typicode"
      },
      {
        "id": 2,
        "title": "json-server",
        "author": "typicode"
      }
    ]
  }
}

  1. 在 package.json 中配置啟動 json-server 的命令,只需更改我們存放數據的 json 文件地址就可以了。
"scripts": {
    "jsondb": "json-server --watch ./src/service/json-server/data.json"
}
  1. 理解項目 API 的訪問機制
  • 我們啟動 json-server,npm jsondb,我這里項目一直使用的pnpm作為包管理器,所以使用pnpm jsondb來啟動,

  • Home可以理解為后端服務器的地址,當我們直接在輸入http://localhost:3000/users,

  • 現在我們ctrl+c停止,json-server 的服務,讓后啟動我的使用vite搭建的 Vue 項目,發現默認地址,也是 http://localhost:3000,現在我的頁面是在訪問http://localhost:3000時,重定向到/home頁面。

    我們在訪問瀏覽器地址的時候一方面,我要通過路由轉跳到當前頁面,還需要當前頁面能夠獲取到數據,但是同時啟動 vue 項目和 json-server 兩個地址就沖突,后啟動的地址會被默認更改到http://localhost:3001,但是我們要通過訪問http://localhost:3000/users 來獲取到用戶信息,這個時候就和我們實際工作中項目的開發非常類似了。

    我們一般把前端項目部署到nginx,訪問前端頁面,獲取數據又是從另一個服務器來獲取,這個時候兩個域名不一樣,但是我們要拿到我們想要的數據,就需要規定好接口的地址、參數等一些信息,通過本地跨域,或者nginx轉發來訪問服務器。

image-20211101100224812

啟動 json-server 圖

image-20211101101215982

瀏覽器中訪問數據庫圖

image-20211101101555260

啟動項目圖

  1. 前端跨域代理的配置,在 vite.config.ts
    • 這里我們更改項目等啟動端口到3030
    • 現在我們前端項目路徑為 http://localhost:3030,需要代理所有以 /api 開頭的 API 請求,把它轉發到 http://localhost:3000,並且后端的 API 路徑中不帶 /api前綴,需要自動去掉 /api前綴
server: {
    // host: 'localhost',
    port: 3030,
    proxy: {
      //這里是通過請求/api 來轉發到 https://api.pingping6.com/
      //假如你要請求https://api.*.com/a/b
      //那么axios的url,可以配置為 /api/a/b
      '^/api': {
        target: 'http://localhost:3000/',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
        // configure: (proxy, options) => {
        //   // proxy 是 'http-proxy' 的實例
        // }
      }
    }
  },
  1. 下面我們配置一下 API ,axios 的配置,可以到 Gitee 代碼里看一下 /service/index.ts 文件,里面有注釋,寫的也通俗易懂。
/**
 * * 在具體模塊中導入具體的 config 類型,配置通用的 config 類型,方便復用
 */
import http from '@/service'

enum Api {
  testData = '/api/testdata',
  testPost = '/api/postTestList',
  testPatch = '/api/patchTestList',
  testPut = '/api/putTestList',
  testDelete = '/api/deleteTestList'
}

export const testData = (params?: any) => {
  return http.get<any>(Api.testData, params)
}
export const testPost = (data: any) => {
  return http.post<any>(Api.testPost, data)
}

  1. 下面寫個頁面,測試一下,src/modules/components/test/json-server.vue
<template>
  <h1>通過測試頁面通過json-server,獲取數據</h1>
</template>

<script lang="ts">
import { defineComponent, onMounted } from 'vue'
import { testData } from '@/api/test/index'

export default defineComponent({
  name: 'json-server',
  components: {},
  setup() {
    const testJsonServer = () => {
      testData().then((res) => {
        console.log('testData', res.data.data)
      })
    }
    onMounted(() => {
      console.log('mounted')
      testJsonServer()
    })
    return {
      testJsonServer
    }
  }
})
</script>

<style lang="less" scoped></style>

  1. 打開頁面可以訪問到數據

image-20211101144501545

image-20211101144549668

安裝配置 json-server-auth

安裝

pnpm add json-server-auth -D

配置

// 直接進入驗證

驗證

1. 注冊

  • POST /register
  • POST /signup
  • POST /users

emailpassword 必填,且在請求體中,除了必填之外,自己也可以根據需要添加其他的數據username,age等等

POST /register
{
  "email": "olivier@mail.com",
  "password": "bestPassw0rd"
}

返回結果

// 201 Created
{
  "accessToken": "xxx.xxx.xxx",
  "user": {
    "id": 1,
    "email": "olivier@mail.com"
  }
}

2. 登錄

  • POST /login // 我用login的時候Apifox可以請求到,在項目中就login就不行,換成signin就可以請求通,很奇怪
  • POST /signin
POST /login
{
  "email": "olivier@mail.com",
  "password": "bestPassw0rd"
}

返回結果

200 OK
{
  "accessToken": "xxx.xxx.xxx",
  "user": {
    "id": 1,
    "email": "olivier@mail.com",
    "firstname": "Olivier",
    "lastname": "Monge"
  }
}

3. 使用 postman 或者 Apifox,配置之后,測試一下,register添加兩組數據,再使用這兩組數據登錄,可以之后就在項目中繼續

4. 具體代碼中實踐,順便鞏固一下 Vue3、 TS 和 Ant Design Vue 3.0

下面是簡單寫的注冊和登錄頁面,切換注冊的時候,還有一點問題,后面我再看一下,大家也可以看一下代碼,可以一起交流,

目前登錄功能是可以測試的,接口也是通的

下面的代碼沒有樣式,樣式有很多行,影響閱讀,大家可以 clone Gitee 代碼下來看。

<template>
  <div class="login">
    <div class="content">
      <a-tabs animated :tabBarGutter="-1" type="card" v-model:activeKey="activeKey">
        <a-tab-pane key="login" tab="賬號密碼登錄">
          <div class="login-form">
            <a-form
              ref="formRef"
              :model="formState"
              :rules="rules"
              layout="vertical"
              labelAlign="right"
            >
              <a-form-item label="" name="email">
                <a-input
                  size="large"
                  v-model:value="formState.email"
                  placeholder="請輸入郵箱"
                  allowClear
                />
              </a-form-item>
              <a-form-item label="" name="password">
                <a-input
                  size="large"
                  v-model:value="formState.password"
                  type="password"
                  placeholder="請輸入密碼"
                  allowClear
                />
              </a-form-item>
            </a-form>
            <div class="login-button">
              <a-button v-if="switchBtn" size="large" type="primary" @click="login">登錄</a-button>
              <a-button v-else size="large" type="primary" @click="register">注冊</a-button>
            </div>
            <div class="login-footer">
              <a-button type="link" @click="handleChange">{{ buttonTitle }}</a-button>
            </div>
          </div>
        </a-tab-pane>
        <a-tab-pane key="register" tab="掃碼登錄">
          <div class="login-form">
            <div class="login-qrcode">
              <div class="qrcode-image"></div>
            </div>
            <div class="login-footer">
              <div class="primary-color">二維碼失效時間 5 秒</div>
            </div>
          </div>
        </a-tab-pane>
      </a-tabs>
    </div>
    <!--      <div class="login-button">-->
    <!--        <a-button type="primary" @click="register">注冊</a-button>-->
    <!--        <a-button type="primary" @click="login">登錄</a-button>-->
    <!--      </div>-->
    <!--      <div>-->
    <!--        <a>忘記密碼?</a>-->
    <!--      </div>-->
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, UnwrapRef, ref, toRaw } from 'vue'
import { toLogin, toRegister } from '@/api/login/index'
import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface'
import { message } from 'ant-design-vue'

interface FormState {
  email: string
  password: string
}

export default defineComponent({
  name: 'login',
  components: {},
  setup() {
    // tab 欄默認選擇 login
    const activeKey = ref('login')
    // 登錄與注冊切換
    let switchBtn = ref(true)
    let buttonTitle = ref<string>('新用戶注冊')
    const handleChange = () => {
      switchBtn = ref(!switchBtn.value)
      buttonTitle = ref(switchBtn.value ? '新用戶注冊' : '已有賬號登錄')
      console.log('change', switchBtn.value)
      console.log('text', buttonTitle)
    }
    // form 表單部分
    const formRef = ref()
    // UnwrapRef 單層解包, https://juejin.cn/post/6844904126283776014
    const formState: UnwrapRef<FormState> = reactive({
      email: '',
      password: ''
    })
    const rules = {
      email: [{ required: true, message: '請輸入正確的郵箱格式', trigger: 'blur' }],
      password: [
        { required: true, message: '請輸入密碼!', trigger: 'blur' },
        {
          min: 8,
          max: 16,
          message: '密碼長度需8-16位密碼!',
          trigger: 'blur'
        }
      ]
    }
    const validFlag = ref(false)
    const register = () => {
      valid()
      if (validFlag) {
        toRegister(formState)
          .then((res) => {
            console.log(res)
            validFlag.value = false
          })
          .catch((err) => {
            console.log(err)
            validFlag.value = false
          })
      }
      return
    }
    const login = () => {
      console.log('登錄')
      valid()
      if (validFlag) {
        toLogin(formState)
          .then((res) => {
            console.log(res)
            validFlag.value = false
          })
          .catch((err) => {
            console.log(err)
            validFlag.value = false
            // message.warn('請輸入用戶名或密碼!')
          })
      }
      return
    }
    const valid = () => {
      formRef.value
        .validate()
        .then(() => {
          console.log('values', formState, toRaw(formState))
          validFlag.value = true
          console.log('validFlag', validFlag)
        })
        .catch((error: ValidateErrorEntity<FormState>) => {
          validFlag.value = false
          console.log('error', error)
          message.warn('請輸入用戶名或密碼!')
        })
    }
    const resetForm = () => {
      formRef.value.resetFields()
    }
    return {
      activeKey,
      switchBtn,
      buttonTitle,
      handleChange,
      formRef,
      formState,
      rules,
      validFlag,
      login,
      register,
      valid,
      resetForm
    }
  }
})
</script>

Find me

Gitee:https://gitee.com/heyhaiyon/vite-vue-ts-antd.git

微信公眾號:heyhaiyang

掘金:heyhaiyang

博客園:heyhaiyang

頭條號:heyhaiyang

微信群:歡迎小伙伴加入

IMG_0544


免責聲明!

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



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