Inicializar elemento mais
Element Plus é uma versão atualizada do Element UI para Vue 3.
Instalar e configurar a importação automática sob demanda
# 安装
npm install element-plus --save
Recomenda-se o uso de importação sob demanda A recomendação oficial é usar unplugin-vue-components
esses unplugin-auto-import
dois plug-ins para implementar a importação automática para compensar algumas deficiências da importação sob demanda (registro manual de componentes, etc.).
# 安装插件
npm install -D unplugin-vue-components unplugin-auto-import
Configurar 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()]
})
],
...
})
teste:
<el-button type="primary">Primary</el-button>
globalização
Os componentes do Element Plus usam o inglês por padrão, como o componente de data:
Se você quiser usar outros idiomas (como o chinês), precisará configurar a internacionalização globalmente.
O método de importação completa pode ser configurado através de opções durante o registro locale
.
A importação sob demanda precisa ser configurada usando os componentes Vue fornecidos oficialmente:
<!-- 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>
Efeito (você precisa atualizar a página para que a configuração entre em vigor):
ícone
Se você quiser usar o ícone Element Plus diretamente no projeto como o caso oficial, você precisa registrar o componente globalmente. O plug-in oficial importado automaticamente ainda está em desenvolvimento e o registro global do manual atual:
// 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 e importação automática de componentes
Os plug-ins para importação e instalação automática do Element Plus não são usados apenas para si, na verdade, esses dois plug-ins podem ser aplicados a vários frameworks e bibliotecas.
unplugin-vue-components
O plug-in unplugin-vue-components é usado para identificar automaticamente os componentes usados no modelo Vue, importar e registrar automaticamente sob demanda.
Ele fornece analisadores para várias bibliotecas de UI configuráveis, consulte a seção "Importando de bibliotecas de UI".
Um arquivo será gerado no projeto TypeScript components.d.ts
para complementar e atualizar automaticamente o arquivo de declaração de tipo do componente.
**Observação: **O plug-in reconhece automaticamente os componentes usados no modelo modelocomponents.d.ts
, você pode verificar para confirmar se foi reconhecido.
unplugin-auto-import
O plugin unplugin-auto-import pode importar automaticamente APIs comuns de bibliotecas de configuração sob demanda em ambientes Vite, Webpack, Rollup e esbuild, como o Vue, ref
sem trabalho manual import
.
Você pode imports
configurar a API importada automaticamente (regras predefinidas ou personalizadas) por meio do item de configuração ou resolvers
configurar o analisador da biblioteca de componentes (como Element Plus).
Em um projeto que suporta TypeScript, um arquivo será gerado no diretório raiz do projeto após a instalação do plug-in auto-imports.d.ts
Quando a configuração for importada automaticamente, a declaração de tipo correspondente à API da biblioteca de configuração será complementada automaticamente.
Nota:
auto-imports.d.ts
O arquivo será verificado pelo ESLint por padrão, e um erro será relatado<变量> is defined but never used.
. Você pode ignorar a verificação do arquivo pelo ESLint.
Configurar a importação automática da API
Configure a importação automática da API para Vue, Vue Router e 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()]
}),
...
],
...
})
Após o salvamento entrar em vigor, auto-imports.d.ts
o conteúdo será preenchido automaticamente e .eslintrc-auto-import.json
a configuração da variável global eslint será gerada no diretório raiz do projeto.
Esses dois arquivos precisam ser adicionados manualmente aos arquivos de configuração TypeScript e 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'
],
...
}
Ignora auto-imports.d.ts
a validação ESLint.
# .eslintignore
auto-imports.d.ts
Recomenda-se reiniciar o editor para que a configuração tenha efeito.
Agora você pode usar diretamente a API do Vue, Vue Router e Pinia sem import
trabalho manual.
Por exemplo, você pode anotar as importações das seguintes APIs:
<!-- 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'
...
Perceber:
- Nem todas as APIs , como Vue Router,
createRouter
não serão importadas. Para APIs específicas que podem ser importadas automaticamente, consulte unplugin-auto-import/src/presets.eslintrc-auto-import.json
Se você não precisar adicionar configuração após gerar o arquivo, é recomendávelenabled: true
definir comofalse
, caso contrário, esse arquivo será gerado todas as vezes.
Referência separada para componentes ElementPlus
O princípio da importação automática sob demanda é <template>
importar automaticamente identificando os componentes usados no , o que leva ao fato de que, se você usar ElMessage
esses componentes que chamam métodos diretamente no JS, o plug-in não reconhecerá e concluirá a importação automática.
Por exemplo:
<script>
Usado em componentes de arquivo único Vue- Usado no interceptador Axios
Portanto, esses componentes precisam ser operados manualmente:
- Importar componentes manualmente
import
(a importação completa também requer manualimport
) - Importar arquivos de estilo manualmente (
element-plus/theme-chalk/xxx.css
)
ElMessage
Por exemplo , componentes comumente usados :
import {
ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/el-message.css'
ElMessage.success('成功使用')
Mas ainda há um problema com isso, pois alguns componentes também utilizam outros componentes Element, como o ElMessageBox
botão de confirmação em usa ElButton
o componente, embora a renderização seja bem-sucedida, mas por não ser importado automaticamente pelo plug-in, não há estilo.
Se for usado em um componente de arquivo único Vue e usado no modelo
<el-button>
, ele acionará a importação automática do arquivo de estilo do componente.
Portanto, é recomendável importar sob demanda e ainda importar arquivos de estilo completos para evitar esses problemas de limite.
// 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('成功使用')
Propriedades globais do Vue (globalProperties)
Documentação oficial:
No Vue 2, variáveis e métodos que podem ser acessados Vue.prototype
globalmente ( ) para todas as instâncias do Vue podem ser definidos de uma só vez .this
O Vue 3 usa o objeto na instância raiz para registrar as propriedades globais acessadas por todas as instâncias do componente na app.config.globalProperties
instância ( ), em vez do método do Vue 2 de modificar todas as instâncias raiz.app
Registre o componente de prompt de mensagem ElementPlus globalmente
Se o Element Plus for totalmente introduzidoapp.config.globalProperties
, alguns métodos globais de componentes (como , , ElMessage
etc. $message
) ElMessageBox
serão adicionados automaticamente.$msgbox
$alert
No entanto, se você usar o método de importação sob demanda , ao usar esse tipo de componente, será necessário importar manualmente o componente e o estilo do componente no módulo usado.
Para reduzir importações repetidas em componentes Vue, eles podem ser registrados como variáveis globais da instância Vue (o nome da variável refere-se ao nome do registro de importação completo):
// 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
}
}
usar variáveis globais
Pode ser acessado por meio de variáveis globais na API de opções this.<globalProperty>
ou usado diretamente nos modelos:
<template>
<button @click="$message.success('可以在模板中直接使用')">
提示
</button>
</template>
<script lang="ts">
export default defineComponent({
mounted() {
this.$message.success('Options API 成功使用')
}
})
</script>
Use variáveis globais na configuração
O funcionário não apresenta como usar variáveis globais em setup()
e .<script setup>
Como app.config.globalProperties
o objetivo é substituir Vue.prototype
o uso do 2.x pela atualização da API global, não haverá mais uma configuração global única do Vue, mas uma configuração separada para cada instância raiz .
Isso não deve ser usado em setup
, você deve importar o conteúdo diretamente ou setup
usá-lo em provide/inject
.
Consulte Problemas:
modo fornecer/injetar
<!-- 父级组件,如 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>
Como obter a instância na configuração (não recomendado)
De outra forma, o Vue expõe uma API que getCurrentInstance()
pode acessar instâncias de componentes internos, por meio das quais as variáveis globais da instância raiz podem ser acessadas:
<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>
sugestão
Existem várias formas de utilizá-lo, sendo recomendável utilizar uma forma segura, como a importação direta ou o uso sob a opção API.
Declaração de tipo TypeScript de variável global
Adicionar arquivo de declaração de tipo:
// src\types\global.d.ts
import {
ElMessage, ElMessageBox } from 'element-plus'
declare module 'vue' {
// vue 全局属性
export interface ComponentCustomProperties {
$message: typeof ElMessage
$msgBox: typeof ElMessageBox
}
}
Módulo de solicitação de pacotes baseado no Axios
npm i axios
Configuração básica
// 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
Todas as solicitações de interface são src/api
organizadas no diretório:
// src\api\common.ts
// 公共基础接口封装
import request from '@/utils/request'
export const demo = () => {
return request({
method: 'GET',
url: '/demo'
})
}
usar:
<!-- 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>
O tipo de interface que encapsula os dados de resposta
O que é obtido atualmente res
é o objeto de resposta empacotado pelo Axios.Os dados reais retornados pelo back-end não possuem um tipo declarado, portanto o IDE não pode fornecer prompts inteligentes, portanto, o tipo dos dados de resposta deve ser declarado manualmente.
request
Dados de resposta genéricos não são suportados, portanto, enviar solicitações que suportem genéricos devem ser usados request.<method>
.
export const demo = () => {
return request.get<{
status: number
msg: string
data: {
title: string
date: number
}
}>('/demo')
}
Agora o IDE pode solicitar automaticamente res.data
os campos em .
Mas cada interface retornará status
, msg
e data
campos. Para evitar declarações repetidas, eles podem ser encapsulados em um tipo de interface (interface) e data
definidos como um tipo genérico:
interface ResponseData<T = any> {
status: number
msg: string
data: T
}
export const demo = () => {
return request.get<ResponseData<{
title: string
date: number
}>>('/demo')
}
Encapsular métodos de solicitação genéricos
Agora o acesso aos data
campos de dados de resposta precisa ser passado res.data.data.title
.
Se quiser ser mais conciso, por exemplo res.title
, pode retornar após a requisição .then(res => res.data.data)
.
Portanto, esta ação deve ser adicionada após cada solicitação.
Normalmente processamos no interceptor axios, mas request.get()
o tipo de retorno ainda será o objeto encapsulado pelo Axios (AxiosResponse).
Enquanto estiver funcionando corretamente, o Smart Tips não funcionará.
Você pode encapsular um método que recebe um tipo genérico e chamá-lo internamente 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)
}
Mas desta forma, não dá para usar request.get()
o método para enviar a requisição:
// 之前定义的 interface ResponseData 就不需要了
interface DemoData {
title: string
date: number
}
export const demo = () => {
return request<DemoData>({
method: 'GET',
url: '/demo'
})
}
Este método não pode ser usado para request.<method>
enviar solicitações, existem vantagens e desvantagens, opte por usar de acordo com os hábitos pessoais.
Extrair módulo de tipo de interface
O formato dos dados de resposta da interface geral pode ser usado em vários lugares, para reutilizar seus tipos de interface, eles podem ser extraídos em um módulo separadamente.
src/api
Crie uma pasta no diretório para types
armazenar módulos de tipo relacionados à API:
// src\api\types\common.ts
export interface DemoData {
title: string
date: number
}
usar:
// 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>
Variáveis e padrões de ambiente
Variáveis e padrões de ambiente | Vite Documentação oficial chinesa
Geralmente, o endereço base (baseUrl) de diferentes ambientes será configurado para a interface do projeto, que normalmente é configurada na variável de ambiente.
O Vite expõe variáveis de ambiente em um import.meta.env.[variable]
objeto especial. Ao compilar, essas variáveis de ambiente serão identificadas como strings e substituídas estaticamente, portanto, valores de chave dinâmicos não podem ser usados, por exemplo, import.meta.env[variable]
.
O Vite oferece suporte da mesma forma que o Vue CLI, .env.[mode]
especificando variáveis de ambiente por meio de arquivos.
Ao contrário do Vue CLI, as variáveis personalizadas deste último devem começar VUE_APP_
com , enquanto o Vite deve VITE_
começar com .
Configurar variáveis de ambiente
Os valores são substituídos como strings e não podem ser citados, a menos que sejam incluídos #
.
# .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
})
...
Nota: Modificar as variáveis de ambiente requer reiniciar o Vite ( npm run dev
) para entrar em vigor.
Variáveis de ambiente Suporte a TypeScript
O Vite fornece apenas definições de tipo TS para variáveis de ambiente padrão ( MODE
, BASE_URL
, PROD
, DEV
) e as variáveis de ambiente definidas pelo usuário precisam adicionar definições de tipo manualmente.
// src\env.d.ts
...
// Vite 环境变量
// eslint-disable-next-line no-unused-vars
interface ImportMetaEnv {
readonly VITE_API_BASEURL: string
}
Como a interface está definida, mas não é usada, o eslint relatará um erro e essa regra poderá ser desativada para esta linha de código.
problemas entre domínios
Normalmente, o projeto de front-end e o projeto de back-end são implantados separadamente, e a interface do servidor possui restrições entre domínios. Há muitas maneiras de resolver o problema entre domínios. As soluções de front-end mais comuns são duas:
ambiente de desenvolvimento | Ambiente de produção |
---|---|
Configurar o CORS no servidor | Configurar o CORS no servidor |
Configure o proxy do servidor de desenvolvimento, como server.proxy do vite e CLI do VuedevServer.proxy |
Configure o proxy do servidor de produção, como nginx |
Geralmente, o desenvolvimento back-end é muito preguiçoso para configurar o CORS. A solução comum para o front-end é configurar o proxy reverso do servidor (proxy).
O princípio é construir um servidor de trânsito para encaminhar solicitações para evitar problemas entre domínios.A interface solicita um endereço local e o servidor que executa o código front-end o encaminha para o servidor de destino.
Altere o caminho base da requisição para um caminho local (concorda-se que /api
o caminho da requisição no início é uma requisição de interface que precisa ser encaminhada):
# .env.development
# 开发模式下加载的环境变量
VITE_API_BASEURL=/api
Lembre-se de reiniciar para que as variáveis de ambiente entrem em vigor.
/api
Proxy reverso configurado :
// 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: O código do servidor usado no caso atual é configurado com CORS por padrão, que pode ser excluído
app.use(cors())
para testar os efeitos entre domínios.