我尝试在v-for
循环中使用组件,并初始化ref
以便将来从父级访问其中的某些方法。这是我的情况的简化代码:
<template>
<div class="hello">
{{ msg }}
<ul>
<list-item
v-for="item in items"
:key="item.id"
:value="item.text"
:ref="`item${item.id}`"
/>
</ul>
</div>
</template>
<script>
import ListItem from "./ListItem";
export default {
name: "HelloWorld",
components: {
ListItem
},
data() {
return {
msg: "Welcome to Your Vue.js App",
items: [
{ id: 1, text: "foo" },
{ id: 2, text: "bar" },
{ id: 3, text: "baz" },
{ id: 4, text: "foobar" }
]
};
},
mounted() {
setTimeout(() => this.$refs.item2.highlight(), 1500);
}
};
</script>
还有ListItem
组件:
<template>
<li v-bind:class="{ highlight: isHighlighted }">
{{value}}
</li>
</template>
<script>
export default {
name: "list-item",
props: ["value"],
data() {
return {
isHighlighted: false
};
},
methods: {
highlight() {
this.isHighlighted = !this.isHighlighted;
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.highlight {
color: red;
}
</style>
它只是呈现一些列表项,并在半秒后突出显示其中一个。但是我遇到了一个错误:Uncaught TypeError: _this.$refs.item2.highlight is not a function
在调试会话之后,我发现了一个有趣的事实:v-for
循环中定义的引用不是组件,而是具有一个组件的数组。
逻辑是什么,f包装器是什么?有人遇到这种情况吗?有人可以解释这种行为吗?
上面提供的代码可以与setTimeout(() => this.$refs.item2[0].highlight(), 1500);
配合使用
我是否必须始终通过[0]
?有没有更好的方法?请帮助。
答案 0 :(得分:5)
我试图通过传递方法中的索引来处理v-for内部的引用:
<div v-for="(item, index) in items" @click="toggle(index)">
<p ref="someRef"></p>
</div>
toggle(index) {
this.refs['someRef'][index].toggle();
}
但是实际上,由于ref的索引未排序,因此切换了错误的元素。
所以我所做的是将数据属性添加到ref元素:
<div v-for="(item, index) in items" @click="toggle(index)">
<p ref="someRef" :data-key="index"></p>
</div>
现在每个引用都有其特定的数据键。可以这样切换:
toggle(index) {
const dropdown = this.$refs['someRef'].find(
el => el.$attrs['data-key'] === index
);
dropdown.toggle();
}
答案 1 :(得分:4)
对于 Vue 3 用户:
在 Vue 3 中,此类用法将不再自动在 $refs
中创建数组。要从单个绑定中检索多个引用,请将 ref
绑定到提供更多灵活性的函数(这是一项新功能):
HTML
<div v-for="item in list" :ref="setItemRef"></div>
使用选项 API:
export default {
data() {
return {
itemRefs: []
}
},
methods: {
setItemRef(el) {
if (el) {
this.itemRefs.push(el)
}
}
},
beforeUpdate() {
this.itemRefs = []
},
updated() {
console.log(this.itemRefs)
}
}
使用合成 API:
import { onBeforeUpdate, onUpdated } from 'vue'
export default {
setup() {
let itemRefs = []
const setItemRef = el => {
if (el) {
itemRefs.push(el)
}
}
onBeforeUpdate(() => {
itemRefs = []
})
onUpdated(() => {
console.log(itemRefs)
})
return {
setItemRef
}
}
}
答案 2 :(得分:1)
我也遇到过同样的问题。
如sobolevon所述,$refs.{ref name}
的返回值是v-for refs中的数组,因此我的解决方案是将$refs.{ref name}
视为默认情况下仅包含一项的数组,并写入{{ 1}}。
它适用于我的情况。
答案 3 :(得分:1)
我通过使用动态引用解决了排序问题::ref="'myRef' + index"
。
如果这样做,Vue 会为 v-for 中的每个项目创建一个新数组,其中唯一的元素将始终是您想要的 ref。然后您可以使用 this.$refs['myRef' + index][0]
访问它。
(这在 Vue 3 中不起作用。)
答案 4 :(得分:0)
考虑您的主要问题:https://vuejs.org/v2/api/#ref
文档说:
将ref与v-for一起使用时,获得的ref将是一个数组,其中包含镜像数据源的子组件。
但是,我会说您做错了,因为使用refs
并不是一个好方法。在vue
地区,我们有非常有用的替代方法。例如,可以使用prop
。
这就是您的代码的重写版本:
<template>
<div class="hello">
{{ msg }}
<ul>
<list-item
v-for="item in items"
:key="item.id"
:value="item.text"
:isHighlighed="item.isHighlighed"
/>
</ul>
</div>
</template>
<script>
import ListItem from "./ListItem";
export default {
name: "HelloWorld",
components: {
ListItem
},
data() {
return {
msg: "Welcome to Your Vue.js App",
items: [
// We have moved `isHighlighed` falg into the data array:
{ id: 1, text: "foo", isHighlighed: false },
{ id: 2, text: "bar", isHighlighed: true },
{ id: 3, text: "baz", isHighlighed: false },
{ id: 4, text: "foobar", isHighlighed: false }
]
};
};
};
</script>
然后更改您的组件定义以接收新的prop
:
<script>
export default {
name: "list-item",
props: ["value", "isHighlighted"]
};
</script>
这将解决您的问题。
答案 5 :(得分:0)
在v-for中使用引用时,组件/ DOM节点直接作为数组存储在变量名中,因此您无需在引用名中使用索引号。因此,您可以这样做:
<list-item
v-for="item in items"
:key="item.id"
:value="item.text"
ref="items"
/>
并像这样使用组件中的引用:
this.$refs.items[index]
还请注意,引用可能不正确,需要以不同的方式处理,这是完全不同的问题。您可以在此处进行以下操作:https://github.com/vuejs/vue/issues/4952
答案 6 :(得分:0)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.21/vue.js"></script>
<div
v-for="(item,index) in items"
:key="index">
<q-popup-proxy
ref="qDateProxy">
<q-date
:data-key="index"
v-model="item.date"
@input="CalendarHide(index)"
mask="MM/DD/YYYY"
range>
</q-date>
</q-popup-proxy>
</div>
<script>
CalendarHide (Val) {
this.$refs ['qDateProxy'] [val].hide()
}
</script>