[英]TypeScript VueJS: Using watcher with computed property
I'm building a custom component that will allow me to use arbitrary <div>
s as radio buttons.我正在构建一个自定义组件,它允许我使用任意
<div>
作为单选按钮。 Currently my code looks like so:目前我的代码如下所示:
<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>
To utilize this I can put it in a template like so:为了利用它,我可以把它放在一个模板中,如下所示:
<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>
This works as expected.这按预期工作。 I can click on the
<div>
s and it switches which one is selected and updates the variable appropriately.我可以单击
<div>
并切换选择哪一个并适当地更新变量。
But now I want to tie this into a global state manager.但现在我想将它与全局状态管理器联系起来。 So instead of a local
politicalParty
variable, I have a computed property like so:因此,我有一个计算属性,而不是本地
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>
Putting a console.log
statement in the setter I can see that it is getting called, and the variable is being updated.在 setter 中放置一个
console.log
语句,我可以看到它正在被调用,并且变量正在被更新。 But putting a console.log
statement in my value
watcher (in the RadioDiv
component) shows it's no longer being called now that I'm using computed properties.但是在我的
value
观察器(在RadioDiv
组件中)中放置一个console.log
语句表明它现在不再被调用,因为我正在使用计算属性。
What's the secret to get my RadioDiv
reactive again, now that I'm using global state?既然我正在使用全局状态,那么让我的
RadioDiv
再次响应的秘诀是什么?
The issue doesn't seem to be specific to my custom components, or to watchers.这个问题似乎并不特定于我的自定义组件或观察者。 I decided to ignore this and move on while waiting for an answer from StackOverflow and ran into the issue again with Quasar's components:
我决定忽略这一点,继续等待 StackOverflow 的回答,然后再次使用 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>
This led me to try using no custom components whatsoever:这导致我尝试不使用任何自定义组件:
<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>
Once again: No reactivity.再一次:没有反应。 When I use a computed property with
v-model
nothing seems to change after the call to set
当我将计算属性与
v-model
一起使用时,调用set
后似乎没有任何变化
If globalState
were just an Object
, then it would not be reactive, so computed
is only going to read its value once .如果
globalState
只是一个Object
,那么它不会是响应式的,因此computed
只会读取一次它的值。 Same for testVal
, which is just a String
(also not reactive itself). testVal
也一样,它只是一个String
(本身也不是反应式的)。
To make the test
computed prop reactive to testVal
, create testVal
with Vue.observable()
:要使
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 }
}
Similarly for globalState
, exporting a Vue.observable()
would allow your computed props to be reactive:与
globalState
类似,导出Vue.observable()
将使您的计算道具具有反应性:
// globalState.js
export default Vue.observable({
politicalParty: ''
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.