DEV Community

Leo
Leo

Posted on

Vue 3 `<script setup>` 代码组织标准指南

组织顺序概览 (1-8 模式)

顺序 类别 说明
1 核心依赖引入 Vue 内置 API、插件、第三方通用库。
2 业务资源引入 自定义组件、自定义 Hooks、常量定义、API 函数。
3 组件通信定义 definePropsdefineEmits
4 状态声明区 ref, reactive, Hooks 执行结果, Template Refs
5 计算属性 computed
6 逻辑方法 所有的交互函数、内部辅助函数。
7 副作用与监听 onMounted, watch, watchEffect
8 对外暴露 defineExpose

完整代码示例:用户管理弹窗

<script setup>
/** * 1. 核心依赖引入 
 */
import { ref, computed, onMounted, watch } from 'vue'
import { ElMessage } from 'element-plus'

/** * 2. 业务资源引入 (组件、Hooks、API)
 */
import UserEditDialog from './components/UserEditDialog.vue'
import { useUserManagement } from '@/hooks/useUserManagement'
import { DEFAULT_ROLE } from '@/constants/user'

/** * 3. 组件通信定义 (Props & Emits)
 */
const props = defineProps({
  userId: { type: Number, default: null }
})
const emit = defineEmits(['refresh', 'close'])

/** * 4. 状态声明 (Hooks 执行, Refs, Template Refs)
 */
// 执行自定义 Hooks 获取共享逻辑
const { list, loading, submitting, loadList, saveUser } = useUserManagement()

// 模板引用 (对应模板中 ref="dialogRef")
const dialogRef = ref(null) 

// 本地私有响应式状态
const isEditMode = ref(false)
const searchQuery = ref('')

/** * 5. 计算属性 (Computed)
 */
const dialogTitle = computed(() => isEditMode.value ? '编辑用户' : '新增用户')

/** * 6. 逻辑方法 (Functions)
 */
const handleOpenAdd = () => {
  isEditMode.value = false
  dialogRef.value?.open()
}

const handleConfirmSave = async (data) => {
  const success = await saveUser(props.userId, data)
  if (success) {
    emit('refresh')
    dialogRef.value?.close()
  }
}

/** * 7. 生命周期钩子 & 监听器 (Lifecycle & Watchers)
 */
onMounted(() => {
  if (props.userId) {
    isEditMode.value = true
    loadList()
  }
})

watch(() => props.userId, (newId) => {
  console.log('用户 ID 变更为:', newId)
})

/** * 8. 对外暴露 (Expose)
 */
defineExpose({
  openAdd: handleOpenAdd,
  refresh: loadList
})
</script>

<template>
  <UserEditDialog ref="dialogRef" @save="handleConfirmSave" />
</template>

Enter fullscreen mode Exit fullscreen mode

为什么这样组织最科学?

  1. 依赖清晰:文件顶部的 import 区让你一眼看出这个组件依赖了哪些外部组件和 Hooks,不会出现“逻辑幽灵”。
  2. 契合 Vue 初始化流程
  3. 先接收 props(外部输入)。
  4. 基于输入初始化 state(内部变量)。
  5. 基于变量定义 computed(数据加工)。
  6. 最后在 onMounted(生命周期)中触发。

  7. 心智负担低:当你需要查找一个方法时,直接滚到代码中后部;当你需要查看有哪些响应式变量时,直接看中前部。这在多人协作中能极大减少代码阅读时间。

📌 最佳实践提示:

  • 关于 Template Refs:始终把 const dialogRef = ref(null) 放在第 4 部分,紧跟在 Hooks 调用之后。

Top comments (0)