简体   繁体   English

VUE 2+访问子方法

[英]VUE 2+ accessing child methods

I have a situation where in VUE I need to access a child function from within the child as well as from the parent. 我遇到一种情况,在VUE中,我需要从子级以及父级中访问子级功能。 I have a working example, but there must be a better way to access the child function from the parent. 我有一个有效的示例,但是必须有一种更好的方法来从父级访问子级功能。

The example has a couple of event listeners that should expand when clicked or keypressed. 该示例包含几个事件侦听器,在单击或按键时应将其展开。 I want to use the child.do_something method from the parent with the global EventListener . 我想将父级的child.do_something方法与全局EventListener

Is there a better way to use the child than this? 有没有比这更好的方法来使用孩子了?

 // 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> 

You could use a ref and then reference the particular child you need by index. 您可以使用ref,然后通过索引引用所需的特定孩子。 This would allow you to avoid using the internal values. 这样可以避免使用内部值。

<child v-for="(item,index) in keysList" :item="item" :key="item.keyCode" ref="children"></child>

And in keystroke : keystroke

const index = this.keysList.findIndex(k => k.keyCode == evt.keyCode)
this.$refs.children[index].do_something()

Here your code modified. 在这里,您的代码已修改。

 // 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> 

Or a slightly more direct approach using a different ref for each child. 或者,为每个孩子使用不同的引用的更直接的方法。

<child v-for="(item,index) in keysList" :item="item" :key="item.keyCode" :ref="item.keyCode"></child>

And in keystroke : keystroke

this.$refs[evt.keyCode][0].do_something()

The unfortunate part here is that because the ref is set as part of a loop, each ref is an array of one element. 这里不幸的是,因为ref被设置为循环的一部分,所以每个ref都是一个元素的数组。 If I think of a way around that I'll edit it in. 如果我想办法解决该问题,请对其进行编辑。

And here is that working. 这就是工作。

 // 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> 

You can achieve this by adding one more property active to the items in your parent data keysList & update the active property for the matching keystroke . 您可以通过向父数据keys中的项添加另一个active属性来实现此目的,并为匹配的击键更新active属性。 As you are passing the item as prop to your child, you can use the item.active from the props. 将物品作为道具传递给孩子时,可以使用道具中的item.active。 You don't need the isActive data in your child. 您不需要孩子中的isActive数据。

Parent: 家长:

    var parent = new Vue({
  el: '#parent',
  data: {
    keysList: [{
        keyCode: "65",
        kbd: "A",
        active: false
      },
      {
        keyCode: "83",
        kbd: "S",
        active: false
      }
    ],
  },
  components: {
    'child': child,
  },
  methods: {
    keystroke: function(keyCode) {
      this.keysList.forEach(key => {key.active = key.keyCode === keyCode.toString()});
    }
  },
  created: function() {
    window.addEventListener('keydown', (e) => this.keystroke(e.keyCode));
  }
})

<div class="keys" id='parent'>
  <child v-for="(item,index) in keysList" :item="item" :key="item.keyCode" :isActive="item.active"></child>
</div>

Child: 儿童:

    var child = {
  props: ['item'],

  template: `
    <div class="key" :class="{playing: item.active}" v-on:click='do_something'>
      <kbd class="noselect">{{ item.kbd }}</kbd>
    </div>
  `,

  methods: {
    do_something: function(event) {
       // DO OTHER STUFF too
    },
  },
}

This way you are managing the state just at one place and you don't need to access your child from your parent 这样,您就可以在一个地方管理状态,而无需从父母那里访问孩子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM