You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quasar QSelect首次打开未定位至选中选项问题求助

QSelect首次打开未滚动到选中项,二次打开正常的问题排查

我基于Quasar UI构建Vue 3/TypeScript应用,开发带国家下拉框的国际电话输入组件时遇到问题:使用QSelect实现的下拉框,首次打开选项列表时停在顶部,不会自动滚动到当前选中项;但关闭后重新打开,就能正确滚动到选中项——这才是首次打开时的预期行为。

已尝试的无效方案

在handleOnCountryOptionsShow方法中试过以下操作,均未解决问题:

  • 调用reset()、refresh()、updateMenuPosition()方法
  • 获取选中项索引后调用scrollTo(index)
  • 使用nextTick()等待渲染完成

问题复现代码

<template>
  <q-input ref="inputElement" v-model="inputNumber">
    <template #prepend>
      <q-select
        ref="countrySelectElement"
        v-model="countrySelected"
        :options="countryOptions"
        option-value="id"
        option-label="name"
        :virtual-scroll-slice-size="countryOptions?.length"
        :virtual-scroll-item-size="countryOptionItemHeight"
        @popup-show="handleOnCountryOptionsShow"
      >
        <template #option="scope">
          <div>
            <div
              class="country-item q-pa-sm cursor-pointer"
              :class="{ 'country-option-focused': scope.focused }"
            >
              {{ scope.opt.name }}
            </div>
            <q-resize-observer
              @resize="hanldeCountryOptionResize"
            ></q-resize-observer>
          </div>
        </template>
        <template #selected-item="scope">
          <div v-if="scope.opt">
            {{ scope.opt.name }}
          </div>
        </template>
      </q-select>
      <q-separator vertical />
    </template>
  </q-input>
</template>

<script lang="ts" setup>
import { nextTick, onMounted, ref } from "vue";
import { QSelect, QInput, QResizeObserver } from "quasar";

const inputElement = ref<QInput | null>(null);
const inputNumber = ref<string>();

const countrySelectElement = ref<QSelect | null>(null);
const countrySelected = ref<{ id: number; name: string }>();
const countryOptions = ref<{ id: number; name: string }[]>();
const countryOptionItemHeight = ref(0);

const generateCountries = () => {
  const countries: { id: number; name: string }[] = [];
  for (let i = 1; i <= 250; i++) {
    countries.push({ id: i, name: `Country ${i}` });
  }
  return countries;
};

const hanldeCountryOptionResize = (size: { height: number; width: number }) => {
  if (!countryOptionItemHeight.value) {
    countryOptionItemHeight.value = size.height;
  }
};

onMounted(() => {
  // 生成国家列表
  countryOptions.value = generateCountries();
  // 初始化选中项
  countrySelected.value = countryOptions.value[111];
});

const handleOnCountryOptionsShow = async () => {
  await nextTick();
  const index = countrySelectElement.value?.getOptionIndex();
  console.log("index", index); // 能正确打印选中项索引
  countrySelectElement.value?.reset();
  countrySelectElement.value?.refresh();
  countrySelectElement.value?.updateMenuPosition();
  if (index) countrySelectElement.value?.scrollTo(index);
};
</script>

<style>
.country-item:hover,
.country-option-focused {
  background-color: #eeeeee;
}
</style>

问题截图

问题截图

关键发现

经测试,问题与自定义#option插槽相关——移除该插槽后,QSelect首次打开就能正常滚动到选中项,但我需要保留自定义插槽的样式。


解决方案

1. 修复虚拟滚动高度初始化问题

首次打开时,countryOptionItemHeight可能还未通过resize-observer获取到正确值,导致虚拟滚动无法计算选中项位置。可以提前设置默认高度:

onMounted(() => {
  countryOptions.value = generateCountries();
  countrySelected.value = countryOptions.value[111];
  // 提前设置默认高度(根据自定义选项的样式调整,比如q-pa-sm的元素高度约48px)
  countryOptionItemHeight.value = 48;
});

2. 调整滚动触发时机

虚拟列表首次渲染需要更多时间,可通过两次nextTick确保DOM完全渲染后再触发滚动:

const handleOnCountryOptionsShow = async () => {
  await nextTick();
  await nextTick(); // 等待虚拟列表完成渲染
  const index = countrySelectElement.value?.getOptionIndex();
  if (index !== undefined) {
    countrySelectElement.value?.scrollTo(index);
  }
};

3. 优化虚拟滚动配置

移除virtual-scroll-slice-size="countryOptions?.length",该配置会强制渲染所有选项,失去虚拟滚动意义,同时可能干扰滚动计算:

<q-select
  ref="countrySelectElement"
  v-model="countrySelected"
  :options="countryOptions"
  option-value="id"
  option-label="name"
  :virtual-scroll-item-size="countryOptionItemHeight"
  @popup-show="handleOnCountryOptionsShow"
>

内容的提问来源于stack exchange,提问作者TinyTiger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 18:47:08