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

VueJS+Quasar集成Google Places Autocomplete遇InvalidValueError求助

在Quasar框架中集成Google Places Autocomplete时遇到InvalidValueError的解决方案

问题重现

在Quasar地址表单中实现Google Places Autocomplete功能时,触发错误:

InvalidValueError: not an instance of HTMLInputElement

原代码如下:

Google Maps脚本引入

<script src="https://maps.googleapis.com/maps/api/js?key=MY_API_TOKEN&libraries=places"></script>

组件模板

<template>
  <q-card-section class="q-pt-none">
    <q-form @submit="save" class="q-gutter-md">
      <q-input
        filled
        v-model="modelAddress.title"
        :label="$t('address_title_label')"
        :hint="$t('address_title_hint')"
        lazy-rules
        :rules="[isNotEmpty]"
      />
      <q-input
        filled
        v-model="modelAddress.country"
        :label="$t('address_country_label')"
        :hint="$t('address_country_hint')"
        lazy-rules
        :rules="[isNotEmpty]"
      />
      <q-input
        filled
        v-model="modelAddress.city"
        :label="$t('address_city_label')"
        :hint="$t('address_city_hint')"
        lazy-rules
        :rules="[isNotEmpty, isCityOrPostalCode]"
      />
      <q-input
        filled
        v-model="modelAddress.code"
        :label="$t('address_code_label')"
        :hint="$t('address_code_hint')"
        lazy-rules
        :rules="[isNotEmpty]"
      />
      <q-input
        filled
        v-model="modelAddress.street"
        ref="streetRef"
        id="streetRef"
        :label="$t('address_street_label')"
        :hint="$t('address_street_hint')"
        lazy-rules
        :rules="[isNotEmpty]"
      />
      <q-input
        filled
        v-model="modelAddress.number"
        :label="$t('address_number_label')"
        :hint="$t('address_number_hint')"
        lazy-rules
        :rules="[isNotEmpty]"
      />
      <div class="address-form-btn">
        <q-btn color="primary" :label="$t('save_btn')" type="submit" />
      </div>
    </q-form>
  </q-card-section>
</template>

组件脚本

<script>
/* eslint-disable */
import { defineComponent, onMounted, ref } from "vue"

export default defineComponent({
  name: "AddressFrom",
  setup () {
    const streetRef = ref()
    onMounted(() => {
      const autocomplete = new google.maps.places.Autocomplete(streetRef.value, {
        types: ['address'], 
        fields: ['address_components']
      })
    })
    return { streetRef }
  },
  data() {
    return {
      modelAddress: this.address
    }
  },
  props: {
    address: {
      type: String,
      default: "",
    },
  },
  methods: {
    save() {
      this.$emit("save", this.$data.modelAddress)
    },
    isNotEmpty(val) {
      if (!val) {
        return this.$t("please_pick_something")
      }
    }
  }
})
</script>

问题原因

Quasar的<q-input>是封装后的UI组件,通过ref获取到的是Quasar组件实例,不是原生的HTMLInputElement。而Google Places Autocomplete构造函数要求必须传入原生input元素,因此触发类型错误。

解决方案

1. 获取原生input元素

使用Quasar组件提供的getNativeInputEl()方法,直接获取内部的原生input元素,这是最可靠的方式。

2. 修正其他代码问题

  • 修正address props的类型:从String改为Object,因为modelAddress是包含多个字段的对象
  • 统一使用Composition API(提升代码一致性)

修正后的完整代码

<template>
  <q-card-section class="q-pt-none">
    <q-form @submit="save" class="q-gutter-md">
      <!-- 其他输入框保持不变 -->
      <q-input
        filled
        v-model="modelAddress.street"
        ref="streetRef"
        id="streetRef"
        :label="$t('address_street_label')"
        :hint="$t('address_street_hint')"
        lazy-rules
        :rules="[isNotEmpty]"
      />
      <!-- 其他输入框保持不变 -->
    </q-form>
  </q-card-section>
</template>

<script>
/* eslint-disable */
import { defineComponent, onMounted, ref, reactive } from "vue"

export default defineComponent({
  name: "AddressForm",
  props: {
    address: {
      type: Object, // 修正类型为Object
      default: () => ({
        title: "",
        country: "",
        city: "",
        code: "",
        street: "",
        number: ""
      }),
    },
  },
  setup (props) {
    const streetRef = ref()
    // 使用reactive管理表单数据
    const modelAddress = reactive({ ...props.address })

    onMounted(() => {
      if (streetRef.value && window.google) {
        // 获取原生input元素
        const nativeInput = streetRef.value.getNativeInputEl()
        const autocomplete = new google.maps.places.Autocomplete(nativeInput, {
          types: ['address'], 
          fields: ['address_components']
        })

        // 可选:监听自动完成选择事件,自动填充其他字段
        autocomplete.addListener('place_changed', () => {
          const place = autocomplete.getPlace()
          // 解析address_components填充对应字段
          place.address_components.forEach(component => {
            const types = component.types
            if (types.includes('country')) {
              modelAddress.country = component.long_name
            } else if (types.includes('locality')) {
              modelAddress.city = component.long_name
            } else if (types.includes('postal_code')) {
              modelAddress.code = component.long_name
            }
          })
        })
      }
    })

    // 定义校验规则
    const isNotEmpty = (val) => {
      if (!val) {
        return this.$t("please_pick_something")
      }
      return true
    }

    // 提交方法
    const save = () => {
      this.$emit("save", { ...modelAddress })
    }

    return { streetRef, modelAddress, isNotEmpty, save }
  }
})
</script>

额外注意事项

  • 确保Google Maps脚本在组件挂载前已加载完成,否则会出现google is not defined错误
  • 如果使用Quasar CLI,建议将Google Maps脚本配置到quasar.config.js的boot目录下,通过boot文件加载更符合框架规范
  • 可以根据需求调整Autocomplete的types和fields参数,优化自动完成的结果范围

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 20:00:05