Vue - 从字符串中渲染元素

时间:2018-05-29 07:46:34

标签: vue.js vuejs2 vue-component

我想从我的数据库中的字符串创建一个vue元素。

在这种情况下,它应该是带有笑脸表情符号的消息。 我实际上将它保存为:Some text with Emoji: :santa::skin-tone-3:,并替换&#39; ::&#39;之间的所有有效字符串。使用<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>

但不是渲染的元素应该是这样的:

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

我只得到:

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

将此元素渲染为最佳可能性的最佳方式是什么?

4 个答案:

答案 0 :(得分:2)

我现在想到的是:

convertedMessage(){
    let el = Vue.compile("<Emoji emoji=':santa::skin-tone-3:' :size='16' />")
    el = new Vue({
        components: {
            Emoji
        },
        render: el.render,
        staticRenderFns: el.staticRenderFns
    }).$mount()
    return "Some text with Emoji: "+el.$el.innerHTML
}

也许还有更好的解决方案来解决这个问题?

答案 1 :(得分:1)

有些简单的方法可以完成您通常想要做的事情。如果您提供更多细节,则正确的方向可能是这些解决方案之一之前的策略模式,但是您可能想要以下解决方案之一:

1)Vue使您可以立即定义动态组件,因此这一行:

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

...将在这样的对象数组中绘制一堆组件(例如):{name:'myComponentName',props:{foo:1,bar:'baz'}}。

2)Vue允许您通过简单地添加v-html =“ variable”

将HTML注入组件中

例如,这是一个创建动态SVG图标的组件,其中SVG的内容是从JavaScript变量中动态注入的...

<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允许您通过this。$ options.template动态定义组件模板:

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

4)Vue允许您定义渲染功能,因此代理组件或其他高级技巧并不重要:

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
    });
  }
});

一个聪明的天才为此在这里写了一个jsbin:http://jsbin.com/fifatod/5/edit?html,js,output

5)Vue允许您使用Vue.extend创建组件,甚至将原始JavaScript对象传递到页面或应用程序组件部分,例如这样,它从模板的简单字符串和道具数组,您还可以单独使用JS对象以相同的方式扩展数据,创建对象等。

new Vue({
  el: '#app',
  data: {
    foo: 'bar',
    props: {a: 'a', b: 'b'}
  },
  components: {
    foo: {
      template: '<p>{{ a }} {{ b }}</p>',
      props: ['a', 'b']
    }
  }
})

答案 2 :(得分:1)

当我需要做类似的事情时,这就是我要做的事情。

我正常渲染了该组件,例如<my-component>,但是由于我只需要渲染HTML,因此将其包裹在<div class="hidden">中,如下所示:

<div class="hidden">
   <my-component />
</div>

使用CSS:

.hidden {
  display: none;
}

这样,我可以通过$refs引用该元素,或者可以使用document.querySelector()从DOM中获取该元素,同时使最终用户看不到它。

因此,在上面的示例中,要获取呈现的HTML,只需执行以下操作:

let el = document.querySelector('.hidden');
let renderedHTMLString = el.children[0].outerHTML;

这样,您将获得呈现的HTML,而没有与Vue.compile或任何其他插件相关的任何间接费用。 正常渲染。把它藏起来。进入外部HTML。

答案 3 :(得分:0)

v-html仅呈现纯HTML,请参阅https://vuejs.org/v2/guide/syntax.html#Raw-HTML

在你的情况下,你应该看一下渲染函数和JSX。我不是专家,但似乎有些人正在用dangerouslySetInnerHTML JSX功能实现你想要的东西。看一下这个主题:How do I convert a string to jsx?

我知道有时我们别无选择,但如果你能做到最好,我认为最好的办法是避免从后端生成模板,因为它会破坏关注点(也可能是安全问题)。