【问题标题】:Auto-select first <select> option when loading async options in Vue 3在 Vue 3 中加载异步选项时自动选择第一个 <select> 选项
【发布时间】:2021-06-04 15:09:25
【问题描述】:

我有一个 &lt;select&gt; HTML 元素,我想将它 v-model 绑定到 Vue.js 3 的 setup() 方法中的 ref 值。因此,当用户选择不同的选项时,Form.ProductID 引用会更新。

这里是&lt;select&gt; 代码:

<select v-model="Form.ProductID" id="ProductID" name="ProductID">
  <option value="1">Option A</option>
  <option value="2">Option B</option>
  <option value="3">Option C</option>
</select>

还有setup():

export default {
  name: "ComponentProductSelector",
  setup() {
    const Form = ref({
      ProductID: '2',
      Price: null,
      Currency: null
    })

    onMounted(() => Form.value.ProductID)
    document.querySelector("#ProductID option:first-of-type")
  }
}

在 vue devtools 中首次加载时,它显示数据为:

Form (Object Ref) 
    ProductID: "[object HTMLOptionElement]"

当我在 &lt;select&gt; 元素中选择一个选项时,Form.ProductID 会按预期更新并显示我选择了哪个选项,例如:

 Form (Object Ref) 
        ProductID: 3

问题是在第一次加载页面时,&lt;select&gt; 元素没有选择带有value="2" 的选项,即使我在setup() 中对其进行了硬编码。它只是显示一个空白选项!但是,如果我将 &lt;select&gt; 元素更改为以下代码,则可以:

<select ref="Form.ProductID" id="ProductID" name="ProductID">
  <option value="1">Option A</option>
  <option value="2">Option B</option>
  <option value="3">Option C</option>
</select>

现在渲染组件时默认选择带有value="2"的选项,但是Form.ProductID的实际值不会更新,vue devtools继续将ProductID: "[object HTMLOptionElement]"显示为数据。

如何让&lt;select&gt; 元素使用v-model 工作,并在组件加载时选择默认选项?

【问题讨论】:

  • 肯定有不同的问题,应该可以工作jsfiddle.net/sh0ber/zrj18f69
  • @shob 你是对的,这是一段代码:onMounted(() =&gt; Form.value.ProductID = document.querySelector("#ProductID option:first-of-type") 默认选择第一个选项。是否可以让Form.value.ProductID等于第一个选项onMounted的值?
  • 为什么不将Form.ProductID 设置为 1?
  • @shob 因为我不能总是知道 ID 是什么。它们最终将来自数据库作为 json

标签: javascript vue.js vuejs3 vue-composition-api vue-reactivity


【解决方案1】:

回答 cmets 中关于异步加载时如何选择第一个选项的更新问题。加载数据后,将 Form 的值设置为 options 数组中的第一项(克隆以避免变异),而不是手动操作输入 DOM。

例如:

<select v-model="Form.ProductID" id="ProductID" name="ProductID" v-if="options">
  <option v-for="option in options" :key="option.ProductID" :value="option.ProductID">
    {{ option.ProductID }}
  </option>
</select>
setup() {
  const options = ref(null);
  const Form = ref(null);

  axios.get('...').then(response => {
    options.value = response.data;
    Form.value = { ...options.value[0] };    // Clone and select first option
  });
  return { options, Form }
}

&lt;select&gt; 上有一个v-if,用于延迟其渲染,直到数据准备好。

这是一个演示:

const { createApp, ref } = Vue;
const app = createApp({
  setup() {
    const options = ref(null);
    const Form = ref(null);
    
    axios.get('https://jsonplaceholder.typicode.com/posts').then(response => {
      options.value = response.data;
      Form.value = { ...options.value[0] };    // Clone and select first option
    });
    return { options, Form }
  }
});
app.mount("#app");
<div id="app">
  <select v-model="Form.id" id="ProductID" name="ProductID" v-if="options">
    <option v-for="option in options" :key="option.id" :value="option.id">
      {{ option.id }}
    </option>
  </select>
</div>

<script src="https://unpkg.com/vue@next"></script>
<script src="https://unpkg.com/axios"></script>

【讨论】:

  • 不客气!我做了一个小更新。首先克隆选项很重要,或者为Form 创建一个新对象并一个一个添加属性,克隆任何引用类型。否则更改表单输入会更改选项 #1 的选项数据
猜你喜欢
  • 2020-04-28
  • 2014-11-18
  • 2015-10-12
  • 2014-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多