Vue 中未调用计算属性集
Posted
技术标签:
【中文标题】Vue 中未调用计算属性集【英文标题】:computed property set not called in Vue 【发布时间】:2020-11-06 14:57:01 【问题描述】:根据文档,只要我定义 get/set 方法,我应该能够在 Vue 中使用计算属性作为 v-model
,但在我的情况下它不起作用:
export default
template: `
<form class="add-upload" @submit.prevent="return false">
<label><input type="checkbox" v-model="options.test" /> test </label>
</form>
`,
computed:
options:
get()
console.log('get');
return test: false;
,
set(value)
console.log('set');
,
,
当我选中/取消选中输入时,显然不会调用 set
。
但是在显示组件的时候会调用get
...
【问题讨论】:
这里option
是被动的,而不是 options.test
这是否意味着我需要使用 get/set 为每个键定义计算属性?那将迫使我编写大量重复的代码。我这里只有test
,但我计划添加更多输入字段..
使用表单提交。因为复选框将单独更新表单值
我不明白?
那么为什么要在 v-model
中使用计算属性呢?定义数据有什么问题?这里的问题是v-model
尝试在options.test
上设置值,但您的计算属性正在options
上设置新值。不确定这是否会自动工作。
【参考方案1】:
代替computed
getter/setter,使用本地数据道具,初始化为目标localStorage
项目;和一个deep watcher(检测任何子属性的更改)在更改时设置localStorage
。这使您仍然可以将v-model
与本地数据属性一起使用,同时观察对象子属性的变化。
步骤:
-
声明一个本地数据属性(名为
options
),初始化为localStorage
的当前值:
export default
data()
return
options:
,
mounted()
const myData = localStorage.getItem('my-data')
this.options = myData ? JSON.parse(myData) :
,
-
在 data 属性 (
options
) 上声明一个监视,将 deep=true
和 handler
设置为将 localStorage
设置为新值的函数:
export default
watch:
options:
deep: true,
handler(options)
localStorage.setItem('my-data', JSON.stringify(options))
,
demo
【讨论】:
【参考方案2】:编辑:看了下你依赖localstorage的cmets,我只能建议你采取Vuex的方式,用一个持久化库来处理localstorage。 (https://www.npmjs.com/package/vuex-persist) 这样,您的本地存储将始终链接到您的应用程序,您不必每次都弄乱 getItem/setItem。
看看你的方法,我认为你有理由使用计算属性而不是数据属性。
出现问题是因为您的计算属性返回了一个在 get
处理程序中没有定义的对象。
无论您尝试什么,都无法在 set
处理程序中操作该对象。
get
和 set
必须链接到一个公共引用。正如许多人所建议的那样,您的应用程序中的数据属性或事实来源(Vuex 实例就是一个很好的例子)。
这样,您的 v-model
将与您的计算属性的 set
处理程序完美配合。
这是一个演示解释的工作小提琴:
使用 Vuex
const store = new Vuex.Store(
state:
// your options object is predefined in the store so Vue knows about its structure already
options:
isChecked: false
,
mutations:
// the mutation handler assigning the new value
setIsCheck(state, payload)
state.options.isChecked = payload;
);
new Vue(
store: store,
el: "#app",
computed:
options:
get()
// Here we return the options object as depicted in your snippet
return this.$store.state.options;
,
set(checked)
// Here we use the checked property returned by the input and we commit a Vuex mutation which will mutate the state
this.$store.commit("setIsCheck", checked);
)
body
background: #20262E;
padding: 20px;
font-family: Helvetica;
#app
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
h2
font-weight: bold;
margin-bottom: 15px;
<div id="app">
<h2>isChecked: options.isChecked </h2>
<input type="checkbox" v-model="options.isChecked" />
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vuex@2.0.0"></script>
带有数据属性
new Vue(
el: "#app",
data:
options:
isChecked: false
,
computed:
computedOptions:
get()
return this.options;
,
set(checked)
this.options.isChecked = checked;
)
body
background: #20262E;
padding: 20px;
font-family: Helvetica;
#app
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
h2
font-weight: bold;
margin-bottom: 15px;
<div id="app">
<h2>isChecked: computedOptions.isChecked </h2>
<input type="checkbox" v-model="computedOptions.isChecked" />
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
恕我直言,您的方法有点特别,但同样,您必须有自己的理由这样做。
【讨论】:
【参考方案3】:看来问题在于options
的存在和getter 的返回值。
你可以试试这个:
let options;
try
options = JSON.parse(localStorage.getItem("options"));
catch(e)
// default values
options = test: true ;
function saveOptions(updates)
localStorage.setItem("options", JSON.stringify( ...options, ...updates ));
export default
template: `
<form class="add-upload" @submit.prevent="return false">
<label><input type="checkbox" v-model="test" /> test </label>
</form>`,
computed:
test:
get()
console.log('get');
return options.test;
,
set(value)
console.log('set', value);
saveOptions( test: value );
,
,
希望这会有所帮助。
【讨论】:
【参考方案4】:这里的代码非常简单的解释。计算属性取决于其他数据/反应变量。如果只有当反应性属性改变了它们的值,并且如果相同的属性用于计算其他一些计算属性,那么计算属性就会变成反应性的。
这样我们必须设置值并在 setter 和 getter 方法中获取。
new Vue(
el: '#app',
data:
message: 'Use computed property on input',
foo:0,
isChecked:true
,
computed:
bar:
get: function()
return this.foo;
,
set: function(val)
this.foo = val;
,
check:
get: function()
return this.isChecked;
,
set: function(val)
this.isChecked = val;
)
<script src="https://unpkg.com/vue"></script>
<div id="app">
<p> message Text</p>
<input type="text" v-model="bar" />
bar
<br/>
<p> message Checkbox</p>
<input type="checkbox" v-model="check" />
check
</div>
【讨论】:
【参考方案5】:我不熟悉是否有可以在这里工作的计算集方法,但还有一些其他方法可以解决这个问题。
如果您想要一个单一的 getter 来改变数据,您可以使用基于事件的方法来设置数据。这个方法是我最喜欢的:
export default
template: `
<form class="add-upload" @submit.prevent="">
<label for="test"> test </label>
options.test
<input id="test" type="checkbox" v-model="options.test" @input="setOptions(test: !options.test)"/>
</form>
`,
data()
return
optionsData:
test: false
,
computed:
options:
get()
return this.optionsData;
,
,
,
methods:
setOptions(options)
this.$set(this, "optionsData", ...this.optionsData, ...options )
如果您在 get/set 中没有真正做任何事情,您可以使用 data 选项
export default
template: `
<form class="add-upload" @submit.prevent="">
<label for="test"> test </label>
options.test
<input id="test" type="checkbox" v-model="options.test" />
</form>
`,
data()
return
options:
test: false
然后还有每个属性的get/set选项
export default
template: `
<form class="add-upload" @submit.prevent="">
<label for="test"> test </label>
test
<input id="test" type="checkbox" v-model="test" />
</form>
`,
data()
return
optionsData:
test: false
,
computed:
test:
get()
return this.optionsData.test;
,
set(value)
this.optionsData.test = value
,
,
【讨论】:
【参考方案6】:Vue 计算属性的返回值不会自动变为响应式。因为您要返回一个普通对象,并且因为您要分配给计算属性内的属性,所以 setter 不会触发。
您有两个问题需要解决,一个问题的解决方案是存储您计算的属性值的反应版本(请参阅Vue.observable()
)。下一个问题有点微妙,我需要知道为什么你想加入二传手。如果没有更多信息,我最好的猜测是您实际上正在寻找执行副作用。在这种情况下,您应该注意更改的值(请参阅vm.$watch()
)。
这是我根据上述假设编写该组件的方式。
export default
template: `
<form class="add-upload" @submit.prevent="return false">
<label><input type="checkbox" v-model="options.test" /> test </label>
</form>
`,
computed:
options(vm)
return (
vm._internalOptions ||
(vm._internalOptions = Vue.observable( test: false ))
)
,
,
watch:
"options.test"(value, previousValue)
console.log("set")
,
,
如果您需要根据options
上的任何变化触发副作用,您可以深入观看。但最大的警告是对象必须是响应式的(由Vue.observable()
解决或在data
选项中定义它)。
export default
watch:
options:
handler(value, previousValue)
console.log("set")
,
deep: true,
,
,
【讨论】:
以上是关于Vue 中未调用计算属性集的主要内容,如果未能解决你的问题,请参考以下文章