How to replace a string with a component (vue)

2019-07-29 04:29发布

问题:

I have strings that contains ### and I am replacing with array values. Now I want to use them with a component, I created the component and it works but I don't know how to use it in the strings. I don't want to wrap them manually because I don't know how the strings will be, it can have several ###. If it has 2 ###, options will have 2 subArrays.

What is the better way to do it?

Code: https://jsfiddle.net/tsobh4nu/

Vue.component('opt', {
  template: `<label>
                <span class="bold" v-for="(str,idx) in options">
                     {{str + " / "}}
                </span>
             </label>`,
  props:{options: Array}
})

new Vue({
  el: '#app',
  data: {
    str: "I have ### and you have a ###.",
      options: [
        ['AAA', 'BBB', 'CCC'],
        ['XXX', 'YYY', 'ZZZ']
      ]
  },
  computed:{
  	replacedStr(){
    	let newStr = this.str;
      this.options.forEach(option=>{
      	newStr = newStr.replace('###',this.concatenateOptions(option));
      })
      return newStr;
    }
  },
  methods: {
    concatenateOptions(strArr) {
      let separator = "";
      let strOptions = "";
      strArr.forEach(word => {
        strOptions += separator  + word;
        separator = " / ";
      });
      return strOptions;
    }
  }
})
.bold {
  font-weight: bold
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
  <p>I want something like this, but using components: </p>
  {{replacedStr}}
  <br>
  <hr>
  My Components:<br>
  <opt :options="options[0]"></opt>
  <br>
  <opt :options="options[1]"></opt>
</div>

Many thanks.

回答1:

You need to move up the food chain ! You're going to lengths to bypass the goodness of vue. Your data.string is a template, and your ### is a not very meaningful placeholder, and then you have to do the work yourself.

Can't you use Vue's templating system? And your concatenateOptions method can be replaced with Array.join().



回答2:

This is more general, but I hope it will help someone. Add a dynamic component in your template: <component v-bind:is="processedHtml"></component>.

Then add a computed method:

computed: {
    processedHtml () {
        let html = this.html.replace('[Placeholder]', '<my-component></my-component>');
        return {
            template: '<div>' + html + '</div>'
        }
     }
}

Where <my-component> is your custom component and the this.html is your HTML content that contains the placeholder [Placeholder].

It is important to return an element that has one root node. That's why the return is wrapped with <div>.

Read more advanced tutorial about this issue here in my blog. For example, to pass props to <my-component>