面试题答案
一键面试1. 表单绑定
使用Vue的双向数据绑定
在Vue中,对于常规的输入框、下拉框等元素,可以使用v-model
指令进行双向数据绑定。例如:
<input v-model="formData.inputField" />
<select v-model="formData.selectField">
<option v-for="option in options" :value="option.value">{{ option.label }}</option>
</select>
对于自定义组件,可以通过props
传递数据,并通过$emit
触发事件来实现双向绑定。在自定义组件内部,使用modelValue
作为props接收数据,update:modelValue
作为事件名触发数据更新。
<template>
<div>
<input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</div>
</template>
<script setup>
defineProps({
modelValue: {
type: String,
default: ''
}
});
</script>
然后在父组件中使用:
<CustomComponent v-model="formData.customField" />
2. 初始值管理
异步获取初始值
可以使用async/await
或Promise来处理异步数据源。在created
或mounted
钩子函数中发起异步请求。
import { ref } from 'vue';
import { fetchData1, fetchData2 } from '@/api';
export default {
setup() {
const formData = ref({});
const fetchInitialData = async () => {
const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);
formData.value = {
...data1,
...data2
};
};
fetchInitialData();
return { formData };
}
};
使用Vuex进行状态管理(可选,对于大型项目)
如果项目比较复杂,可以引入Vuex来管理表单的初始值状态。在Vuex的actions
中进行异步请求,mutations
中更新状态。
// store/modules/form.js
import { fetchData1, fetchData2 } from '@/api';
const state = {
initialFormData: {}
};
const actions = {
async fetchInitialData({ commit }) {
const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);
commit('SET_INITIAL_FORM_DATA', { ...data1, ...data2 });
}
};
const mutations = {
SET_INITIAL_FORM_DATA(state, data) {
state.initialFormData = data;
}
};
export default {
namespaced: true,
state,
actions,
mutations
};
在组件中:
<script setup>
import { useStore } from 'vuex';
const store = useStore();
const formData = ref({});
store.dispatch('form/fetchInitialData').then(() => {
formData.value = store.state.form.initialFormData;
});
</script>
3. 表单重置功能
保存提交前的值
在提交表单前,将当前表单的值备份。可以使用一个辅助变量来存储。
import { ref } from 'vue';
export default {
setup() {
const formData = ref({});
const backupFormData = ref({});
const submitForm = async () => {
backupFormData.value = { ...formData.value };
try {
await submit(formData.value);
} catch (error) {
// 提交失败,恢复某些字段
formData.value = {
...backupFormData.value,
errorField: '特定的错误提示值'
};
}
};
return { formData, submitForm };
}
};
优雅的重置逻辑
可以封装一个重置函数,将恢复和设置错误提示值的逻辑封装起来。
const resetForm = (formData, backupFormData) => {
formData.value = {
...backupFormData.value,
errorField: '特定的错误提示值'
};
};
const submitForm = async () => {
backupFormData.value = { ...formData.value };
try {
await submit(formData.value);
} catch (error) {
resetForm(formData, backupFormData);
}
};
4. 性能优化
防抖与节流
对于频繁触发的事件(如输入框输入事件),使用防抖或节流函数来减少不必要的计算。可以使用lodash
库中的debounce
和throttle
函数。
<input @input="debouncedInput" />
import { debounce } from 'lodash';
import { ref } from 'vue';
export default {
setup() {
const formData = ref('');
const debouncedInput = debounce((value) => {
// 处理输入逻辑
formData.value = value;
}, 300);
return { formData, debouncedInput };
}
};
减少不必要的重新渲染
使用computed
属性而不是watch
来监听数据变化,因为computed
会缓存计算结果,只有当依赖数据变化时才重新计算。同时,在模板中避免过多的复杂表达式,将复杂逻辑封装到方法或计算属性中。
5. 代码结构
组件化
将表单拆分成多个组件,每个组件负责一部分功能。例如,将具有相同交互逻辑的输入框组封装成一个组件,自定义组件单独封装。这样可以提高代码的复用性和可维护性。
// FormInputGroup.vue
<template>
<div>
<input v-model="formData.input1" />
<input v-model="formData.input2" />
</div>
</template>
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
formData: {
type: Object,
required: true
}
});
</script>
在主表单组件中使用:
<template>
<div>
<FormInputGroup :formData="formData" />
<CustomComponent v-model="formData.customField" />
</div>
</template>
<script setup>
import FormInputGroup from '@/components/FormInputGroup.vue';
import CustomComponent from '@/components/CustomComponent.vue';
import { ref } from 'vue';
const formData = ref({});
</script>
目录结构
src/
├── api/
│ ├── fetchData1.js
│ ├── fetchData2.js
│ └── submit.js
├── components/
│ ├── CustomComponent.vue
│ └── FormInputGroup.vue
├── store/
│ ├── modules/
│ │ └── form.js
│ └── index.js
├── views/
│ └── FormView.vue
└── main.js
通过这样的目录结构,可以清晰地组织代码,将不同功能的代码放在相应的目录下,方便维护和扩展。