【问题标题】:Vuejs typescript this.$refs.<refField>.value does not existVuejs 打字稿 this.$refs.<refField>.value 不存在
【发布时间】:2020-11-26 04:24:34
【问题描述】:

在使用 typescript 重写我的 VueJs 项目时,我遇到了 TypeScript 错误。

这是具有自定义 v-model 的组件的一部分。

html 中的输入字段有一个名为“plate”的引用,我想访问它的值。该字段上的@input 调用下面编写的更新方法。

Typescript 抱怨盘子上不存在值。

@Prop() value: any;

update() {
    this.$emit('input',
        plate: this.$refs.plate.value
    });
}

模板:

<template>  
<div>
    <div class="form-group">
        <label for="inputPlate" class="col-sm-2 control-label">Plate</label>

        <div class="col-sm-10">
            <input type="text" class="form-control" id="inputPlate" ref="plate" :value="value.plate" @input="update">
        </div>
    </div>

</div>
</template>

【问题讨论】:

  • 可以将类型标记为 HTMLInputElement

标签: javascript typescript vue.js vuejs2 vue-component


【解决方案1】:

你可以这样做:

class YourComponent extends Vue {
  $refs!: {
    checkboxElement: HTMLFormElement
  }

  someMethod () {
    this.$refs.checkboxElement.checked
  }
}

来自本期:https://github.com/vuejs/vue-class-component/issues/94

【讨论】:

  • 我正在使用let mycomp = Vue.extend({}) 语法。我怎么能这样做呢?我也应该使用上面的语法吗?
  • 您可以创建一个表示 ref 类型的接口,然后将其转换为该类型。至少那时您避免了任何,并且您的视图将根据它进行类型检查。
  • 嗯,谢谢.. 我实际上讨厌 vue 类组件中的装饰器。
  • 这不起作用。也许它曾经是,但不是今天(使用 vue-cli 3)。
  • 我需要写$refs!:(注意感叹号)才能让它工作,但我使用的是vue-property-decorator。 @George 如果我的修复没问题,您能否编辑答案?不想为类组件用户破坏它,因为那里可能存在一些差异(编辑:啊实际上感叹号在您发布的链接中)
【解决方案2】:

编辑 - 2021-03(组合 API)

更新此答案是因为 Vue 3(如果您使用的是 Vue 2,则为组合 API 插件)具有一些新功能。

<template>
  <div ref="root">This is a root element</div>
</template>

<script lang="ts">
  import { ref, onMounted, defineComponent } from '@vue/composition-api'

  export default defineComponent({
    setup() {
      const root = ref(null)

      onMounted(() => {
        // the DOM element will be assigned to the ref after initial render
        console.log(root.value) // <div>This is a root element</div>
      })

      return {
        root
      }
    }
  })
</script>

编辑 - 2020-04:

我推荐的vue-property-decorator library provides @Ref,而不是我原来的答案。

import { Vue, Component, Ref } from 'vue-property-decorator'

import AnotherComponent from '@/path/to/another-component.vue'

@Component
export default class YourComponent extends Vue {
  @Ref() readonly anotherComponent!: AnotherComponent
  @Ref('aButton') readonly button!: HTMLButtonElement
}

原答案

以上答案都不适用于我想要做的事情。添加以下 $refs 属性最终修复了它,并且似乎恢复了预期的属性。我在this github post.上找到了链接的解决方案

class YourComponent extends Vue {
  $refs!: {
    vue: Vue,
    element: HTMLInputElement,
    vues: Vue[],
    elements: HTMLInputElement[]
  }

  someMethod () {
    this.$refs.<element>.<attribute>
  }
}

【讨论】:

  • 这引导我走向正确的方向。我是 vuejs 新手,不太了解 $ref 的用法,所以对于像我这样的其他人:@Ref('aButton') readonly button!: HTMLButtonElement 允许您从脚本中以 this.button 访问 &lt;button ref="aButton" ... /&gt; 所在的元素。
  • const root = ref(null) TypeScript 编译器怎么可能知道root 的类型在这里?不需要明确指定类型 (HTMLDivElement) 吗?
  • 是的,我相信 vue 的 composition api 的类型是这样的 ref(null) 真的是 ref(null) 或类似的东西
【解决方案3】:

这对我有用:使用 (this.$refs.&lt;refField&gt; as any).value(this.$refs.['refField'] as any).value

【讨论】:

  • 应该是(this.$refs['refField'] as any).value
  • 这清除了错误,但首先破坏了使用 typescript 的好处。
  • 可能更适合转换为unknown,然后转换为casttype-guard 转换为您需要的任何其他值。 unknown 更宽松,但仍会进行通常的类型检查,因此更安全。
  • 无需投射任何东西。 ref 的类型为 Vue | Element | Vue[] | Element[],如果不够具体,您可以使用 instanceof 运算符来修复类型错误并根据特定返回类型抛出异常或运行循环或您需要执行的任何其他操作运行时。
【解决方案4】:

son.vue

const Son = Vue.extend({
  components: {},
  props: {},
  methods: {
    help(){}
  }
  ...
})
export type SonRef = InstanceType<typeof Son>;
export default Son;

父.vue

<son ref="son" />

computed: {
  son(): SonRef {
    return this.$refs.son as SonRef;
  }
}

//use
this.son.help();

【讨论】:

  • 引用自定义组件类型的绝妙方法。这种方式也让我可以避免使用类装饰器。
  • 看起来很酷,但是方法名称自动完成在 PhpStorm 中对我不起作用:( import VForm from 'vuetify/src/components/VForm/VForm.ts'; type RefVForm = InstanceType&lt;typeof VForm&gt;;
  • InstanceType 是我所需要的。谢谢
  • 是的!这正是官方文档中缺少的内容。为什么我要使用类组件?选项 API 要好得多...
【解决方案5】:

避免使用方括号&lt; &gt; 进行类型转换,因为它会与 JSX 冲突。

试试这个

update() {
    const plateElement = this.$refs.plate as HTMLInputElement
    this.$emit('input', { plate: plateElement.value });
}

作为我一直记得的笔记

Typescript 只是 Javascript,具有强大的打字能力以确保类型安全。所以 (通常) 它不会预测 X 的类型(var、param 等),也不会 自动 对任何操作进行类型转换。

另外,typescript 的另一个目的是让 JS 代码变得更清晰/可读,所以总是尽可能地定义类型。

【讨论】:

    【解决方案6】:

    也许它对某人有用。它看起来更漂亮,并且仍然支持类型。

    HTML:

    <input ref="inputComment" v-model="inputComment">
    

    TS:

    const inputValue = ((this.$refs.inputComment as Vue).$el as HTMLInputElement).value;
    

    【讨论】:

      【解决方案7】:

      如果是自定义组件方法调用,

      我们可以对该组件名称进行类型转换,因此很容易引用该方法。

      例如

      (this.$refs.annotator as AnnotatorComponent).saveObjects();
      

      其中 AnnotatorComponent 是基于类的 vue 组件,如下所示。

      @Component
      export default class AnnotatorComponent extends Vue {
          public saveObjects() {
              // Custom code
          }
      }
      

      【讨论】:

        【解决方案8】:

        我找到了让它工作的方法,但在我看来它很丑。

        随时提出其他/更好的建议。

        update() {
            this.$emit('input', {
                plate: (<any>this.$refs.plate).value,
            });
        }
        

        【讨论】:

        • 强制转换为 any 不是类型安全的 - 最好像下面的答案那样定义 $refs :)
        【解决方案9】:

        如果您要将现有的 vue 项目从 js 转换为 ts 并希望保留旧格式,请确保使用 Vue.extend() 包装您的导出。

        之前:

        <script lang="ts">
        
        export default {
          mounted() {
            let element = this.$refs.graph;
        
        ...
        

        之后:

        <script lang="ts">
        
        import Vue from "vue";
        
        export default Vue.extend({
          mounted() {
            let element = this.$refs.graph;
        
        ...
        

        【讨论】:

          猜你喜欢
          • 2021-03-21
          • 1970-01-01
          • 2015-12-16
          • 1970-01-01
          • 1970-01-01
          • 2017-11-28
          相关资源
          最近更新 更多