在计算属性中使用 $refs
Posted
技术标签:
【中文标题】在计算属性中使用 $refs【英文标题】:Using $refs in a computed property 【发布时间】:2017-09-17 19:25:58 【问题描述】:如何在计算内部访问$refs
?第一次运行计算属性时它总是未定义。
【问题讨论】:
是的,它仅在第一个渲染循环完成时定义。对于它的价值,明确建议不要,因为它不是响应式的。 vuejs.org/v2/guide/components.html#Child-Component-Refs你可能需要找到更好的模式... 使用 Watch 功能 内挂载:enter link description here 【参考方案1】:要在这里回答我自己的问题,我在其他任何地方都找不到满意的答案。有时您只需要访问 dom 元素即可进行一些计算。希望这对其他人有帮助。
一旦组件被挂载,我不得不欺骗 Vue 更新计算属性。
Vue.component('my-component',
data()
return
isMounted: false
,
computed:
property()
if(!this.isMounted)
return;
// this.$refs is available
,
mounted()
this.isMounted = true;
)
【讨论】:
有完全相同的要求,这是我找到的唯一可行的解决方案。将类属性绑定到计算属性,如果嵌套组件(ref)设置了一些属性,则必须应用一些类。 @Bondsmith 对不起哈哈,我是提问者和回答者,我想我忘了接受我自己的回答 我没有意识到。真有趣ツ 非常有帮助,感谢@EricGuan 花时间回答您自己的问题以帮助他人 虽然这最初有效,但它不是反应性的,当 refs 更改时,它不会更新,例如,clientWidth 是静态的,就好像它只在挂载时获取初始大小,如果对象更改,它不会更新。【参考方案2】:我认为引用Vue js guide很重要:
$refs 仅在组件被渲染后才被填充,并且它们不是响应式的。它只是作为直接子操作的逃生舱口 - 您应该避免从模板或计算属性中访问 $refs。
因此,这不是你应该做的事情,尽管你总是可以绕过它。
【讨论】:
【参考方案3】:如果您在v-if
之后需要$refs
,您可以使用updated()
挂钩。
<div v-if="myProp"></div>
updated()
if (!this.myProp) return;
/// this.$refs is available
,
【讨论】:
绝招!在computed
的逻辑中加入v-if
条件,以便将它们注册为依赖项。正是对 ref
和 v-if
切换元素的好奇心的答案
或者把访问$refs的代码放到nextTick里面:this.$nextTick(() => this.$refs...)【参考方案4】:
我刚遇到同样的问题,并意识到这是计算属性不起作用的情况。
根据当前文档(https://vuejs.org/v2/guide/computed.html):
"[...]我们可以定义相同的函数作为方法,而不是计算属性。对于最终结果,这两种方法确实完全相同。但是不同的是,计算属性根据它们的反应性依赖项进行缓存。计算属性只会在其某些反应性依赖项发生变化时重新评估"
因此,在这些情况下(可能)发生的情况是,完成组件的挂载生命周期并设置 refs 并不算作对计算属性的依赖项的反应性更改。
例如,在我的例子中,当我的 ref 表中没有选定的行时,我需要禁用一个按钮。 因此,此代码将不起作用:
<button :disabled="!anySelected">Test</button>
computed:
anySelected ()
if (!this.$refs.table) return false
return this.$refs.table.selected.length > 0
您可以做的是将计算属性替换为方法,并且应该可以正常工作:
<button :disabled="!anySelected()">Test</button>
methods:
anySelected ()
if (!this.$refs.table) return false
return this.$refs.table.selected.length > 0
【讨论】:
我认为这种方法是迄今为止最好的方法。它不会将指令扩展到data()
、updated()
和其他部分。干净简洁。
方法不是响应式的,并且不会在 ref 属性更改时更新。【参考方案5】:
对于像我这样只需要将一些数据传递给 prop 的其他用户,我使用 data
而不是 computed
Vue.component('my-component',
data()
return
myProp: null
,
mounted()
this.myProp= 'hello'
//$refs is available
// this.myProp is reactive, bind will work to property
)
【讨论】:
如果您不需要它是被动的,这比接受的答案要好。【参考方案6】:我遇到了类似的情况,我用以下方法解决了它:
data: () =>
return
foo: null,
, // data
然后你观察变量:
watch:
foo: function()
if(this.$refs)
this.myVideo = this.$refs.webcam.$el;
return null;
,
// watch
注意 if
评估 this.$refs
的存在性,当它发生变化时,你会得到你的数据。
【讨论】:
【参考方案7】:如果需要,请使用属性绑定。 :disabled 属性在这种情况下是被动的
<button :disabled="$refs.email ? $refs.email.$v.$invalid : true">Login</button>
但是要检查两个字段,我发现没有其他方法可以作为虚拟方法:
<button :disabled="$refs.password ? checkIsValid($refs.email.$v.$invalid, $refs.password.$v.$invalid) : true">
data.submitButton.value
</button>
methods:
checkIsValid(email, password)
return email || password;
【讨论】:
【参考方案8】:我所做的是将引用存储到数据属性中。然后,我在挂载事件中填充这个数据属性。
data()
return
childComps: [] // reference to child comps
,
methods:
// method to populate the data array
getChildComponent()
var listComps = [];
if (this.$refs && this.$refs.childComps)
this.$refs.childComps.forEach(comp =>
listComps.push(comp);
);
return this.childComps = listComps;
,
mounted()
// Populates only when it is mounted
this.getChildComponent();
,
computed:
propBasedOnComps()
var total = 0;
// reference not to $refs but to data childComps array
this.childComps.forEach(comp =>
total += comp.compPropOrMethod;
);
return total;
【讨论】:
【参考方案9】:另一种方法是完全避免使用 $refs,只订阅来自子组件的事件。
它需要子组件中的显式设置器,但它是响应式的,不依赖于挂载时间。
父组件:
<script>
data()
return
childFoo: null,
</script>
<template>
<div>
<Child @foo="childFoo = $event" />
<!-- reacts to the child foo property -->
childFoo
</div>
</template>
子组件:
data()
const data =
foo: null,
this.$emit('foo', data)
return data
,
emits: ['foo'],
methods:
setFoo(foo)
this.foo = foo
this.$emit('foo', foo)
<!-- template that calls setFoo e.g. on click -->
【讨论】:
这是正确的做法,brb以上是关于在计算属性中使用 $refs的主要内容,如果未能解决你的问题,请参考以下文章
vue composition API - ref变量内的计算属性
Vue 3 - 如何在没有 .value 的情况下使用反应式 ref 和计算?