Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue - Render an element out of string

I would like to create a vue element from a string from my database.

In this case, it should be a message with a smiley emoji. I actually save it like: Some text with Emoji: :santa::skin-tone-3:, and replace all valid string between '::' with the <Emoji emoji=':santa::skin-tone-3:' :size='16' />

<template>
  <span class=message v-html=convertedMessage></div>
</template>

<script>
  import { Emoji } from 'emoji-mart-vue'

  export default {
    components: {
      Emoji
    },
    computed:{
      convertedMessage(){
        return "Some text with Emoji: "+"<Emoji emoji=':santa::skin-tone-3:' :size='16' />"
      }
    }
  }
</script>

But instead of the rendered element which should be something like:

<span data-v-7f853594="" style="display: inline-block; width: 32px; height: 32px; background-image: url(&quot;https://unpkg.com/[email protected]/img/apple/sheets/64.png&quot;); background-size: 5200%; background-position: 15.6863% 41.1765%;"></span>

I only get:

<emoji emoji=":santa::skin-tone-3:" :size="16"></emoji>

What is the best possibility to render this Element like intended?

like image 704
Jakob Graf Avatar asked May 29 '18 07:05

Jakob Graf


1 Answers

Here are some much easier ways to do what you generally want. If you give more specifics, your right direction may be a strategy pattern before one of these solutions, but one of these solutions is probably what you want:

1) Vue lets you dynamically define components right out of the box, so this single line:

<component v-for="(component, index) in components" :key="'component'+index" :is="component.name" v-bind="component.props" />

...would draw a bunch of components in an array of objects like this (for example): {name: 'myComponentName', props: {foo: 1, bar: 'baz'}}.

2) Vue lets you inject HTML into components by simply adding v-html="variable"

For example, here is a component that creates dynamic SVG icons, where the contents of the SVG is dynamically injected from JavaScript variables...

<template>
  <svg xmlns="http://www.w3.org/2000/svg"
    :width="width"
    :height="height"
    viewBox="0 0 18 18"
    :aria-labelledby="name"
    role="presentation"
  >
    <title :id="name" lang="en">{{name}} icon</title>
    <g :fill="color" v-html="path">
    </g>
  </svg>
</template>

<script>
import icons from '../common/icons'
export default {
  props: {
    name: {
      type: String,
      default: 'box'
    },
    width: {
      type: [Number, String],
      default: 18
    },
    height: {
      type: [Number, String],
      default: 18
    },
    color: {
      type: String,
      default: 'currentColor'
    }
  },
  data () {
    return {
      path: icons[this.name]
    }
  },
  created () {
    console.log(icons)
  }
}
</script>

<style scoped>
  svg {
    display: inline-block;
    vertical-align: baseline;
    margin-bottom: -2px;
  }
</style>

3) Vue lets you dynamically define your component template through this.$options.template:

export default {
  props: ['name', 'props'],
  template:  '',
  created(){
    this.$options.template = `<component :is="name" ${props.join(' ')} ></component>`
  },
}

4) Vue lets you define a render function, so proxy components or other advanced shenanigans are trivial:

Vue.component('component-proxy', {
  props: {
    name: {
      type: String,
      required: true
    },
    props: {
      type: Object,
      default: () => {}
    }
  },
  render(h) {
    // Note the h function can render anything, like h('div') works too.
    // the JS object that follows can contain anything like on, class, or more elements
    return h(this.name, {
      attrs: this.props
    });
  }
});

A smart genius wrote a jsbin for this here: http://jsbin.com/fifatod/5/edit?html,js,output

5) Vue allows you to create components with Vue.extend or even passing in raw JavaScript objects into a page or apps components section, like this, which creates a component named "foo" from a simple string for the template and an array for props, you could also extend the data, created, on, etc. the same way using the JS object alone:

new Vue({
  el: '#app',
  data: {
    foo: 'bar',
    props: {a: 'a', b: 'b'}
  },
  components: {
    foo: {
      template: '<p>{{ a }} {{ b }}</p>',
      props: ['a', 'b']
    }
  }
})
like image 61
Nick Steele Avatar answered Oct 12 '22 20:10

Nick Steele