Vue3+Vite+Ts プロジェクト戦闘 03 Element Plus の初期化、API とコンポーネントの自動インポート、ElMessage コンポーネントの使用、Vue グローバル プロパティ、Axios、環境変数、クロスドメイン

エレメントプラスの初期化

Element Plus は、Vue 3 用の Element UI のアップグレード バージョンです。

自動オンデマンドインポートをインストールして構成する

# 安装
npm install element-plus --save

オンデマンド インポートの使用が推奨されています。公式では、unplugin-vue-componentsunplugin-auto-importこれら 2 つのプラグインを使用して自動インポートを実装し、オンデマンド インポートの欠点 (コンポーネントの手動登録など) を補うことが推奨されています。

# 安装插件
npm install -D unplugin-vue-components unplugin-auto-import

Vite を設定します。

// vite.config.ts
...
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import {
    
     ElementPlusResolver } from 'unplugin-vue-components/resolvers'

// https://vitejs.dev/config/
export default defineConfig({
    
    
  plugins: [
    ...
    // ElementPlus 自动导入
    AutoImport({
    
    
      resolvers: [ElementPlusResolver()]
    }),
    Components({
    
    
      resolvers: [ElementPlusResolver()]
    })
  ],
  ...
})

テスト:

<el-button type="primary">Primary</el-button>

グローバリゼーション

Element Plus コンポーネントでは、日付コンポーネントなど、デフォルトで英語が使用されます。

ここに画像の説明を挿入

他の言語 (中国語など) を使用したい場合は、国際化をグローバルに構成する必要があります。

完全なインポート方法は、登録時のオプションを通じて設定できますlocale

オンデマンド インポートは、公式に提供されている Vue コンポーネントを使用して設定する必要があります。

<!-- src\App.vue -->
<template>
  <el-config-provider :locale="locale">
    <router-view />
  </el-config-provider>
</template>

<script setup lang="ts">
import locale from 'element-plus/lib/locale/lang/zh-cn'
</script>

効果 (設定を有効にするにはページを更新する必要があります):

ここに画像の説明を挿入

アイコン

公式の場合のようにプロジェクト内で Element Plus アイコンを直接使用したい場合は、コンポーネントをグローバルに登録する必要があります。公式の自動インポートされたプラグインはまだ開発中であり、現在の手動グローバル登録は次のとおりです。

// src\plugins\element-plus.ts
import {
    
     App } from 'vue'
import * as ElIconModules from '@element-plus/icons-vue'

export default {
    
    
  install(app: App) {
    
    
    // 批量注册 Element Plus 图标组件
    // 或者自定义 ElIconModules 列表
    for (const iconName in ElIconModules) {
    
    
      app.component(iconName, (ElIconModules as any)[iconName])
    }
  }
}

// src\main.ts
import {
    
     createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import elementPlus from './plugins/element-plus'

// 加载全局样式
import './styles/index.scss'

createApp(App)
  .use(router)
  .use(store)
  .use(elementPlus)
  .mount('#app')

APIとコンポーネントの自動インポート

Element Plus の自動インポートとインストール用のプラグインは、それ自体で使用されるだけでなく、実際、これら 2 つのプラグインはさまざまなフレームワークやライブラリに適用できます。

unplugin-vue-コンポーネント

unplugin-vue-componentsプラグインは、Vue テンプレートで使用されるコンポーネントを自動的に識別し、オンデマンドで自動的にインポートおよび登録するために使用されます。

いくつかの構成可能な UI ライブラリのパーサーを提供します。「UI ライブラリからのインポート」セクションを参照してください。

TypeScript プロジェクト内にファイルが生成され、components.d.tsコンポーネントの型宣言ファイルを自動的に補完および更新します。

**注意: **プラグインは、テンプレート templateで使用されているコンポーネントを自動的に認識します。components.d.ts認識されているかどうかを確認することができます。

アンプラグイン自動インポート

unplugin-auto-importrefプラグインは、手動作業を行わずに、Vite、Webpack、Rollup、および esbuild 環境 (Vue など) にオンデマンドで構成ライブラリの共通 A​​PI を自動的にインポートできますimport

imports構成アイテムを通じて自動的にインポートされた API (プリセットまたはカスタム ルール) を構成したり、resolversコンポーネント ライブラリ (Element Plus など) のパーサーを構成したりできます。

TypeScript をサポートしているプロジェクトでは、プラグインのインストール後にプロジェクトのルート ディレクトリにファイルが生成され、auto-imports.d.ts設定が自動インポートされる際に、設定ライブラリの API に対応する型宣言が自動的に補完されます。

注:auto-imports.d.tsファイルはデフォルトで ESLint によって検証され、エラーが報告されます<变量> is defined but never used.。ESLint によるファイルの検証は無視できます。

API 自動インポートを構成する

Vue、Vue Router、Pinia の API 自動インポートを構成します。

// vite.config.ts
...
import AutoImport from 'unplugin-auto-import/vite'
...

// https://vitejs.dev/config/
export default defineConfig({
    
    
  plugins: [
    ...
    AutoImport({
    
    
      imports: [
        // presets
        'vue',
        'vue-router',
        'pinia'
      ],
      eslintrc: {
    
    
        enabled: true,
        filepath: './.eslintrc-auto-import.json',
        globalsPropValue: true
      },
      // ElementPlus 自动导入
      resolvers: [ElementPlusResolver()]
    }),
    ...
  ],
  ...
})

保存が有効になると、auto-imports.d.tsコンテンツが自動的に入力され、.eslintrc-auto-import.jsoneslint グローバル変数構成がプロジェクトのルート ディレクトリに生成されます。

これら 2 つのファイルは、TypeScript および ESLint 構成ファイルに手動で追加する必要があります。

// tsconfig.json
{
    
    
  ...
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "auto-imports.d.ts"],
  "references": [{
    
     "path": "./tsconfig.node.json" }]
}

// .eslintrc.js
module.exports = {
    
    
  ...
  extends: [
    ...
    // unplugin-auto-import
    './.eslintrc-auto-import.json'
  ],
  ...
}

ESLint 検証を無視しますauto-imports.d.ts

# .eslintignore
auto-imports.d.ts

設定を有効にするには、エディタを再起動することをお勧めします。

Vue、Vue Router、Pinia の API を手作業なしで直接使用できるようになりましたimport

たとえば、次の API のインポートに注釈を付けることができます。

<!-- src\layout\AppHeader\Breadcrumb.vue -->
...

<script setup lang="ts">
// import { useRouter } from 'vue-router'
// import { computed } from 'vue'

const router = useRouter()

const routes = computed(() => {
      
      
  return router.currentRoute.value.matched.filter(item => item.meta.title)
})

</script>

// src\store\index.ts
// import { defineStore } from 'pinia'

const useStore = defineStore('main', {
    
    
...
})

export default useStore

// src\main.ts
// import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// import { createPinia } from 'pinia'
import elementPlus from './plugins/element-plus'

...

知らせ:

  1. Vue Router などのすべての API がcreateRouterインポートされるわけではありません。自動的にインポートできる特定の API については、unplugin-auto-import/src/presetsを参照してください。
  2. ファイルの生成.eslintrc-auto-import.json後に設定を追加する必要がない場合は、enabled: trueに設定することをお勧めしますfalse。そうしないと、このファイルが毎回生成されます。

ElementPlus コンポーネントへの個別の参照

自動オンデマンド インポートの原則は、<template>で使用されているコンポーネントを識別して自動的にインポートすることです。そのため、ElMessageJS のメソッドを直接呼び出すコンポーネントを使用すると、プラグインは自動インポートを認識せず、完了できません。

例えば:

  • Vue の単一ファイル コンポーネント<script>で使用される
  • Axiosインターセプターで使用

したがって、そのようなコンポーネントは手動で操作する必要があります。

  • コンポーネントを手動でimportインポートします (インポートを完了するには手動も必要ですimport)
  • スタイル ファイルを手動でインポートする ( element-plus/theme-chalk/xxx.css)

たとえば、一般的に使用されるElMessageコンポーネントは次のとおりです。

import {
    
     ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/el-message.css'

ElMessage.success('成功使用')

しかし、これにはまだ問題があります。一部のコンポーネントは他の Element コンポーネントも使用しているためです。レンダリングは成功しても、ElMessageBox確認ボタンがそのコンポーネントを使用しているElButtonなど、レンダリングは成功しますが、プラグインを通じて自動的にインポートされないため、スタイル。

ここに画像の説明を挿入

これが Vue 単一ファイル コンポーネントで使用され、 template で使用される場合<el-button>、コンポーネントのスタイル ファイルの自動インポートがトリガーされます。

したがって、このような境界の問題を回避するには、オンデマンドでインポートし、完全なスタイル ファイルをインポートすることをお勧めします。

// src\plugins\element-plus.ts
import {
    
     App } from 'vue'
import * as ElIconModules from '@element-plus/icons-vue'
import 'element-plus/theme-chalk/index.css'

export default {
    
    
  install(app: App) {
    
    
    // 批量注册 Element Plus 图标组件
    // 或者自定义 ElIconModules 列表
    for (const iconName in ElIconModules) {
    
    
      app.component(iconName, (ElIconModules as any)[iconName])
    }
  }
}

import {
    
     ElMessage } from 'element-plus'
// 不再需要单独引入组件样式
// import 'element-plus/theme-chalk/el-message.css'

ElMessage.success('成功使用')

Vue グローバル プロパティ (globalProperties)

公式ドキュメント:

Vue 2 では、すべての Vue インスタンスに対してグローバルにアクセスできる変数とメソッドVue.prototype( ) を一度に設定できます。this

Vue 3 は、Vue 2 のすべてのルート インスタンスを変更する方法の代わりに、ルート インスタンス上のオブジェクトを使用して、app.config.globalPropertiesインスタンス ( )app内のすべてのコンポーネント インスタンスによってアクセスされるグローバル プロパティを登録します。

ElementPlus メッセージ プロンプト コンポーネントをグローバルに登録する

Element Plus が完全に導入されると、app.config.globalPropertiesコンポーネントのいくつかのグローバル メソッド ( ElMessageなど$message)が自動的に追加ElMessageBoxされます$msgbox$alert

ただし、オンデマンド インポート方法を使用する場合、このタイプのコンポーネントを使用する場合は、使用するモジュールにコンポーネントとコンポーネント スタイルを手動でインポートする必要があります。

Vue コンポーネントでのインポートの繰り返しを減らすために、それらを Vue インスタンスのグローバル変数として登録できます (変数名は完全なインポート登録の名前を指します)。

// src\plugins\element-plus.ts
import {
    
     App } from 'vue'
import * as ElIconModules from '@element-plus/icons-vue'
import {
    
     ElMessage, ElMessageBox } from 'element-plus'
import 'element-plus/theme-chalk/index.css'

export default {
    
    
  install(app: App) {
    
    
    // 批量注册 Element Plus 图标组件
    // 或者自定义 ElIconModules 列表
    for (const iconName in ElIconModules) {
    
    
      app.component(iconName, (ElIconModules as any)[iconName])
    }

    // 将消息提示组件注册为全局方法
    app.config.globalProperties.$message = ElMessage
    app.config.globalProperties.$msgBox = ElMessageBox
  }
}

グローバル変数を使用する

オプション API のグローバル変数を介してアクセスすることもthis.<globalProperty>、テンプレートで直接使用することもできます。

<template>
  <button @click="$message.success('可以在模板中直接使用')">
    提示
  </button>
</template>
<script lang="ts">
export default defineComponent({
    
    
  mounted() {
    
    
    this.$message.success('Options API 成功使用')
  }
})
</script>

セットアップでグローバル変数を使用する

公式では、setup()や での<script setup>グローバル変数の使い方は紹介されていません。

app.config.globalPropertiesの目的は、グローバル API の更新によって 2.x の使用を置き換えることであるためVue.prototype、1 回限りの Vue グローバル設定はなくなり、ルート インスタンスごとに個別の設定が必要になります。

これは で使用することを意図したものではないためsetup、コンテンツを直接インポートするか、setupで使用する必要がありますprovide/inject

問題を参照してください:

提供/注入モード

<!-- 父级组件,如 App.vue -->
<script setup>
import {
      
       ElMessage } from 'element-plus'

provide('$message', ElMessage)
</script>

<!-- 子孙组件 -->
<script setup>
const $message = inject('$message')

onMounted(() => {
      
      
  $message.success('setup - provide/inject 成功使用')
})
</script>

セットアップでインスタンスを取得する方法 (非推奨)

別の方法では、Vue は内部コンポーネント インスタンスにアクセスできる API を公開しgetCurrentInstance()、これを通じてルート インスタンスのグローバル変数にアクセスできます。

<script setup lang="ts">
const instance = getCurrentInstance()

onMounted(() => {
      
      
  instance.proxy.$message.success('setup - getCurrentInstance() 成功使用')
  // 也可以使用 appContext
  console.log(instance.appContext.config.globalProperties.$message === instance.proxy.$message) // true
})
</script>

<script lang="ts">
export default defineComponent({
      
      
  mounted() {
      
      
    console.log(this.instance.proxy === this) // true
  }
})
</script>

提案

使い方はいろいろありますが、直接インポートしたり、オプションAPIを利用したりするなど、安全な方法を使うことをお勧めします。

グローバル変数 TypeScript の型宣言

型宣言ファイルを追加します。

// src\types\global.d.ts
import {
    
     ElMessage, ElMessageBox } from 'element-plus'

declare module 'vue' {
    
    
  // vue 全局属性
  export interface ComponentCustomProperties {
    
    
    $message: typeof ElMessage
    $msgBox: typeof ElMessageBox
  }
}

Axiosベースのパッケージリクエストモジュール

npm i axios

基本構成

// src\utils\request.ts
import axios from 'axios'
import {
    
     ElMessage } from 'element-plus'
// 在 plugins/element-plus.ts 引入了全部组件样式,这里不需额外引入

// 创建 axios 实例
const request = axios.create({
    
    
  baseURL: 'http://localhost:5000/api/admin'
})

// 请求拦截器
request.interceptors.request.use(function (config) {
    
    
  // 统一设置用户身份 token
  return config
}, function (error) {
    
    
  return Promise.reject(error)
})

// 响应拦截器
request.interceptors.response.use(function (response) {
    
    
  // 统一处理接口响应错误,如 token 过期无效、服务端异常等
  if (response.data.status && response.data.status !== 200) {
    
    
    ElMessage.error(response.data.msg || '请求失败,请稍后重试')
    return Promise.reject(response.data)
  }
  return response
}, function (error) {
    
    
  return Promise.reject(error)
})

export default request

すべてのインターフェース要求は、src/api次のディレクトリーの下に編成されます。

// src\api\common.ts
// 公共基础接口封装
import request from '@/utils/request'

export const demo = () => {
    
    
  return request({
    
    
    method: 'GET',
    url: '/demo'
  })
}

使用:

<!-- src\views\login\index.vue -->
<template>
  <div>
    登录
  </div>
</template>

<script setup lang="ts">
import {
      
       demo } from '@/api/common'
import {
      
       onMounted } from 'vue'

onMounted(() => {
      
      
  demo().then(res => {
      
      
    console.log(res.data)
    // {"msg":"ok","status":200,"data":{"title":"Hello World","date":1649412637487}}
  })
})

</script>

応答データをカプセル化するインターフェースのタイプ

現在取得されているのはres、Axios によってパッケージ化された応答オブジェクトです。バックエンドによって返される実際のデータには宣言された型がないため、IDE はスマート プロンプトを提供できないため、応答データの型を手動で宣言する必要があります。

request応答データのジェネリックはサポートされていないため、代わりにジェネリックをサポートする送信リクエストを使用する必要がありますrequest.<method>

export const demo = () => {
    
    
  return request.get<{
    
    
    status: number
    msg: string
    data: {
    
    
      title: string
      date: number
    }
  }>('/demo')
}

これで、IDE はres.dataの下のフィールドに自動的にプロンプ​​トを表示できるようになりました。

ただし、各インターフェイスはとフィールドを返しますstatus宣言の繰り返しを避けるために、これらをインターフェイス型 (インターフェイス) にカプセル化し、ジェネリック型として定義できます。msgdatadata

interface ResponseData<T = any> {
    
    
  status: number
  msg: string
  data: T
}

export const demo = () => {
    
    
  return request.get<ResponseData<{
    
    
    title: string
    date: number
  }>>('/demo')
}

汎用リクエストメソッドをカプセル化する

応答データのdataフィールドにアクセスするには、 を渡す必要がありますres.data.data.title

たとえば、より簡潔にしたい場合はres.title、リクエストの後に return することができます.then(res => res.data.data)

したがって、このアクションは各リクエストの後に追加する必要があります。

通常は axios インターセプターで処理しますが、request.get()戻り値の型は Axios によってカプセル化されたオブジェクト (AxiosResponse) になります。

正常に動作している間は、スマート ヒントは機能しません。

ジェネリック型を受け取るメソッドをカプセル化し、内部で呼び出すことができますrequest()

// src\utils\request.ts
import axios, {
    
     AxiosRequestConfig } from 'axios'

...

export default <T = any>(config: AxiosRequestConfig) => {
    
    
  return request(config).then(res => (res.data.data || res.data) as T)
}

request.get()ただし、この方法では、メソッドを使用してリクエストを送信することはできません。

// 之前定义的 interface ResponseData 就不需要了
interface DemoData {
    
    
  title: string
  date: number
}

export const demo = () => {
    
    
  return request<DemoData>({
    
    
    method: 'GET',
    url: '/demo'
  })
}

この方法はリクエストの送信には使用できませんrequest.<method>。メリットとデメリットがあるため、個人の習慣に応じて使用することを選択してください。

インターフェースタイプモジュールの抽出

一般的なインターフェイスの応答データの形式は複数の場所で使用される可能性があるため、それらのインターフェイスの種類を再利用するために、個別にモジュールに抽出することができます。

API 関連のタイプ モジュールを保存するフォルダーsrc/apiをディレクトリの下に作成します。types

// src\api\types\common.ts
export interface DemoData {
    
    
  title: string
  date: number
}

使用:

// src\api\common.ts
// 公共基础接口封装
import request from '@/utils/request'
import {
    
     DemoData } from '@/api/types/common'

export const demo = () => {
    
    
  return request<DemoData>({
    
    
    method: 'GET',
    url: '/demo'
  })
}

<!-- src\views\login\index.vue -->
<template>
  <div>
    登录
  </div>
</template>

<script setup lang="ts">
import {
      
       demo } from '@/api/common'
import {
      
       DemoData } from '@/api/types/common'
import {
      
       onMounted, ref } from 'vue'

const data = ref<DemoData>()

onMounted(() => {
      
      
  demo().then(res => {
      
      
    data.value = res
    console.log(data.value.title)
  })
})

</script>

環境変数とパターン

環境変数とパターン | Vite 公式中国語ドキュメント

通常、さまざまな環境のベース アドレス (baseUrl) がプロジェクトのインターフェイスに設定され、通常は環境変数で設定されます。

Vite は特別なimport.meta.env.[variable]オブジェクトで環境変数を公開します。ビルド時に、これらの環境変数は文字列として識別され、静的に置き換えられるため、動的なキー値は使用できませんimport.meta.env[variable]

Vite は Vue CLI と同じ方法をサポートしており、.env.[mode]ファイルを通じて環境変数を指定します。

Vue CLI とは異なり、後者のカスタム変数はVUE_APP_で始まる必要がありますが、ViteVITE_では で始まる必要があります。

環境変数を構成する

値は文字列として置換され、含まれない限り引用符で囲まなくてもかまいません#

# .env.development
# 开发模式下加载的环境变量
VITE_API_BASEURL=http://localhost:5000/api/admin

# .env.production
# 生产模式下加载的环境变量
VITE_API_BASEURL=http://localhost:5000/api/admin

// src\utils\request.ts
import axios, {
    
     AxiosRequestConfig } from 'axios'

// 创建 axios 实例
const request = axios.create({
    
    
  baseURL: import.meta.env.VITE_API_BASEURL
})

...

注: 環境変数の変更をnpm run dev有効にするには、Vite ( ) を再起動する必要があります。

環境変数 TypeScript のサポート

MODEVite はデフォルトの環境変数 ( 、BASE_URLPROD、 )の TS タイプ定義のみを提供しておりDEV、ユーザー定義の環境変数は手動でタイプ定義を追加する必要があります。

// src\env.d.ts
...

// Vite 环境变量
// eslint-disable-next-line no-unused-vars
interface ImportMetaEnv {
    
    
  readonly VITE_API_BASEURL: string
}

インターフェイスは定義されていますが使用されていないため、eslint はエラーを報告し、このコード行ではこのルールを無効にすることができます。

クロスドメインの問題

通常、フロントエンド プロジェクトとバックエンド プロジェクトは別々にデプロイされ、サーバー インターフェイスにはクロスドメインの制限があります。クロスドメインを解決するには多くの方法があります。最も主流のフロントエンド ソリューションは次の 2 つです:

開発環境 本番環境
サーバー上で CORS を構成する サーバー上で CORS を構成する
vite の server.proxyや Vue CLIなどの開発サーバー プロキシを構成します。devServer.proxy nginx などの実稼働サーバー プロキシを構成する

一般に、バックエンドの開発は CORS を構成するには時間がかかるため、フロントエンドの一般的な解決策はサーバー リバース プロキシ (プロキシ) を構成することです。

原則として、クロスドメインの問題を回避するためにリクエストを転送するトランジット サーバーを構築することです。インターフェイスはローカル アドレスをリクエストし、フロントエンド コードを実行しているサーバーはそれをターゲット サーバーに転送します。

/apiリクエストのベース パスをローカル パスに変更します (最初のリクエスト パスは、転送する必要があるインターフェイス リクエストであることが合意されています)。

# .env.development
# 开发模式下加载的环境变量
VITE_API_BASEURL=/api

環境変数を有効にするために、必ず再起動してください。

構成された/apiリバース プロキシ:

// vite.config.ts
...

export default defineConfig({
    
    
  ...
  server: {
    
    
    proxy: {
    
    
      '/api': {
    
    
        // 目标地址
        target: 'http://localhost:5000/api/admin',

        // 有的服务器会验证 origin
        // 默认接收到的是真实的 origin 即 http://localhost:3000
        // 设置 changeOrigin 为 true 后,代理服务器就会把 origin 修改为 target 的 origin(http://localhost:5000)
        // 一般建议加上此设置
        changeOrigin: true,

        // 路径重写
        // 路径即请求路径,如 /api/demo
        // 默认会这样拼接: <target.path><path> 如 http://localhost:5000/api/admin/api/demo
        // 重新后为 http://localhost:5000/api/admin/demo
        rewrite: path => path.replace(/^\/api/, '')
      }
    }
  }
})

app.use(cors())PS: 現在のケースで使用されているサーバー コードはデフォルトで CORS で構成されており、クロスドメイン効果をテストするために削除できます。

おすすめ

転載: blog.csdn.net/u012961419/article/details/124300061