[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) 区别

使用 constlet 声明 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 区别

使用 constlet 声明 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 可以通过以下两种常见方式实现,尤其是在需要根据‌动态变量‌(比如循环中的索引或数据标识)管理引用时:

3.1.1 方法 1:使用函数形式的 ref(推荐)

在模板中通过函数动态绑定 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,无需手动清理。
  • 响应式存储‌:使用 reactiveref 对象存储 DOM 引用,方便后续操作。

3.1.2 方法 2:结合 v-for 和数组保存多个 ref

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

3.2.1 使用 getCurrentInstance(谨慎使用)

getCurrentInstance 返回当前组件实例,通过它可以间接访问全局属性,但官方不推荐依赖内部实例。

import { getCurrentInstance } from 'vue';

// 获取组件实例
const instance = getCurrentInstance();

// 访问全局属性(如挂载在 globalProperties 上的 $api)
const $api = instance?.appContext.config.globalProperties.$api;

// 使用 $api
$api.getData();

注意事项:

  • 不推荐原因:实例内部结构可能随版本变化,且破坏 Composition API 的模块化。
  • 使用场景:临时解决方案或访问无法通过其他方式获取的全局属性。

3.2.2 使用 provide/inject(推荐)

通过依赖注入传递全局内容,更符合 Vue 3 的组合式 API 设计。

  1. 在根组件(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');
    
  2. 在子组件中注入内容

    <script setup>
    import { inject } from 'vue';
    // 注入全局 $api
    const $api = inject('$api');
    // 使用 $api
    $api.getData();
    </script>
    
  3. 优点

    • 显式依赖声明,代码可维护性高。
    • 避免依赖内部实例,兼容性更好。

3.2.3 导入全局模块(推荐替代方案)

将全局工具类或配置作为 ES 模块导出,直接按需导入使用。

  1. 创建全局模块(如 src/utils/api.js

    export const api = {
      getData: () => { /* ... */ }
    };
    
  2. 在组件中按需导入

    <script setup>
    import { api } from '@/utils/api';
    // 直接使用
    api.getData();
    </script>
    
  3. 优点

    • 完全模块化,无副作用。
    • 无需依赖 Vue 实例,适合纯工具函数。

3.2.4 使用 globalProperties(兼容 Vue 2 风格)

main.js 挂载全局属性,通过模板或 Options API 访问,但非 Composition API 推荐方式。

  1. 在根组件(main.js)提供全局内容

    // main.js
    app.config.globalProperties.$api = { getData: () => {} };
    
  2. 在选项式组件中使用

    <!-- 组件中通过 Options API 使用 -->
    <script>
    export default {
      mounted() {
        this.$api.getData();
      }
    }
    </script>
    

3.2.5 总结:最佳实践推荐

方法 推荐度 场景
provide/inject ⭐⭐⭐⭐ 需要跨组件共享的全局状态或服务
导入模块 ⭐⭐⭐⭐ 工具函数、第三方库等无状态逻辑
globalProperties ⭐⭐ 兼容旧项目或快速原型开发
getCurrentInstance 临时解决方案,需谨慎使用

核心原则

  • 优先使用模块化导入:保持代码解耦和可测试性。
  • 跨组件状态用 provide/inject:替代 Vuex/Pinia 的轻量级方案。
  • 避免直接操作实例:除非明确了解潜在风险。

通过以上方法,可以在 <script setup> 中安全高效地管理全局依赖。

参考资料

vue3中getCurrentInstance不推荐使用以及在<script setup>中获取全局内容(三种方式)

Last Updated: 4/15/2025, 11:23:38 AM