2016-11-13 3 views
5

ich ein Formular in einem Admin-Bereich haben, wo Benutzer können Text mit Kurzwahlnummern in ihnen:Dynamisch Vue 2-Komponenten von Short injizieren

Wärmeofen bei [temp c = 200]

Was Ich möchte, dass temp shortcode geparst und in eine Vue 2-Komponente umgewandelt wird, wenn sie im Front-End angezeigt wird.

Hier ist eine vereinfachte Temperature.vue Komponente:

<template> 
    <span class="temperature"> 
     {{ celsius }}&deg;C 
    </span> 
</template> 

<script> 
    import { mapGetters, mapActions } from 'vuex' 

    export default { 
     props: ['celsius'], 
     name: 'temperature' 
    } 
</script> 

Und hier ist eine vereinfachte Instructions.vue Komponente, die den Text mit Kurzwahlnummern werden analysieren und Render:

<template> 
    <div v-html="parseShortcodes(text)"></div> 
</template> 

<script> 
    import ShortcodeParser from 'meta-shortcodes' 
    import Temperature from 'Temperature.vue' 

    export default { 

     data:() => { 
      return { 
       text: 'Heat oven at [temp c=200]', 
       parser: ShortcodeParser() 
      } 
     }, 
     components: [ 
      Temperature 
     ], 
     methods: { 
      parseShortcodes(text) { 
       return this.parser.parse(text) 
      } 
     }, 
     created() { 
      this.parser.add('temp', function(options) { 
       return '<temperature :celsius="'+options.c+'"></temperature>' 
      }) 
     } 
    } 
</script> 

Die Analyse funktioniert gut, und die Substitution wird gedruckt im Frontend. Aber das <temperature>-Tag wird wörtlich wiedergegeben und nicht als eine Vue-Komponente, die etwas erwartet wird.

Wärmeofen bei < Temperatur: celsius = „200“> </Temperatur>

Was kann ich nicht meinen Kopf zu wickeln scheinen um das, was Schritt ist ich nehmen soll es tatsächlich zu verwandeln in die Temperature Komponente, die ich definiert habe. Ist es überhaupt möglich? Gibt es mehr orthodoxe Wege, dies zu tun, was mir fehlt?

Es gibt auch die Sicherheitsbedenken v-html der Verwendung des Textes zu machen. Ich möchte nicht unbedingt, dass das da ist, aber ich schätze, es ist noch weit hergeholt, dass die Komponente Temperature aus einer Escapezeichenfolge angezeigt wird. Ich kann immer vor dem Einfügen in die Datenbank bereinigen, aber ich möchte immer noch v-html vermeiden, wenn überhaupt möglich.

Antwort

4

Um Ihr Beispiel zu machen arbeiten Sie die Render-Funktion Ihrer Instructions Komponente verwenden müssen. In der Renderfunktion können Sie eine neue Vue-Komponente erstellen, z. B. "intruction", an die Sie die aus der Kurzwahl extrahierte Zeichenfolge als Vorlage übergeben. In dieser Komponentendeklaration fügen Sie die Temperaturkomponente als untergeordnetes Element hinzu und die gerenderte Prop wird gerendert. Und das ist es. Das Beispiel folgt:

Instructions.vue

<script> 
    import ShortcodeParser from 'meta-shortcodes' 
    import Temperature from 'Temperature.vue' 

    export default { 

     data:() => { 
      return { 
       text: 'Heat oven at [temp c=200]', 
       parser: ShortcodeParser() 
      } 
     }, 
     methods: { 
      parseShortcodes(text) { 
       return this.parser.parse(text) 
      } 
     }, 
     render (createElement) { 

      const template = this.parseShortcodes(this.text) //returns something like this <div class="intruction">'Heat oven at <temperature :celsius="200"></temperature>'</div> 

      var component = Vue.component('instruction', { 
       template: template, 
       components: { 
        'temperature': Temperature 
       } 
      }) 

      return createElement(
       'div', 
       { 
        class: { 
         instructions: true 
        } 
       }, 
       [ 
        createElement(component) 
       ] 
      ) 
     } 
    } 
</script> 
+0

Cool, ich mag diesen Ansatz. Nicht weit von dem, was ich habe, wirklich ... Ich werde es so schnell wie möglich testen und Sie wissen lassen! –

0

Derzeit gibt es keinen Schritt, wo Sie Vorlage kompiliert wird, das ist, warum es als Text wiedergegeben wird. Ich glaube, Sie tun könnten, den Text mit der Komponente ersetzen folgenden

  1. Sobald Sie die Temperatur es in html-Elemente wickeln finden
  2. Erstellen Sie neue Vue Instanz in JavaScript (nicht als HTML-Vorlage in string)
  3. Berg vue Beispiel auf der Oberseite dieses Elements el-Option oder montiert $
  4. verwenden Interpolation statt v-html XSS https://vuejs.org/v2/guide/syntax.html#Text
+0

-Code-weise wie würde das aussehen in dem Beispiel habe ich? –

2

Hier ist mein Ansatz, nicht sicher zu verhindern, wenn es was dies ist Du bist hinterher. Es führt eine Zwischenkomponente ein, um Objekte dynamisch zu rendern. Auch ich modifizierte Instructions.vue ein bisschen für meine Tests können Sie ändern Ihre Short Parser

Instructions.vue

<template> 
    <div> 
    <input type="text" @input="parseInput" /> 
    <DynamicComponent :type="parsedType" :props="parsedProps"></DynamicComponent> 
    </div> 
</template> 

<script> 
import DynamicComponent from './DynamicComponent'; 


export default { 
    components: { 
    DynamicComponent 
    }, 
    data() { 
    return { 
     parsedType: '', 
     parsedProps: '' 
    }; 
    }, 
    methods: { 
    parseInput(e) { // parse the input 
     if (e.target.value === '[temp c=200]') { // change this to use your parser 
     this.parsedType = 'Temperature'; 
     this.parsedProps = { celsius: 200 }; 
     } else { 
     this.parsedType = ''; 
     this.parsedProps = ''; 
     } 
    } 
    } 
}; 
</script> 

Dynamic passen.vue

<script> 
import Temperature from './Temperature'; 
// import all other dynamically rendered components 


export default { 
    components: { 
    // let it know what components are there 
    Temperature 
    }, 
    props: ['type', 'props'], 
    render(h) { 
    return h(this.type, { 
     props: this.props 
    }, this.$slots.default); 
    } 
}; 
</script> 
+0

Ein sehr interessanter Ansatz und sieht ziemlich sauber aus. Ich werde es ausprobieren, sobald ich die Gelegenheit dazu habe und werde zu dir zurückkommen. –