Recientemente, inicié Vue3 y completé 3 proyectos. Encontré muchos problemas. Hoy, me tomaré un tiempo para resolverlo y compartiré 15 problemas más comunes con usted. Básicamente, se publican las direcciones de los documentos correspondientes. Lea más documentos ~
Completado Los tres proyectos están desarrollados básicamente en Vue3 (modo setup-script), por lo que se resumen principalmente en varios aspectos:
-
vue3 -
Vite -
VueRouter -
Pinia -
Elemento Plus
1. Vue3
1. Cambios en los métodos de ciclo de vida de Vue2.x y Vue3.x
Dirección del documento: https://v3.cn.vuejs.org/guide/composition-api-lifecycle-hooks.html
Los métodos del ciclo de vida de Vue2.x y Vue3.x han cambiado mucho. Echemos un vistazo primero:
2.x Ciclo de vida | 3.x Ciclo de vida | Descripción del tiempo de ejecución |
---|---|---|
antes de crear | configuración | Ejecutar antes de la creación del componente |
creado | configuración | Ejecutar después de crear el componente |
antes del monte | onBeforeMount | Ejecutado antes de que el componente se monte en el nodo |
montado | en Montado | Ejecutar después de montar el componente |
antes de Actualizar | onBeforeUpdate | Ejecutar antes de la actualización del componente |
actualizado | onActualizado | Ejecutado después de que se completa la actualización del componente |
antes de destruir | onBeforeUnmount | Ejecutar antes de que se desinstale el componente |
destruido | en Desmontado | Ejecutar después de que se complete la desinstalación del componente |
error capturado | onErrorCaptured | Activa la función de enlace al capturar una excepción de un componente descendiente |
En la actualidad, Vue3.x todavía es compatible con el ciclo de vida de Vue2.x, pero no se recomienda mezclar y combinar. Puede usar el ciclo de vida de 2.x en la etapa inicial e intentar usar el ciclo de vida de 3 .x más tarde.
Como uso el script-srtup
modo , uso las funciones del ciclo de vida de Vue3.x directamente:
// A.vue
<script setup lang="ts">
import { ref, onMounted } from "vue";
let count = ref<number>(0);
onMounted(() => {
count.value = 1;
})
</script>
Para conocer el tiempo de ejecución de cada enlace, también puede consultar la documentación: https://v3.cn.vuejs.org/guide/instance.html#Lifecycle Diagram
2. En el modo de configuración de secuencias de comandos, el componente principal obtiene los datos del componente secundario
Dirección del documento: https://v3.cn.vuejs.org/api/sfc-script-setup.html#defineexpose
Aquí presentamos principalmente cómo el componente principal obtiene las variables definidas dentro del componente secundario. Para la comunicación entre los componentes principal y secundario, puede consultar la documentación para obtener más detalles: https://v3.cn.vuejs.org/guide/ componentes-básicos.html
Podemos usar la macro de la macro del compilador globaldefineExpose
para exponer los parámetros en el componente secundario al componente principal y usar el {key: vlaue}
método instancia del componente secundario a través del método ref de la plantilla y luego el valor correspondiente Puede ser obtenido:
// 子组件
<script setup>
let name = ref("pingan8787")
defineExpose({ name }); // 显式暴露的数据,父组件才可以获取
</script>
// 父组件
<Chlid ref="child"></Chlid>
<script setup>
let child = ref(null)
child.value.name //获取子组件中 name 的值为 pingan8787
</script>
Nota :
-
Las macros del compilador global solo se pueden usar en el modo de configuración de secuencias de comandos; -
En el modo de configuración de secuencias de comandos, las macros import
se de usarlas; -
El modo de configuración de secuencias de comandos proporciona un total de 4 macros, que incluyen: defineProps, defineEmits, defineExpose, withDefaults.
3. Proporcione valores predeterminados para accesorios
documentación dedefinedProps: https://v3.cn.vuejs.org/api/sfc-script-setup.html#defineprops-%E5%92%8C-defineemitswithDefaults documentación: https://v3.cn.vuejs.org/api /sfc-script-setup.html#%E4%BB%85%E9%99%90-typescript-%E7%9A%84%E5%8A%9F%E8%83%BD
Las cuatro macros globales del compilador proporcionadas por el modo de configuración de secuencias de comandos se han presentado anteriormente , pero no se han presentado en detalle.Esta sección presenta defineProps
y withDefaults
. El uso de defineProps
macros se puede utilizar para definir los parámetros de entrada de los componentes, de la siguiente manera:
<script setup lang="ts">
let props = defineProps<{
schema: AttrsValueObject;
modelValue: any;
}>();
</script>
La desventaja de esta declaración es que solo define los tipos props
de schema
y modelValue
dos propiedades en la propiedad defineProps
No proporciona una forma de establecer el valor predeterminado de props.
De hecho, podemos lograr esto a través de la macro withDefaults:
<script setup lang="ts">
let props = withDefaults(
defineProps<{
schema: AttrsValueObject;
modelValue: any;
}>(),
{
schema: [],
modelValue: ''
}
);
</script>
La función de ayuda withDefaults proporciona verificación de tipos para valores predeterminados y garantiza que el tipo de los accesorios devueltos elimine las marcas opcionales para las propiedades que han declarado valores predeterminados.
4. Configurar parámetros personalizados globales
Dirección del documento: https://v3.cn.vuejs.org/guide/migration/global-api.html#vue-prototype-%E6%9B%BF%E6%8D%A2%E4%B8%BA-config- propiedades globales
En Vue2.x podemos Vue.prototype
agregar propiedad de propiedad global. Pero en Vue3.x necesitas Vue.prototype
reemplazar con config.globalProperties
config:
// Vue2.x
Vue.prototype.$api = axios;
Vue.prototype.$eventBus = eventBus;
// Vue3.x
const app = createApp({})
app.config.globalProperties.$api = axios;
app.config.globalProperties.$eventBus = eventBus;
Al usarlo, primero debe obtener el objeto de instancia a través del getCurrentInstance
método :
// A.vue
<script setup lang="ts">
import { ref, onMounted, getCurrentInstance } from "vue";
onMounted(() => {
const instance = <any>getCurrentInstance();
const { $api, $eventBus } = instance.appContext.config.globalProperties;
// do something
})
</script>
La salida de instance
contenido es la siguiente:
5. Cambios en el modelo v
Dirección del documento: https://v3.cn.vuejs.org/guide/migration/v-model.html
Cuando estamos usando v-model
directivas , de hecho v-bind
y taquigrafía v-on
combinada , existen diferencias entre Vue2.x y Vue3.x.
-
Vue2.x
<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
En el componente secundario, si desea realizar un enlace de datos bidireccional en una propiedad, this.$emit('update:myPropName', newValue)
puede actualizar el v-model
valor enlazado pasando .
-
Vue3.x
<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent :modelValue="pageTitle" @update:modelValue="pageTitle = $event"/>
script-setup
En modo, no puede usar this.$emit
para enviar eventos de actualización, después de todo, no existe this
tal cosa. En este momento, necesita usar las dos macros de defineProps y defineEmits presentadas anteriormente para lograr:
// 子组件 child.vue
// 文档:https://v3.cn.vuejs.org/api/sfc-script-setup.html#defineprops-%E5%92%8C-defineemits
<script setup lang="ts">
import { ref, onMounted, watch } from "vue";
const emit = defineEmits(['update:modelValue']); // 定义需要派发的事件名称
let curValue = ref('');
let props = withDefaults(defineProps<{
modelValue: string;
}>(), {
modelValue: '',
})
onMounted(() => {
// 先将 v-model 传入的 modelValue 保存
curValue.value = props.modelValue;
})
watch(curValue, (newVal, oldVal) => {
// 当 curValue 变化,则通过 emit 派发更新
emit('update:modelValue', newVal)
})
</script>
<template>
<div></div>
</template>
<style lang="scss" scoped></style>
Cuando se usa el componente principal, es muy simple:
// 父组件 father.vue
<script setup lang="ts">
import { ref, onMounted, watch } from "vue";
let curValue = ref('');
watch(curValue, (newVal, oldVal) => {
console.log('[curValue 发生变化]', newVal)
})
</script>
<template>
<Child v-model='curValue'></Child>
</template>
<style lang="scss" scoped></style>
6. Los errores del entorno de desarrollo no son fáciles de solucionar
Dirección del documento: https://v3.cn.vuejs.org/api/application-config.html#errorhandler
Vue3.x genera avisos de aviso más amigables para algunas excepciones en el proceso de desarrollo, como el siguiente aviso:
De esta forma, la fuente de la anormalidad puede ser informada con mayor claridad, y puede verse que el problema probablemente esté <ElInput 0=......
aquí , pero no es lo suficientemente claro. En este momento, puede agregar el controlador de excepciones global proporcionado por Vue3.x para mostrar el contenido del error y la información de la pila de llamadas con mayor claridad. El código es el siguiente :
// main.ts
app.config.errorHandler = (err, vm, info) => {
console.log('[全局异常]', err, vm, info)
}
En este punto, puede ver la salida de la siguiente manera:
Se hizo más claro de inmediato. Por supuesto, este elemento de configuración también se puede utilizar para integrar los servicios de seguimiento de errores Sentry y Bugsnag. Lectura recomendada: ¿Cómo implementa Vue3 el manejo global de excepciones?
7. Observar los datos de ref no es intuitivo e inconveniente
Cuando mostramos la variable ref
declarada .
const count = ref<numer>(0);
console.log('[测试 ref]', count)
Verá que la consola emite un RefImpl
objeto :
Parece muy poco intuitivo. Todos sabemos que para obtener y modificar el valor de la variable ref
declarada , debe .value
obtenerla, por lo que también puede:
console.log('[测试 ref]', count.value);
Aquí hay otra forma, que es activar la opción " Habilitar formateadores personalizados " en el panel de configuración de la consola.


En este momento, encontrará que ref
el ha cambiado:
Más claro e intuitivo.
Encontré este método en "Diseño e implementación de Vue.js", pero no encontré ninguna introducción relevante en el documento. Si un amigo lo encuentra, hágamelo saber ~
2. Invitar
1. El uso de la importación dinámica de Vite
Dirección del documento: https://cn.vitejs.dev/guide/features.html#glob-import
Los estudiantes que usan webpack deben saber que los archivos se pueden importar require.context
dinámicamente :
// https://webpack.js.org/guides/dependency-management/
require.context('./test', false, /\.test\.js$/);
En Vite, podemos importar archivos dinámicamente usando estos dos métodos:
-
import.meta.glob
El archivo que coincide con este método se carga de forma diferida de forma predeterminada , lo que se implementa a través de la importación dinámica . El fragmento independiente se separará durante la construcción , que es una importación asíncrona , y el retorno es Promesa. Necesita hacer una operación asíncrona. El uso es como sigue:
const Components = import.meta.glob('../components/**/*.vue');
// 转译后:
const Components = {
'./components/a.vue': () => import('./components/a.vue'),
'./components/b.vue': () => import('./components/b.vue')
}
-
import.meta.globEager
Este método es para importar directamente todos los módulos , y se importa sincrónicamente . El resultado devuelto se puede operar directamente a través del for...in
ciclo . El método de uso es el siguiente:
const Components = import.meta.globEager('../components/**/*.vue');
// 转译后:
import * as __glob__0_0 from './components/a.vue'
import * as __glob__0_1 from './components/b.vue'
const modules = {
'./components/a.vue': __glob__0_0,
'./components/b.vue': __glob__0_1
}
Si solo importa componentes de Vue3 de forma asíncrona, también puede usar la API de Vue3 defineAsyncComponent para cargarlos directamente:
// https://v3.cn.vuejs.org/api/global-api.html#defineasynccomponent
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
app.component('async-component', AsyncComp)
2. Visite configurar alias tipo alias
Dirección del documento: https://cn.vitejs.dev/config/#resolve-alias
Cuando el proyecto es más complejo, a menudo es necesario configurar alias de ruta de alias para simplificar algo de código:
import Home from '@/views/Home.vue'
También es muy sencillo de configurar en Vite, solo configúralo vite.config.ts
en resolve.alias
:
// vite.config.ts
export default defineConfig({
base: './',
resolve: {
alias: {
"@": path.join(__dirname, "./src")
},
}
// 省略其他配置
})
Si está utilizando TypeScript, el editor le mostrará una advertencia de que la ruta no existe⚠️, tsconfig.json
puede agregar compilerOptions.paths
la configuración en:
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}
3. Visite configurar global scss
Dirección del documento: https://cn.vitejs.dev/config/#css-preprocessoroptions
Cuando necesitamos usar variables de tema configuradas con scss (p. ej $primary
.), métodos de mezcla (p. ej @mixin lines
.), etc., como:
<script setup lang="ts">
</script>
<template>
<div class="container"></div>
</template>
<style scoped lang="scss">
.container{
color: $primary;
@include lines;
}
</style>
Podemos configurar el archivo de configuración del tema scss en vite.config.ts
el css.preprocessorOptions.scss.additionalData
:
// vite.config.ts
export default defineConfig({
base: './',
css: {
preprocessorOptions: {
// 添加公共样式
scss: {
additionalData: '@import "./src/style/style.scss";'
}
}
},
plugins: [vue()]
// 省略其他配置
})
Si no desea utilizar el archivo de configuración scss, también puede escribir el código scss directamente:
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: '$primary: #993300'
}
}
}
})
3. VueRouter
1. Obtener parámetros de enrutamiento en el modo de configuración de secuencias de comandos
Dirección del documento: https://router.vuejs.org/zh/guide/advanced/composition-api.html
Dado que en el script-setup
modo , no se this
puede usar, no puede usar directamente this.$router
o this.$route
para obtener parámetros de enrutamiento y rutas de salto. Cuando necesitamos obtener parámetros de enrutamiento, podemos usar vue-router
el useRoute
método provisto para obtenerlo, de la siguiente manera:
// A.vue
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import router from "@/router";
import { useRoute } from 'vue-router'
let detailId = ref<string>('');
onMounted(() => {
const route = useRoute();
detailId.value = route.params.id as string; // 获取参数
})
</script>
Si desea realizar saltos de enrutamiento, puede usar el valor de retorno del useRouter
método para saltar:
const router = useRouter();
router.push({
name: 'search',
query: {/**/},
})
4. Pinia
1. Las variables destruidas por la tienda no se actualizan después de la modificación
文档地址:https://pinia.vuejs.org/core-concepts/#using-the-store
当我们解构出 store 的变量后,再修改 store 上该变量的值,视图没有更新:
// A.vue
<script setup lang="ts">
import componentStore from "@/store/component";
const componentStoreObj = componentStore();
let { name } = componentStoreObj;
const changeName = () => {
componentStoreObj.name = 'hello pingan8787';
}
</script>
<template>
<span @click="changeName">{{name}}</span>
</template>
这时候点击按钮触发 changeName
事件后,视图上的 name
并没有变化。这是因为 store 是个 reactive 对象,当进行解构后,会破坏它的响应性。所以我们不能直接进行解构。这种情况就可以使用 Pinia 提供 storeToRefs
工具方法,使用起来也很简单,只需要将需要解构的对象通过 storeToRefs
方法包裹,其他逻辑不变:
// A.vue
<script setup lang="ts">
import componentStore from "@/store/component";
import { storeToRefs } from 'pinia';
const componentStoreObj = componentStore();
let { name } = storeToRefs(componentStoreObj); // 使用 storeToRefs 包裹
const changeName = () => {
componentStoreObj.name = 'hello pingan8787';
}
</script>
<template>
<span @click="changeName">{{name}}</span>
</template>
这样再修改其值,变更马上更新视图了。
2. Pinia 修改数据状态的方式
按照官网给的方案,目前有三种方式修改:
-
通过 store.属性名
赋值修改单笔数据的状态;
这个方法就是前面一节使用的:
const changeName = () => {
componentStoreObj.name = 'hello pingan8787';
}
-
通过 $patch
方法修改多笔数据的状态;
文档地址:https://pinia.vuejs.org/api/interfaces/pinia._StoreWithState.html#patch
当我们需要同时修改多笔数据的状态时,如果还是按照上面方法,可能要这么写:
const changeName = () => {
componentStoreObj.name = 'hello pingan8787'
componentStoreObj.age = '18'
componentStoreObj.addr = 'xiamen'
}
上面这么写也没什么问题,但是 Pinia 官网已经说明,使用 $patch
的效率会更高,性能更好,所以在修改多笔数据时,更推荐使用 $patch
,使用方式也很简单:
const changeName = () => {
// 参数类型1:对象
componentStoreObj.$patch({
name: 'hello pingan8787',
age: '18',
addr: 'xiamen',
})
// 参数类型2:方法,该方法接收 store 中的 state 作为参数
componentStoreObj.$patch(state => {
state.name = 'hello pingan8787';
state.age = '18';
state.addr = 'xiamen';
})
}
-
通过 action
方法修改多笔数据的状态;
也可以在 store 中定义 actions 的一个方法来更新:
// store.ts
import { defineStore } from 'pinia';
export default defineStore({
id: 'testStore',
state: () => {
return {
name: 'pingan8787',
age: '10',
addr: 'fujian'
}
},
actions: {
updateState(){
this.name = 'hello pingan8787';
this.age = '18';
this.addr = 'xiamen';
}
}
})
使用时:
const changeName = () => {
componentStoreObj.updateState();
}
这三种方式都能更新 Pinia 中 store 的数据状态。
五、Element Plus
1. element-plus 打包时 @charset 警告
项目新安装的 element-plus 在开发阶段都是正常,没有提示任何警告,但是在打包过程中,控制台输出下面警告内容:
Consulte los problemas oficiales durante mucho tiempo: https://github.com/element-plus/element-plus/issues/3219.
vite.config.ts
Intentando configurar charset: false
en , el resultado tampoco es válido:
// vite.config.ts
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
charset: false // 无效
}
}
}
})
Finalmente encontré la solución en los temas oficiales:
// vite.config.ts
// https://blog.csdn.net/u010059669/article/details/121808645
css: {
postcss: {
plugins: [
// 移除打包element时的@charset警告
{
postcssPlugin: 'internal:charset-removal',
AtRule: {
charset: (atRule) => {
if (atRule.name === 'charset') {
atRule.remove();
}
}
}
}
],
},
}
2. Configuración del paquete de idioma chino
Dirección del documento: https://element-plus.gitee.io/zh-CN/guide/i18n.html#%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE
Por defecto, los componentes de elemnt-plus están en inglés:
Podemos cambiar a chino introduciendo el paquete de idioma chino y agregándolo a la configuración de ElementPlus:
// main.ts
// ... 省略其他
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import locale from 'element-plus/lib/locale/lang/zh-cn'; // element-plus 中文语言包
app.use(ElementPlus, { locale }); // 配置中文语言包
En este momento, puede ver que el texto de los componentes en ElementPlus pasa a ser chino.
Resumir
Lo anterior es mi resumen de la experiencia de evitar boxes después de 3 proyectos desde la entrada hasta el cubo de la familia Vue 3 de combate real De hecho, muchos de ellos se presentan en el documento, pero no estoy familiarizado con él al principio. También espero que lea más documentos ~
El modo de configuración del script Vue3 es, de hecho, cada vez más fragante.