Vue3+Quasar中q-tabs切换时自定义组件值显示异常求助
问题分析
出现标签页切换时自定义组件显示旧值但提交数据正确的情况,核心原因是自定义组件的数据同步逻辑不规范和全局变量共享导致的状态混乱:
- 全局变量
dataArr被所有组件实例共享,切换标签页时不同实例的选项数据会互相干扰 - 自定义组件未遵循Vue的v-model规范,使用了自定义的
UserProfileprops和change事件,导致父子组件间的数据同步存在延迟或失效 - 内部
model的初始化和watch逻辑存在引用赋值问题,无法正确响应外部props的更新
解决方案
1. 移除全局共享变量,改为组件内部私有数据
将全局的dataArr移到组件的data中,确保每个组件实例拥有独立的选项数据,避免跨实例干扰。
2. 遵循Vue v-model规范
使用标准的modelValue props和update:modelValue事件实现双向绑定,替代自定义的UserProfile和change事件,确保数据同步的可靠性。
3. 修正数据同步逻辑
- 内部
model通过computed实现双向绑定,确保内部状态和外部props实时同步 - 监听
modelValue变化,处理异步加载选项可能导致的显示异常
4. 处理标签页组件缓存(可选)
如果父组件的q-tab-pane使用了keep-alive,在组件的activated钩子中重新同步数据,确保激活标签页时显示最新值。
修改后的自定义组件代码
<script> export default { props: { modelValue: { // 改用标准v-model的props名 type: Object, required: true }, PropertyName: { type: String, }, ParentName: { type: String, }, readonly: { type: Boolean, default: false, }, }, data() { return { applicationName: this.$gf_p.Prospot, name: "UserProfile", controllerName: "Master", dataArr: [], // 改为组件内部私有数据 options: [], parentName: "", }; }, computed: { // 用computed实现内部model与外部modelValue的双向绑定 model: { get() { return this.modelValue; }, set(newVal) { this.$emit('update:modelValue', newVal); } } }, methods: { filterFn(val, update, abort) { update(() => { const needle = val.toLowerCase(); this.options = this.dataArr.filter( (v) => v.Name.toLowerCase().indexOf(needle) > -1 ); }); }, getUserProfile() { this.$gf .GetApi(this.applicationName, this.controllerName, this.name) .then((response) => { this.dataArr = JSON.parse(response.data.result); this.options = this.dataArr; }); }, }, watch: { // 监听外部props变化,确保值匹配选项时正常显示 modelValue(newVal) { if (this.dataArr.length > 0 && newVal) { const exists = this.dataArr.some(item => item.ID === newVal.ID); // 可选:如果值不在选项中,可清空或做其他处理 // if (!exists) this.model = null; } } }, mounted() { this.getUserProfile(); }, activated() { // 标签页激活时,若选项未加载则重新请求 if (this.dataArr.length === 0) { this.getUserProfile(); } } }; </script> <template> <div> <q-select outlined dense v-model="model" use-input input-debounce="0" :options="options" @filter="filterFn" option-value="ID" option-label="Name" :label="$gf.getLabel(PropertyName, ParentName)" style="width: 100%" :readonly="readonly" > <template v-slot:append v-if="!readonly"> <q-icon v-if="model !== ''" name="close" @click.stop="model = ''" class="cursor-pointer" /> </template> <template v-slot:no-option> <q-item> <q-item-section class="text-grey"> No results </q-item-section> </q-item> </template> </q-select> </div> </template>
父组件使用方式调整
将原来的自定义绑定改为标准v-model写法:
<!-- 原写法 --> <CustomSelect :UserProfile="form.userProfile" @change="form.userProfile = $event" /> <!-- 修改后写法 --> <CustomSelect v-model="form.userProfile" :PropertyName="..." :ParentName="..." />
内容的提问来源于stack exchange,提问作者Busenur Adıbelli
相关产品推荐
相关产品推荐

