如何在 Vue 中以 Typescript 语法定义使用 prop 作为其初始值的本地数据属性?

Posted

技术标签:

【中文标题】如何在 Vue 中以 Typescript 语法定义使用 prop 作为其初始值的本地数据属性?【英文标题】:How can I, in Vue, define a local data property that uses a prop as its initial value, in Typescript syntax? 【发布时间】:2019-06-25 10:20:57 【问题描述】:

在 Vue 中将 prop 传递给子组件时,documentation 表示:

另外,每次父组件更新时,子组件中的所有 props 都会刷新为最新的值。这意味着您不应该尝试改变子组件内的道具。如果你这样做了,Vue 会在控制台中警告你。

prop用于传入一个初始值;子组件之后希望将其用作本地数据属性。在这种情况下,最好定义一个使用 prop 作为初始值的本地数据属性:

props: ['initialCounter'],
data: function () 
  return 
    counter: this.initialCounter
  

我们正在使用打字稿。 “定义本地数据属性”的语法如下(to my understanding):

<script lang="ts">
import Vue from 'vue'
import  Component  from 'vue-property-decorator'

@Component
export default class App extends Vue 
  // Data property
  myDataProperty: string;
</script>

prop 的语法是:

@Component
export default class App extends Vue 
  // Makes a "exampleProperty" a component prop with the default value of 'Example'
  @Prop(default: 'Example')
  exampleProperty: string

所以,我们尝试按照文档进行操作,结果是:

parentComponent.vue

<template>
  <childComponent testProperty='test' />
</template>

childComponent.vue

<script lang="ts">
import  Component, Prop, Vue  from 'vue-property-decorator';

@Component
export default class childComponent extends Vue 
  @Prop(
    
      default: 'notTest',
      validator: (component) => 
        return [
          'notTest',
          'test',
        ].indexOf(component) > -1;
      ,
    ,
  )
  testProperty!: string;
  testProperty = this.testProperty;
</script>

可以预见的是,会出现`Duplicate identifier testProperty.

所以,我们尝试了

...
      testProperty!: this.testProperty;
...

导致

重复的标识符“testProperty”。 属性 'testProperty' 没有初始化程序,也没有在构造函数中明确分配。 后续的属性声明必须具有相同的类型。属性“testProperty”的类型必须为“this”,但此处的类型为“any”。

所以,我决定试试"vue-class-component" decorator.

<script lang="ts">
import  Component, Prop, Vue  from 'vue-property-decorator';

@Component(
  data: function()
    return 
      testProperty: this.testProperty,
    
  
)
export default class childComponent extends Vue 
  @Prop(
    
      default: 'notTest',
      validator: (component) => 
        return [
          'notTest',
          'test',
        ].indexOf(component) > -1;
      ,
    ,
  )
  testProperty!: string;
  testProperty = this.testProperty;
</script>

这导致了错误Property 'testProperty' does not exist on type 'Vue'.

我想在某个处理程序中执行this.testProperty = 'newProperty',但不能,因为那将直接修改道具。

如何在 Typescript 中定义使用 prop 作为初始值的本地数据属性?

编辑:

如果我以上都不做,只是简单地定义了prop,没有尝试定义一个使用prop作为初始值的本地数据属性,然后做

this.testProperty = '测试'

在处理程序中,此错误会显示在 chrome 控制台中:

vue.runtime.esm.js[Vue warn]:避免直接修改 prop,因为每当父组件重新渲染时,该值都会被覆盖。相反,使用基于道具值的数据或计算属性。正在变异的道具:“testProperty”

【问题讨论】:

你不需要使用testProperty = this.testProperty;,也不需要在你的组件数据中声明testProperty 你能澄清一下吗?我想在 childComponent 级别拥有道具的验证器 只需使用@Prop(..) testProperty!: string 就足够了。此外,通过在数据中声明它会导致发生覆盖(因为数据和属性共享相同的命名空间),这将导致 Vue 抛出此警告:[Vue warn]: The data property "testProperty" is already declared as a prop. Use prop default value instead.@Prop 装饰器将处理 (1) 分配默认值, (2) 执行验证:github.com/kaorun343/… 嗯。你能看看我做的编辑吗?如果我只执行 @Prop... 位,稍后尝试修改该属性时会出现错误。 你不能改变一个道具:无论你用 TS 还是 JS 做,你都会得到同样的警告。如果需要,将该道具复制到数据对象中,但使用不同的键,例如。 return testPropertyLocal: this.testProperty 。然后,您可以稍后使用您想要的任何值重新分配 this.testPropertyLocal。然而,这对我来说感觉像是一个 XY 问题:您可能想了解 为什么 您需要改变这个道具,或者考虑使用计算属性。 【参考方案1】:

我会将我的 cmets 总结为一个连贯的答案:您看到的问题是您已经通过将 this.testProperty 声明为道具来定义它:做 testProperty = this.testProperty 充其量是一个循环引用。单独使用@Prop 装饰器将模板中的属性映射到变量。

<script lang="ts">
import  Component, Prop, Vue  from 'vue-property-decorator';

@Component
export default class childComponent extends Vue 
  @Prop(
    
      default: 'notTest',
      validator: (component) => 
        return [
          'notTest',
          'test',
        ].indexOf(component) > -1;
      ,
    ,
  )
  testProperty!: string;

  // Map prop to local data property
  testPropertyLocal = this.testProperty;
</script>

另外,请记住以下警告:VueJS properties must be kebab-case in templates and camelCase in JS。因此,您需要将子组件引用更新为:

<template>
  <childComponent test-property='test' />
</template>

【讨论】:

啊,我很困惑的地方仍然是在 @Component() 装饰器中做数据属性。使用 ts/class 语法解决了这个问题。非常感谢你对我的坚持。

以上是关于如何在 Vue 中以 Typescript 语法定义使用 prop 作为其初始值的本地数据属性?的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 Vue 和 TypeScript 类装饰器语法的外部定义组件

Vue/Typescript/Jest - Jest 单元测试语法错误:意外的令牌导入

为啥我不能在 TypeScript 中以这种方式只读数组?

如何从Typescript中以#或@开头的属性获取JSON数据

TypeScript 导出使用

从 TypeScript 功能的角度来看,Vue.js 3 是不是可以实现基于类的语法?