Projet Vue3+Vite+Ts combat 03 Initialiser Element Plus, importation automatique d'API et de composants, utilisation du composant ElMessage, propriétés globales Vue, Axios, variables d'environnement, inter-domaines

Initialiser Element Plus

Element Plus est une version améliorée d'Element UI pour Vue 3.

Installer et configurer l'importation automatique à la demande

# 安装
npm install element-plus --save

Il est recommandé d'utiliser l'importation à la demande La recommandation officielle est d'utiliser unplugin-vue-componentset unplugin-auto-importces deux plug-ins pour mettre en œuvre l'importation automatique afin de pallier certaines lacunes de l'importation à la demande (enregistrement manuel des composants, etc.).

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

Configurez 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()]
    })
  ],
  ...
})

test:

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

mondialisation

Les composants Element Plus utilisent l'anglais par défaut, comme le composant date :

insérez la description de l'image ici

Si vous souhaitez utiliser d'autres langues (comme le chinois), vous devez configurer l'internationalisation globalement.

La méthode d'importation complète peut être configurée via les options lors de l'enregistrement locale.

L'importation à la demande doit être configurée à l'aide des composants Vue fournis officiellement :

<!-- 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>

Effet (vous devez actualiser la page pour que la configuration prenne effet) :

insérez la description de l'image ici

icône

Si vous souhaitez utiliser l'icône Element Plus directement dans le projet comme le cas officiel, vous devez enregistrer le composant globalement. Le plug-in officiel importé automatiquement est toujours en cours de développement, et l'enregistrement global manuel actuel :

// 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')

Importation automatique d'API et de composants

Les plug-ins pour l'importation et l'installation automatiques d'Element Plus ne sont pas seulement utilisés pour eux-mêmes, en fait, ces deux plug-ins peuvent être appliqués à divers frameworks et bibliothèques.

unplugin-vue-composants

Le plugin unplugin-vue-components est utilisé pour identifier automatiquement les composants utilisés dans le modèle Vue, importer et enregistrer automatiquement à la demande.

Il fournit des analyseurs pour plusieurs bibliothèques d'interface utilisateur configurables, voir la section "Importation à partir de bibliothèques d'interface utilisateur".

Un fichier sera généré dans le projet TypeScript components.d.tspour compléter et mettre à jour automatiquement le fichier de déclaration de type du composant.

**Remarque : **Le plug-in reconnaît automatiquement les composants utilisés dans le modèle de modèlecomponents.d.ts , vous pouvez vérifier pour confirmer s'il a été reconnu.

unplugin-auto-import

Le plugin unplugin-auto-import peut importer automatiquement les API communes des bibliothèques de configuration à la demande dans les environnements Vite, Webpack, Rollup et esbuild, tels que ceux de Vue, refsans travail manuel import.

Vous pouvez importsconfigurer l'API importée automatiquement (règles prédéfinies ou personnalisées) via l'élément de configuration, ou resolversconfigurer l'analyseur de la bibliothèque de composants (comme Element Plus).

Dans un projet supportant TypeScript, un fichier sera généré dans le répertoire racine du projet après l'installation du plug-in auto-imports.d.ts. Lors de l'importation automatique de la configuration, la déclaration de type correspondant à l'API de la bibliothèque de configuration sera automatiquement complétée.

Remarque : auto-imports.d.tsLe fichier sera vérifié par ESLint par défaut et une erreur sera signalée <变量> is defined but never used.. Vous pouvez ignorer la vérification du fichier par ESLint.

Configurer l'importation automatique d'API

Configurez l'importation automatique d'API pour Vue, Vue Router et Pinia :

// 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()]
    }),
    ...
  ],
  ...
})

Après l'enregistrement, auto-imports.d.tsle contenu sera automatiquement rempli et .eslintrc-auto-import.jsonla configuration de la variable globale eslint sera générée dans le répertoire racine du projet.

Ces deux fichiers doivent être ajoutés manuellement aux fichiers de configuration TypeScript et 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'
  ],
  ...
}

Ignore auto-imports.d.tsla validation ESLint.

# .eslintignore
auto-imports.d.ts

Il est recommandé de redémarrer l'éditeur pour que la configuration prenne effet.

Vous pouvez maintenant utiliser directement l'API de Vue, Vue Router et Pinia sans importtravail manuel.

Par exemple, vous pouvez annoter les importations des API suivantes :

<!-- 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'

...

Avis:

  1. Toutes les API , telles que celles de Vue Router, createRouterne seront pas importées. Pour les API spécifiques pouvant être importées automatiquement, reportez-vous à unplugin-auto-import/src/presets
  2. .eslintrc-auto-import.jsonSi vous n'avez pas besoin d'ajouter de configuration après avoir généré le fichier, il est recommandé enabled: truede définir sur false, sinon ce fichier sera généré à chaque fois.

Référence séparée aux composants ElementPlus

Le principe de l'importation automatique à la demande est d' <template>importer automatiquement en identifiant les composants utilisés dans , ce qui conduit au fait que si vous utilisez ElMessagede tels composants qui appellent directement des méthodes dans JS, le plug-in ne reconnaîtra pas et ne terminera pas l'importation automatique.

Par exemple:

  • <script>Utilisé dans les composants Vue à fichier unique
  • Utilisé dans l'intercepteur Axios

Ces composants doivent donc être actionnés manuellement :

  • Importer manuellement importles composants (l'importation complète nécessite également un manuel import)
  • Importer manuellement les fichiers de style ( element-plus/theme-chalk/xxx.css)

Par exemple, les composants couramment utilisésElMessage :

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

ElMessage.success('成功使用')

Mais il y a toujours un problème avec cela, car certains composants utilisent également d'autres composants Element, comme le ElMessageBoxbouton de confirmation dans utilise ElButtonle composant, bien que le rendu soit réussi, mais comme il n'est pas automatiquement importé via le plug-in, il n'y a pas style.

insérez la description de l'image ici

S'il est utilisé dans un composant Vue à fichier unique et utilisé dans le modèle <el-button>, il déclenchera l'importation automatique du fichier de style du composant.

Par conséquent, il est recommandé d'importer à la demande tout en continuant d'importer des fichiers de style complets pour éviter de tels problèmes de limites.

// 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('成功使用')

Propriétés globales de la vue (globalProperties)

Documents officiels :

Dans Vue 2, les variables et les méthodes accessibles Vue.prototypeglobalement ( ) pour toutes les instances de Vue peuvent être définies en même temps .this

Vue 3 utilise l'objet sur l'instance racine pour enregistrer les propriétés globales auxquelles accèdent toutes les instances de composant dans app.config.globalPropertiesl'instance ( ), au lieu de la méthode de Vue 2 consistant à modifier toutes les instances racine.app

Enregistrer le composant d'invite de message ElementPlus globalement

Si Element Plus est entièrement introduitapp.config.globalProperties , certaines méthodes globales de composants (telles que , , ElMessageetc. $message) ElMessageBoxseront ajoutées automatiquement.$msgbox$alert

Cependant, si vous utilisez la méthode d'importation à la demande , lorsque vous utilisez ce type de composant, vous devez importer manuellement le composant et le style de composant dans le module utilisé.

Afin de réduire les importations répétées dans les composants Vue, ils peuvent être enregistrés en tant que variables globales de l'instance Vue (le nom de la variable fait référence au nom de l'enregistrement d'importation complet) :

// 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
  }
}

utiliser des variables globales

Accessible via des variables globales dans l'API options this.<globalProperty>, ou directement utilisable dans les templates :

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

Utiliser des variables globales dans la configuration

L'officiel n'explique pas comment utiliser les variables globales dans setup()et .<script setup>

Parce que app.config.globalPropertiesle but de est de remplacer Vue.prototypel'utilisation de 2.x, avec la mise à jour de l'API globale, il n'y aura plus une configuration globale unique de Vue, mais une configuration distincte pour chaque instance racine .

Ceci n'est pas destiné à être utilisé dans setup, vous devez importer le contenu directement ou setupl'utiliser dans provide/inject.

Reportez-vous à Problèmes :

mode fournir/injecter

<!-- 父级组件,如 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>

Comment obtenir une instance dans la configuration (non recommandé)

D'une autre manière, Vue expose une API qui getCurrentInstance()peut accéder aux instances de composants internes, à travers lesquelles les variables globales de l'instance racine sont accessibles :

<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>

suggestion

Il existe de nombreuses façons de l'utiliser, et il est recommandé d'utiliser un moyen sûr, comme l'importation directe ou l'utilisation sous les options de l'API.

Déclaration de type TypeScript de variable globale

Ajouter un fichier de déclaration de type :

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

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

Module de demande de package basé sur Axios

npm i axios

configuration de base

// 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

Toutes les demandes d'interface sont src/apiorganisées sous le répertoire :

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

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

utiliser:

<!-- 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>

Le type d'interface qui encapsule les données de réponse

Ce qui est actuellement obtenu resest l'objet de réponse empaqueté par Axios. Les données réelles renvoyées par le backend n'ont pas de type déclaré, de sorte que l'IDE ne peut pas fournir d'invites intelligentes, de sorte que le type des données de réponse doit être déclaré manuellement.

requestLes génériques de données de réponse ne sont pas pris en charge. Par conséquent, les demandes d'envoi prenant en charge les génériques doivent être utilisées à la place request.<method>.

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

Maintenant, l'IDE peut demander automatiquement res.datales champs sous .

Mais chaque interface retournera les champs status, msget data.Afin d'éviter les déclarations répétées, ils peuvent être encapsulés dans un type d'interface (interface), et datadéfinis comme un type générique :

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

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

Encapsuler les méthodes de requête génériques

Maintenant, l'accès aux champs des données de réponse datadoit être passé res.data.data.title.

Si vous souhaitez être plus concis, par exemple res.title, vous pouvez revenir après la demande .then(res => res.data.data).

Cette action doit donc être ajoutée après chaque requête.

Habituellement, nous le traitons dans l'intercepteur axios, mais request.get()le type de retour sera toujours l'objet encapsulé par Axios (AxiosResponse).

S'ils fonctionnent correctement, les Smart Tips ne fonctionneront pas.

Vous pouvez encapsuler une méthode qui reçoit un type générique et l'appeler en interne 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)
}

Mais de cette manière, vous ne pouvez pas utiliser request.get()la méthode pour envoyer la requête :

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

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

Cette méthode ne peut pas être utilisée pour request.<method>envoyer des demandes, il y a des avantages et des inconvénients, choisissez de l'utiliser en fonction de vos habitudes personnelles.

Extraire le module de type d'interface

Le format des données de réponse de l'interface générale peut être utilisé à plusieurs endroits.Afin de réutiliser leurs types d'interface, il peut être extrait dans un module séparément.

src/apiCréez un dossier sous le répertoire pour typesstocker les modules de type liés à l'API :

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

utiliser:

// 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>

Variables et modèles d'environnement

Variables et modèles d'environnement | Documentation chinoise officielle de Vite

Généralement, l'adresse de base (baseUrl) des différents environnements sera configurée pour l'interface du projet, qui est généralement configurée dans la variable d'environnement.

Vite expose des variables d'environnement sur un import.meta.env.[variable]objet spécial. Lors de la construction, ces variables d'environnement seront identifiées comme des chaînes et remplacées de manière statique, de sorte que les valeurs de clé dynamiques ne peuvent pas être utilisées, par exemple import.meta.env[variable].

Vite prend en charge la même manière que Vue CLI, .env.[mode]en spécifiant les variables d'environnement via des fichiers.

Contrairement à Vue CLI, les variables personnalisées de ce dernier doivent commencer VUE_APP_par , tandis que Vite doit VITE_commencer par .

Configurer les variables d'environnement

Les valeurs sont remplacées sous forme de chaînes et peuvent être sans guillemets sauf si elles sont incluses #.

# .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
})

...

Remarque : La modification des variables d'environnement nécessite le redémarrage de Vite ( npm run dev) pour prendre effet.

Prise en charge des variables d'environnement TypeScript

Vite fournit uniquement des définitions de type TS pour les variables d'environnement par défaut ( MODE, BASE_URL, PROD, DEV), et les variables d'environnement définies par l'utilisateur doivent ajouter manuellement des définitions de type.

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

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

Étant donné que l'interface est définie mais non utilisée, eslint signalera une erreur et cette règle peut être désactivée pour cette ligne de code.

problèmes inter-domaines

Généralement, le projet frontal et le projet principal sont déployés séparément, et l'interface serveur a des restrictions inter-domaines. Il existe de nombreuses façons de résoudre les problèmes inter-domaines. Les solutions frontales les plus courantes sont au nombre de deux :

environnement de développement Environnement de production
Configurer CORS sur le serveur Configurer CORS sur le serveur
Configurez le proxy du serveur de développement, tel que le server.proxy de vite et les CLI de VuedevServer.proxy Configurer le proxy du serveur de production, tel que nginx

Généralement, le développement back-end est trop paresseux pour configurer CORS. La solution courante pour le front-end est de configurer le serveur proxy inverse (proxy).

Le principe est de construire un serveur de transit pour transmettre les requêtes afin d'éviter les problèmes inter-domaines. L'interface demande une adresse locale, et le serveur exécutant le code frontal la transmet au serveur cible.

Remplacez le chemin de base de la requête par un chemin local (il est convenu que /apile chemin de la requête au début est une requête d'interface qui doit être transmise) :

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

N'oubliez pas de redémarrer pour que les variables d'environnement prennent effet.

/apiProxy inverse configuré :

// 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/, '')
      }
    }
  }
})

PS : Le code serveur utilisé dans le cas actuel est configuré avec CORS par défaut, qui peut être supprimé app.use(cors())pour tester les effets inter-domaines.

Je suppose que tu aimes

Origine blog.csdn.net/u012961419/article/details/124300061
conseillé
Classement