2017-01-07 3 views
1

Folgendes Problem:So greifen Sie auf den Inhalt des Steckplatzes in einer anderen untergeordneten Komponente zu

Ich habe eine Vue.js-Komponente, die auf dem übergeordneten DOM basiert. Aber in dem Moment, in dem die Requisite passiert ist, ist sie (this.$el) undefiniert, wahrscheinlich weil sie noch nicht gemountet ist.

vue Vorlagendatei sieht Meine Komponente wie folgt aus:

<template> 
    <md-card> 
    <md-card-content> 
     <ol> 
     <li v-for="item in headings(content)"> 
      <a :href="`#${item.id}`">{{ item.name }}</a> 
     </li> 
     </ol> 
    </md-card-content> 
    </md-card> 
</template> 
<script> 
    export default { 
    props: ['content'], 
    methods: { 
     headings(content) { 
     // DOM element is used 
     // At this moment, `content` is undefined 
     }, 
    }, 
    }; 
</script> 

Die Komponente, die oben verwendet dieses Stück Code enthält:

<article-index :content="this.$el"></article-index> 

ich das Warten auf die übergeordneten Komponente gedacht, um mounted, aber auf diese Weise kann ich die Vorlage nicht wie oben beschrieben behalten, weil sie immer versuchen würde, sofort auf die Methode (oder Variable) zuzugreifen.

Wie kann ich das lösen?

Edit:

<template> 
    <div class="content"> 
    <div class="left"><article-index :content="this.$el"></article-index></div> 
    <div class="article"><slot></slot></div> 
    <div class="right"><slot name="aside"></slot></div> 
    </div> 
</template> 

Hier ist die Vorlage der übergeordneten Komponente. Das einzige, was ich wirklich brauche, ist das .article Div oder der Inhalt des Slots.

+0

Warum sind vorbei Sie 'diese $ el' in prop.? – Saurabh

+0

@saurabh Weil ich auf das DOM-Element zugreifen muss, um querySelector auszuführen. Wie würdest du es machen? – 22samuelk

+0

Ich werde versuchen, dort eine Vue-Variable zu übergeben, können Sie auch Ihren HTML-Code des übergeordneten DOMs hinzufügen und darauf hinweisen, auf was genau Sie zugreifen möchten. – Saurabh

Antwort

0

Mit Hilfe von @saurabh konnte ich herausfinden, dass ich auf den Slot zugreifen kann, den ich direkt an das Kind übergebe.

Aber das Kernproblem blieb: Die Komponente wurde in diesem Moment nicht montiert.

Also änderte ich, wie ich auf den übergebenen Slot zugreife.

Anstelle des übergeordneten Elements übergebe ich jetzt den Standard-Slot in der übergeordneten Komponente.

Da die slots Prop ist ein Array von VNode Objekte, kann ich keine DOM-Methoden auf ihnen verwenden. Aber da eine VNode 's elm -Eigenschaft das eigentliche DOM-Element enthält, verwende ich das stattdessen.

Wieder das Problem: Es ist noch nicht montiert.

Deshalb zeigt die v-for jetzt auf die headings Daten, nicht die Methode, die entfernt. Stattdessen habe ich eine mounted() Methode hinzugefügt, die automatisch von Vue aufgerufen wird, wenn die Komponenten gemountet wurden.

Wenn diese Methode aufgerufen wird, wurde der Steckplatz montiert, sodass ich auf ihre elm Eigenschaften zugreifen kann. In meinem Fall gibt es mehrere Standard-Slots, so dass das Array slots mehr als ein Element hat. Um es möglich zu machen, eine spezifische querySelectorAll aufzurufen, habe ich einige funktionale Array Magie hinzugefügt.

Edit: Da es sinnvoller ist, querySelector direkt auf den gerenderten Inhalt zuzugreifen, übergebe ich jetzt das $refs Attribut anstelle von $slots. Obwohl ich nur $refs.article benötige, wenn ich es direkt übergebe, werde ich undefiniert. Durch die Übergabe von this.$refs als Ganzes kann die untergeordnete Komponente auf den Artikel ref zugreifen, auch wenn sie vor der Montage nicht existiert.

Also das ist meine neue Stammkomponente:

<template> 
    <div class="content"> 
    <div class="left"> 
     <article-index :refs="this.$refs"></article-index> 
    </div> 
    <div class="article" ref="article"><slot></slot></div> 
    <div class="right"><slot name="aside"></slot></div> 
    </div> 
</template> 

und das Kind:

<template> 
    <md-card> 
    <md-card-content> 
     <ol> 
     <li v-for="item in headings"> 
      <a @click="scroll(item.id)" :href="hash"> 
      {{ item.name }} 
      </a> 
     </li> 
     </ol> 
    </md-card-content> 
    </md-card> 
</template> 
<script> 
    import dashify from 'dashify'; 

    export default { 
    props: ['refs'], 
    data:() => ({ 
     headings: {}, 
     hash: location.hash, 
    }), 
    methods: { 
     scroll(to) { 
     this.refs.article.querySelector(`#${to}`).scrollIntoView(); 
     }, 
    }, 
    mounted() { 
     const elements = Array.from(this.refs.article.querySelectorAll('h2')); 
     elements.forEach(node => node.id = dashify(node.innerText)); 

     this.headings = elements.map(node => ({ 
     name: node.innerText, 
     id: node.id, 
     })); 
    }, 
    }; 
</script> 
2

Sie können es mit this.$slots erhalten, in der Mount-Funktion der Elternkomponente können Sie auf this.$slots zugreifen und es einer Variablen zuweisen, die an article-index Komponente übergeben werden kann.

folgenden Code druckt die übergebenen Slots:

Vue.component('wrapper', { 
    name: 'Wrapper', 
    template: `<div><slot></slot></div>`, 
    mounted() { 
    this.$slots.default.forEach(vnode => { 
     console.log(vnode) 
    }) 
    } 
}) 

Beispiel Geige here.

+0

Also kann ich Methoden wie querySelector nicht verwenden, oder? – 22samuelk

+0

Sie können auf den HTML-Code von 'vnode' zugreifen, indem Sie' vnode.elm' verwenden. http://jsfiddle.net/mimani/hd1n41he/1/ – Saurabh

+0

'Ulme' ist undefined ... – 22samuelk

Verwandte Themen