javascript - VUE 2+ 访问子方法
问题描述
我有一种情况,在 VUE 中,我需要从子内部以及父级访问子函数。我有一个工作示例,但必须有更好的方法从父级访问子函数。
该示例有几个事件侦听器,在单击或按键时应该展开。我想将child.do_something
父级的方法与全局EventListener
.
还有比这更好的使用孩子的方法吗?
// CHILD is a component that needs access to its own click method
var child = {
props: ['item'],
data: function() {
return {
isActive: false
}
},
template: `
<div class="key" :class="{playing: isActive}" v-on:click='do_something'>
<kbd class="noselect">{{ item.kbd }}</kbd>
</div>
`,
methods: {
do_something: function(event) {
this.isActive = !this.isActive
// DO OTHER STUFF too
},
},
}
//PARENT also need to access do_something for the right object when a key is pressed
var parent = new Vue({
el: '#parent',
data: {
keysList: [{
keyCode: "65",
kbd: "A"
},
{
keyCode: "83",
kbd: "S"
},
],
},
components: {
'child': child,
},
methods: {
keystroke: function(keyCode) {
//FIND THE CHILD AND EXECUTE...THIS IS THE TERRIBLE PART
const child = this.$children.find(child => {
return child.$vnode.data.key === keyCode.toString()
});
child.do_something()
}
},
created: function() {
window.addEventListener('keydown', (e) => this.keystroke(e.keyCode));
}
})
.keys {
display: flex;
flex: 1;
min-height: 100vh;
align-items: center;
justify-content: center;
}
.key {
margin: 1rem;
transition: all .07s ease;
color: white;
background: rgba(0, 0, 0, 0.77);
}
.playing {
transform: scale(1.1);
border-color: #ffc600;
box-shadow: 0 0 1rem #ffc600;
}
kbd {
display: block;
font-size: 4rem;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div class="keys" id='parent'>
<child v-for="(item,index) in keysList" :item="item" :key="item.keyCode"></child>
</div>
解决方案
您可以使用 ref,然后通过索引引用您需要的特定子项。这将允许您避免使用内部值。
<child v-for="(item,index) in keysList" :item="item" :key="item.keyCode" ref="children"></child>
并在keystroke
:
const index = this.keysList.findIndex(k => k.keyCode == evt.keyCode)
this.$refs.children[index].do_something()
在这里您的代码已修改。
// CHILD is a component that needs access to its own click method
var child = {
props: ['item'],
data: function() {
return {
isActive: false
}
},
template: `
<div class="key" :class="{playing: isActive}" v-on:click='do_something'>
<kbd class="noselect">{{ item.kbd }}</kbd>
</div>
`,
methods: {
do_something: function(event) {
this.isActive = !this.isActive
// DO OTHER STUFF too
},
},
}
//PARENT also need to access do_something for the right object when a key is pressed
var parent = new Vue({
el: '#parent',
data: {
keysList: [{
keyCode: "65",
kbd: "A"
},
{
keyCode: "83",
kbd: "S"
},
],
},
components: {
'child': child,
},
methods: {
keystroke: function(evt) {
const index = this.keysList.findIndex(k => k.keyCode == evt.keyCode)
this.$refs.children[index].do_something()
}
},
created: function() {
window.addEventListener('keydown', this.keystroke);
}
})
.keys {
display: flex;
flex: 1;
min-height: 100vh;
align-items: center;
justify-content: center;
}
.key {
margin: 1rem;
transition: all .07s ease;
color: white;
background: rgba(0, 0, 0, 0.77);
}
.playing {
transform: scale(1.1);
border-color: #ffc600;
box-shadow: 0 0 1rem #ffc600;
}
kbd {
display: block;
font-size: 4rem;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div class="keys" id='parent'>
<child v-for="(item,index) in keysList" :item="item" :key="item.keyCode" ref="children"></child>
</div>
或者更直接的方法,为每个孩子使用不同的参考。
<child v-for="(item,index) in keysList" :item="item" :key="item.keyCode" :ref="item.keyCode"></child>
并在keystroke
:
this.$refs[evt.keyCode][0].do_something()
这里不幸的是,因为 ref 被设置为循环的一部分,所以每个 ref 都是一个元素的数组。如果我想办法解决这个问题,我会编辑它。
这就是工作。
// CHILD is a component that needs access to its own click method
var child = {
props: ['item'],
data: function() {
return {
isActive: false
}
},
template: `
<div class="key" :class="{playing: isActive}" v-on:click='do_something'>
<kbd class="noselect">{{ item.kbd }}</kbd>
</div>
`,
methods: {
do_something: function(event) {
this.isActive = !this.isActive
// DO OTHER STUFF too
},
},
}
//PARENT also need to access do_something for the right object when a key is pressed
var parent = new Vue({
el: '#parent',
data: {
keysList: [{
keyCode: "65",
kbd: "A"
},
{
keyCode: "83",
kbd: "S"
},
],
},
components: {
'child': child,
},
methods: {
keystroke: function(evt) {
this.$refs[evt.keyCode][0].do_something()
}
},
created: function() {
window.addEventListener('keydown', this.keystroke);
},
})
.keys {
display: flex;
flex: 1;
min-height: 100vh;
align-items: center;
justify-content: center;
}
.key {
margin: 1rem;
transition: all .07s ease;
color: white;
background: rgba(0, 0, 0, 0.77);
}
.playing {
transform: scale(1.1);
border-color: #ffc600;
box-shadow: 0 0 1rem #ffc600;
}
kbd {
display: block;
font-size: 4rem;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div class="keys" id='parent'>
<child v-for="(item,index) in keysList" :item="item" :key="item.keyCode" :ref="item.keyCode"></child>
</div>
推荐阅读
- php - 查找并提取然后替换每个文件中的每一行
- android - Android Emoji App Compat Text View 不呈现某些表情符号,例如
- excel - 将excel工作表插入excel文件的Powershell代码
- java - JavaFX 警报对话框
- r - 样本的历史 - 在 R 中更改限制 x、y
- r - 根据条件向数据框添加列
- blazor - 如何处理托管它的组件/页面中的 Blazor 子组件中引发的异常?
- c# - DDD 删除聚合的最佳解决方案
- python - 使用 pyMongo 和 MongoEngine 从 MongoDb 列表中删除对象及其索引?
- java - 多个 MQTT 客户端订阅同一个主题