TypeScript VueJS:使用具有计算属性的观察器

Posted

技术标签:

【中文标题】TypeScript VueJS:使用具有计算属性的观察器【英文标题】:TypeScript VueJS: Using watcher with computed property 【发布时间】:2021-03-07 08:12:13 【问题描述】:

我正在构建一个自定义组件,它允许我使用任意 <div>s 作为单选按钮。目前我的代码如下所示:

<template>
    <div
        class="radio-div"
        :class="selected ? 'selected' : ''"
        @click="handleClick"
    >
        <slot></slot>
    </div>
</template>

<style lang="scss" scoped>
.radio-div 
    display: inline-block;
    border-radius: 5px;
    border: 1px solid #000;
    padding: 5px;
    margin: 5px;


.radio-div.selected 
    box-shadow: 0 0 10px rgba(255, 255, 0, 0.5);
    border: 2px solid #000;

</style>

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

@Component
export default class RadioDiv extends Vue 
    @Prop()
    val!: string;

    @Prop(
        required: true
    )
    value!: string;

    selected = false;

    mounted() 
        this.selected = this.value === this.val;
    

    @Watch("value")
    onChange() 
        this.selected = this.value === this.val;
    

    handleClick(e: MouseEvent) 
        this.$emit("input", this.val);
    

</script>

为了利用它,我可以将它放在这样的模板中:

<template>
    <div class="q-pa-md">
        <q-card>
            <q-card-section class="bg-secondary">
                <div class="text-h6">Political Affiliation</div>
            </q-card-section>
            <q-separator />
            <q-card-section>
                <radio-div v-model="politicalParty" val="Republican">
                    <div class="text-h6">Republican</div>
                    <p>Wrong answer</p>
                </radio-div>
                <radio-div v-model="politicalParty" val="Democrat">
                    <div class="text-h6">Democrat</div>
                    <p>Wrong answer</p>
                </radio-div>
                <radio-div v-model="politicalParty" val="Independent">
                    <div class="text-h6">Independent</div>
                    <p>These people clearly know what's up</p>
                </radio-div>
            </q-card-section>
        </q-card>
    </div>
</template>

<script lang="ts">
import  Vue, Component, Watch  from "vue-property-decorator";
import RadioDiv from "../components/RadioDiv.vue";

@Component(
    components:  RadioDiv 
)
export default class Profile extends Vue 
    politicalParty = "Independent";

</script>

这按预期工作。我可以点击&lt;div&gt;s,它会切换选择哪一个并适当地更新变量。

但现在我想将它与全局状态管理器联系起来。因此,我有一个 computed 属性,而不是本地 politicalParty 变量:

<script lang="ts">
import  Vue, Component, Watch  from "vue-property-decorator";
import RadioDiv from "../components/RadioDiv.vue";
import globalState from "../globalState";

@Component(
    components:  RadioDiv 
)
export default class Profile extends Vue 
    get politicalParty() 
        return globalState.politicalParty;
    

    set politicalParty(val) 
        globalState.politicalParty = val;
    

</script>

console.log 语句放入设置器中,我可以看到它正在被调用,并且变量正在被更新。但是在我的value 观察程序(在RadioDiv 组件中)中添加console.log 语句表明它现在不再被调用,因为我正在使用计算属性。

既然我正在使用全局状态,那么让我的 RadioDiv 再次响应的秘诀是什么?

更新

这个问题似乎并不特定于我的自定义组件或观察者。我决定忽略这一点,继续等待 *** 的回答,然后再次遇到 Quasar 组件的问题:

<template>
...
            <q-card-section>
                <div class="row">
                    <div class="col">
                        <q-slider v-model="age" :min="0" :max="100" />
                    </div>
                    <div class="col">
                         ageText 
                    </div>
                </div>
            </q-card-section>
...
</template>

<script lang="ts">
...
    get age() 
        return globalState.age;
    

    set age(val) 
        globalState.age = val;
        this.ageText = "You are " + val + " years old";
    
...
</script>

这导致我尝试不使用任何自定义组件:

<template>
...
    <input type="text" v-model="test" />
    <p>Text:  test </p>
...
</template>

<script lang="ts">
let testVal = "";
...
    get test()  return testVal; 
    set test(val)  testVal = val; 
...
</script>

再一次:没有反应。当我使用带有v-model 的计算属性时,调用set 后似乎没有任何变化

【问题讨论】:

【参考方案1】:

如果globalState 只是一个Object,那么它不会是反应式的,所以computed 只会读取它的值一次testVal 也一样,它只是一个 String(本身也不是响应式的)。

要使 test 计算的 prop 响应于 testVal,请使用 Vue.observable() 创建 testVal

const testVal = Vue.observable( x: '' )

@Component
export default class Profile extends Vue 
  get test()  return testVal.x 
  set test(val)  testVal.x = val 

globalState 类似,导出Vue.observable() 将使您的计算道具具有反应性:

// globalState.js
export default Vue.observable(
  politicalParty: ''
)

【讨论】:

以上是关于TypeScript VueJS:使用具有计算属性的观察器的主要内容,如果未能解决你的问题,请参考以下文章

VueJs 使计算属性具有反应性

VueJS + Typescript:类型上不存在属性

使用 typescript 在 vuejs 中声明原型属性

VS Code Typescript 在 Vuejs 项目中给出错误“属性不存在”

vuejs typescript属性路由器不存在

将道具传递给设置时的VueJS 3组合API和TypeScript类型问题:类型上不存在属性“用户”