[TOC]
vue3中常用语法
1. 子组件调用父组件方法
1.1 子组件使用$emit
父组件:
<template>
<ChildComponent @call-parent-method="parentMethod" />
</template>
<script setup>
import { defineComponent } from 'vue';
import ChildComponent from './ChildComponent.vue';
const parentMethod = () => {
console.log('This is a parent method');
};
</script>
子组件:
<template>
<button @click="$emit('call-parent-method')">Call Parent Method</button>
</template>
<script setup>
import { defineComponent, defineEmits } from 'vue';
const emit = defineEmits(['call-parent-method']);
const handleOk = () => {
emit('call-parent-method'); // 在JS里面调用
}
</script>
2. 语法相关
2.1 const 和 let 声明 ref(false) 区别
使用 const
和 let
声明 ref(false)
的区别主要体现在变量的重新赋值能力上,而不是 ref
的响应性。ref
的响应性是由 Vue 内部管理的,与变量的声明方式无关。
const 声明
变量不可重新赋值:使用
const
声明的变量不能被重新赋值。ref
的值可以修改:虽然变量本身不能被重新赋值,但ref
的.value
属性可以被修改。let 声明
变量可重新赋值:使用
let
声明的变量可以被重新赋值。ref
的值可以修改:ref
的.value
属性同样可以被修改。最佳实践:
- 如果不需要重新赋值,推荐使用
const
,因为它更符合函数式编程的不可变性原则,代码更安全、更易读。 - 如果需要重新赋值(例如动态切换
ref
对象),则使用let
。
- 如果不需要重新赋值,推荐使用
import { ref } from 'vue';
const isVisible = ref(false);
isVisible.value = true; // 合法,ref 的值可以被修改
isVisible = ref(true); // 非法,const 声明的变量不能被重新赋值
let isVisible = ref(false);
isVisible.value = true; // 合法,ref 的值可以被修改
isVisible = ref(true); // 合法,let 声明的变量可以被重新赋值
2.2 const 和 let 声明 reactive 区别
使用 const
和 let
声明 reactive
对象时,主要区别在于变量的重新赋值能力,而不是 reactive
对象本身的响应性。
- const 声明
- 不可重新赋值:使用
const
声明的变量不能被重新赋值。 - 对象可变:虽然变量本身不能被重新赋值,但对象的属性可以被修改。
- 不可重新赋值:使用
- let 声明
- 可重新赋值:使用
let
声明的变量可以被重新赋值。 - 对象可变:对象的属性同样可以被修改。
- 可重新赋值:使用
- 最佳实践:在大多数情况下,推荐使用 const 声明 reactive 对象,除非你有明确的理由需要重新赋值。
import { reactive } from 'vue';
const state = reactive({ count: 0 });
state.count = 1; // 合法,对象的属性可以被修改
state = reactive({ count: 2 }); // 非法,const 声明的变量不能被重新赋值
let state = reactive({ count: 0 });
state.count = 1; // 合法,对象的属性可以被修改
state = reactive({ count: 2 }); // 合法,let 声明的变量可以被重新赋值
3. vue3核心语法相关
3.1 dom元素动态绑定 ref 到响应式对象
在 Vue 3 中,动态绑定 DOM 元素的 ref
可以通过以下两种常见方式实现,尤其是在需要根据动态变量(比如循环中的索引或数据标识)管理引用时:
ref
(推荐)
3.1.1 方法 1:使用函数形式的 在模板中通过函数动态绑定 ref
,并将 DOM 元素保存到响应式对象中。
<template>
<div
v-for="item in items"
:key="item.id"
:ref="(el) => setDynamicRef(el, item.id)"
> {{ item.text }} </div>
</template>
<script setup>
import { ref, reactive } from 'vue';
// 响应式对象保存动态 ref
const dynamicRefs = reactive({});
// 将 DOM 元素绑定到 dynamicRefs
const setDynamicRef = (el, id) => {
dynamicRefs[id] = el; // 自动处理 el 为 null 时的卸载逻辑
};
// 示例数据
const items = ref([
{ id: 'a', text: 'Item 1', dom: null },
{ id: 'b', text: 'Item 2', dom: null },
]);
</script>
特点:
- 动态性:通过
item.id
等唯一标识管理引用,避免冲突。 - 自动清理:当元素卸载时,Vue 会自动调用
ref
函数并传入null
,无需手动清理。 - 响应式存储:使用
reactive
或ref
对象存储 DOM 引用,方便后续操作。
v-for
和数组保存多个 ref
3.1.2 方法 2:结合 <template>
<div
v-for="(item, index) in items"
:key="item.id"
:ref="(el) => (item.dom = el)"
> {{ item.text }} </div>
</template>
<script setup>
import { ref } from 'vue';
const items = ref([
{ id: 'a', text: 'Item 1', dom: null },
{ id: 'b', text: 'Item 2', dom: null },
]);
</script>
3.1.3 如果动态绑定的是组件
<ChildComponent :ref="(comp) => (childRef = comp)" />
3.2 script setup语法中获取全局的属性和方法
在main.js
中定义全局的内容:
const app = createApp(App)
app.config.globalProperties.$test = '666'
app.mount('#app')
getCurrentInstance
(谨慎使用)
3.2.1 使用 getCurrentInstance
返回当前组件实例,通过它可以间接访问全局属性,但官方不推荐依赖内部实例。
import { getCurrentInstance } from 'vue';
// 获取组件实例
const instance = getCurrentInstance();
// 访问全局属性(如挂载在 globalProperties 上的 $api)
const $api = instance?.appContext.config.globalProperties.$api;
// 使用 $api
$api.getData();
注意事项:
- 不推荐原因:实例内部结构可能随版本变化,且破坏 Composition API 的模块化。
- 使用场景:临时解决方案或访问无法通过其他方式获取的全局属性。
provide/inject
(推荐)
3.2.2 使用 通过依赖注入传递全局内容,更符合 Vue 3 的组合式 API 设计。
在根组件(main.js)提供全局内容:
import { createApp } from 'vue'; import App from './App.vue'; const app = createApp(App); const globalApi = { getData: () => {} }; // 使用 provide 注入全局内容 app.provide('$api', globalApi); app.mount('#app');
在子组件中注入内容:
<script setup> import { inject } from 'vue'; // 注入全局 $api const $api = inject('$api'); // 使用 $api $api.getData(); </script>
优点:
- 显式依赖声明,代码可维护性高。
- 避免依赖内部实例,兼容性更好。
3.2.3 导入全局模块(推荐替代方案)
将全局工具类或配置作为 ES 模块导出,直接按需导入使用。
创建全局模块(如
src/utils/api.js
):export const api = { getData: () => { /* ... */ } };
在组件中按需导入:
<script setup> import { api } from '@/utils/api'; // 直接使用 api.getData(); </script>
优点:
- 完全模块化,无副作用。
- 无需依赖 Vue 实例,适合纯工具函数。
globalProperties
(兼容 Vue 2 风格)
3.2.4 使用 在 main.js
挂载全局属性,通过模板或 Options API 访问,但非 Composition API 推荐方式。
在根组件(main.js)提供全局内容:
// main.js app.config.globalProperties.$api = { getData: () => {} };
在选项式组件中使用:
<!-- 组件中通过 Options API 使用 --> <script> export default { mounted() { this.$api.getData(); } } </script>
3.2.5 总结:最佳实践推荐
方法 | 推荐度 | 场景 |
---|---|---|
provide/inject | ⭐⭐⭐⭐ | 需要跨组件共享的全局状态或服务 |
导入模块 | ⭐⭐⭐⭐ | 工具函数、第三方库等无状态逻辑 |
globalProperties | ⭐⭐ | 兼容旧项目或快速原型开发 |
getCurrentInstance | ⭐ | 临时解决方案,需谨慎使用 |
核心原则:
- 优先使用模块化导入:保持代码解耦和可测试性。
- 跨组件状态用 provide/inject:替代 Vuex/Pinia 的轻量级方案。
- 避免直接操作实例:除非明确了解潜在风险。
通过以上方法,可以在 <script setup>
中安全高效地管理全局依赖。