Vue Writing Standards
SFC Order
script
import statements
Recommended dependency order:
- vue
- vue-router
- pinia
- @vueuse/core
- UI libraries
- Other dependencies
- Internal project dependencies (monorepo)
- Alias imports
- Relative path imports
Types should be imported separately using
import type
and placed below the same dependencyExample:
tsimport { ref } from 'vue'; import type { Ref } from 'vue';
defineOptions
Props type definition
tsinterface Props { prop1: string; prop2: number; }
defineProps
tsdefineProps<Props>(); const props = defineProps<Props>(); // When using props
Emits type definition
tsinterface Emits { emit1: (arg1: string) => void; emit2: (arg1: number) => void; } // Or interface Emits { emit1: [arg1: string]; emit2: [arg1: number]; }
defineEmits
tsdefineEmits(); const emit = defineEmits(); // When using emit
Imported hooks functions
Example: useRouter, useRoute, and custom hooks
tsconst router = useRouter(); const route = useRoute(); const appStore = useAppStore(); const { loading, startLoading, endLoading } = useLoading();
Component logic definition
tsconst count = ref(0); const increment = () => { count.value++; }; const visible = ref(false); const toggleVisible = () => { visible.value = !visible.value; };
Necessary
init
function, all initialization logic is placed heretsasync function init() { await fetchData(); }
watch and watchEffect
tswatchEffect(() => { console.log(count.value); }); watch( () => count.value, (newValue, oldValue) => { console.log(newValue, oldValue); } );
Lifecycle hooks
ts// Equivalent to executing in the `created` hook init(); onMounted(() => { console.log('mounted'); });
defineExpose
tsconst exposed = { count, increment }; defineExpose(exposed);