VueJs Tree recursive elements emits to parent

我与影子孤独终老i 提交于 2020-05-13 11:40:06

问题


How do you emit event inside recursive child components vuejs

Taking the tree example from vue site https://vuejs.org/v2/examples/tree-view.html

How would you transmit on click to the parent each clicked elements id?


回答1:


In the case of recursive elements, you can create an event bus in the parent, pass it to the children as a prop, and have each prop pass it to any children they generate.

Each child emits events on the bus, and the parent handles them. I copied the tree-view exercise you linked and added the bus functionality.

// demo data
var data = {
  name: 'My Tree',
  children: [{
      name: 'hello'
    },
    {
      name: 'wat'
    },
    {
      name: 'child folder',
      children: [{
          name: 'child folder',
          children: [{
              name: 'hello'
            },
            {
              name: 'wat'
            }
          ]
        },
        {
          name: 'hello'
        },
        {
          name: 'wat'
        },
        {
          name: 'child folder',
          children: [{
              name: 'hello'
            },
            {
              name: 'wat'
            }
          ]
        }
      ]
    }
  ]
};

var itemId = 0;

// define the item component
Vue.component('item', {
  template: '#item-template',
  props: {
    model: Object,
    bus: Object
  },
  data: function() {
    return {
      open: false,
      id: ++itemId
    }
  },
  computed: {
    isFolder: function() {
      return this.model.children &&
        this.model.children.length
    }
  },
  methods: {
    toggle: function() {
      if (this.isFolder) {
        this.open = !this.open;
        this.bus.$emit('toggled', this.id);
      }
    },
    changeType: function() {
      if (!this.isFolder) {
        Vue.set(this.model, 'children', [])
        this.addChild()
        this.open = true
      }
    },
    addChild: function() {
      this.model.children.push({
        name: 'new stuff'
      })
    }
  }
})

// boot up the demo
var demo = new Vue({
  el: '#demo',
  data: {
    treeData: data,
    bus: new Vue()
  },
  created() {
    this.bus.$on('toggled', (who) => {
      console.log("Toggled", who);
    });
  }
})
body {
  font-family: Menlo, Consolas, monospace;
  color: #444;
}

.item {
  cursor: pointer;
}

.bold {
  font-weight: bold;
}

ul {
  padding-left: 1em;
  line-height: 1.5em;
  list-style-type: dot;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<!-- item template -->
<script type="text/x-template" id="item-template">
  <li>
    <div :class="{bold: isFolder}" @click="toggle" @dblclick="changeType">
      {{model.name}}
      <span v-if="isFolder">[{{open ? '-' : '+'}}]</span>
    </div>
    <ul v-show="open" v-if="isFolder">
      <item class="item" :bus="bus" v-for="model in model.children" :model="model">
      </item>
      <li class="add" @click="addChild">+</li>
    </ul>
  </li>
</script>

<p>(You can double click on an item to turn it into a folder.)</p>

<!-- the demo root element -->
<ul id="demo">
  <item class="item" :bus="bus" :model="treeData">
  </item>
</ul>



回答2:


Here's another solution if you don't want to create multiple Vue instances. I use this in my single file recursive components.

It uses the v-on directive (I'm using the @ shorthand).

In your recursive component <template>:

<YourComponent @bus="bus"></YourComponent>

In the recursive component methods:

methods: {
    bus: function (data) {
        this.$emit('bus', data)
    }
}

To kick it off, you emit an event in a child:

this.$emit('bus', {data1: 'somedata', data2: 'somedata'})

That data will be transmitted all the way up the chain, and then you receive that event in the page that called your recursive component:

methods: {
    bus (data) {
        // do something with the data
    }
}

Here's a fiddle showing it in action on the Vue.JS tree example. Right-click on an element, and it will output that model in the console:

https://jsfiddle.net/AlanGrainger/r6kxxoa0/




回答3:


Use v-on="$listeners"

I'll let you into a little secret. The Vue $listeners property (which is documented as being there to pass events down to children), also passes child events to parents!

https://vuejs.org/v2/guide/components-custom-events.html#Binding-Native-Events-to-Components

Here is a pseudo-code example (shorthand for illustrative purposes):

<ancestor-component @messageForAncestor="displayMessage">
  ...
  <parent-component v-on="$listeners">
    ...
    <child-component @click="$emit('messageForAncestor')">

In the display above the child component would pass up an event. The parent would typically be able to listen for the messageForAncestor event and that's where it would need to stop, but. Putting v-on="$listeners" on the parent actually says please pass it on.

Warn: That was probably a bad idea

This is probably a very bad idea though. A better idea would be to simply ask the middle component (the parent) to pass it on...

<!-- better idea (listen for message and pass on message) --> 
<parent-component @message="$emit('message', $event)">



来源:https://stackoverflow.com/questions/46220213/vuejs-tree-recursive-elements-emits-to-parent

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!