0
votes

here is my code:

<head>
  <meta charset="utf-8">
  <!--mobile friendly-->
  <meta name="viewport" content="width=device-width, user-scalable=yes">
  <script type="text/javascript" src="../../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
  <selection>
    <selection-item></selection-item>
    <selection-item></selection-item>
  </selection>
</div>
<script>
  Vue.component("selection", {
    mounted: function () {
      var c = this.$children
      console.log(c)
    },
    template: `<div></div>`
  })
  new Vue({el: "#app"})
</script>
</body>

the output is Array(0), but in my code, selection has children selection-item, so how to get vue component "selection"'s children "selection-item"

here is my vue version:

roroco@roroco ~/Dropbox/js/ro-js/node_modules/vue $ cat package.json |gr version
  "_nodeVersion": "8.4.0",
  "_npmVersion": "5.4.1",
  "version": "2.4.4"
2

2 Answers

1
votes

I find the solution: i should add <slot></slot> in vue component template, here is work code:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <!--mobile friendly-->
  <meta name="viewport" content="width=device-width, user-scalable=yes">
  <script type="text/javascript" src="../../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
  <selection>
    <selection-item></selection-item>
    <selection-item></selection-item>
  </selection>
</div>
<script>
  Vue.component("selection-item", {
    template: `<div>prpr</div>
  `
  })
  Vue.component("selection", {
    mounted: function () {
      var c = this.$children
      console.log(c)
    },
    template: `<div><slot></slot></div>`
  })
  new Vue({el: "#app"})
</script>
</body>
</html>
0
votes

Based on the docs on $children:

The direct child components of the current instance. Note there’s no order guarantee for $children, and it is not reactive. If you find yourself trying to use $children for data binding, consider using an Array and v-for to generate child components, and use the Array as the source of truth.

Another option is to make use of $slots which holds the direct child components wrapped in VNode interface.

Vue.component("selection", {
  mounted() {
    var children = this.$slots.default;
    
    //console.log(children);
  },
  template: `
    <div>
      <slot></slot>
    </div>`
});

Vue.component("selection-item", {
  template: `<div></div>`
});

new Vue({
  el: "#app"
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <selection>
    <selection-item></selection-item>
    <selection-item></selection-item>
  </selection>
</div>

If you need the children as HTML element, they will be inside this same wrapper, under a property called elm. Also note that despite the singular name, this.$slots.default is actually an array. So something like,

const children = this.$slots.default
  .map(vnode => vnode.elm)
  .filter(el => el.tagName === 'DIV');