6

我在管理区域中有一个表单,用户可以在其中输入带有简码的文本:

在 [temp c=200] 下加热烤箱

我想要的是temp在前端显示时将短代码解析并转换为 Vue 2 组件。

这是一个简化的Temperature.vue组件:

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

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

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

这是一个简化的Instructions.vue组件,它将使用简码解析和呈现文本:

<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>

解析工作正常,替换打印在前端。但是<temperature>标签是按字面意思呈现的,而不是作为一个 Vue 组件,这在某种程度上是意料之中的。

在 <temperature :celsius="200"></temperature> 下加热烤箱

我似乎无法理解的是我应该采取什么步骤才能将其实际转换为Temperature我定义的组件。甚至可能吗?有没有我想念的更正统的方法?

v-html用于呈现文本也存在安全问题。我不一定希望它在那里,但我猜期望Temperature组件从转义字符串中出现更加牵强。我总是可以在插入数据库之前进行清理,但如果可能的话,我仍然想避免v-html

4

3 回答 3

7

为了使您的示例正常工作,您需要使用 Instructions 组件的渲染功能。在渲染函数中,您可以创建一个新的 Vue 组件,比如说“指令”,您可以将短代码解析产生的字符串传递给它以用作模板。在该组件声明中,您将附加 Temperature 组件作为子组件,它将呈现您传递的道具。就是这样。示例如下:

说明.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>
于 2016-11-16T14:08:15.480 回答
2

这是我的方法,不确定它是否是你所追求的。它引入了一个中间组件来动态渲染内容。此外,我修改了 Instructions.vue 以进行测试,您可以修改以适合您的简码解析器

说明.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>

动态组件.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>
于 2016-11-16T04:49:43.137 回答
0

目前没有编译模板的步骤,这就是它呈现为文本的原因。我认为您可以执行以下操作来用组件替换文本

  1. 找到温度后,将其包裹在 html 元素中
  2. 在 JavaScript 中创建新的 Vue 实例(不是字符串中的 html 模板)
  3. 使用 el 选项或 $mount 在该元素的顶部安装 vue 实例
  4. 使用插值代替 v-html 来防止 XSS https://vuejs.org/v2/guide/syntax.html#Text
于 2016-11-13T11:57:31.373 回答