最近在群里看到有问到这个问题,然后自己又正好review到这部分的文档,就当作一个需求,做了一番研究,纪录一下。

需求:

将类似<div><span>{{ msg }}</span></div>的字符串直接转换为JSX数据,并挂载到vm中,以减少JS的代码量和复杂度(这应该也是Vue支持JSX的初衷吧)

解决:

文档可以看到,我们并不能直接把字符串变量拿来当JSX语法使用。不过幸运的是Vue提供了一个全局的compile方法,这个方法的作用就是在render函数中编译模板字符串,正如官方的例子:

var res = Vue.compile('<div><span>{{ msg }}</span></div>')
new Vue({
  data: {
        msg: 'hello'
  },
  render: res.render,
  staticRenderFns: res.staticRenderFns
})

我们可以将这段代码封装成一个专门用来解析的组件,就可以在需要时候使用了

const JSX = Vue.component('jsx', {
  render: function (h) {
    return Vue.compile(this.jsx).render.apply(this, arguments)
  },
  props: [
    'jsx'
  ]
})

总结:

如果你不需要解析一些变量,那么上面的代码就足够了。但是像上文所列的需求来看的话,你会发现msg这个变量没能解析出来,因为JSX这个组件里找不到msg变量,所以只能再增加个prop参数。不过这就牵扯出一个问题,有几个变量就要增加几个prop,这个目前误解(谁有好的解决方案,欢迎告知)

完整代码:

const JSX = Vue.component('jsx', {
  render: function (h) {
    return Vue.compile(this.jsx).render.apply(this, arguments)
  },
  props: [
    'jsx',
    'msg'
  ]
})

new Vue({
  el: '#app',
  data () {
    return {
      msg: 'hello',
      jsx: '<div>loading...</div>'
    }
  },
  components: {
    JSX
  },
  template: '<JSX :jsx="jsx" :msg="msg" />',
  created () {
    setTimeout(() => {
      this.jsx = '<div><span>{{msg}}</span></div>'
    }, 1000)
  }
})

在线示例:
https://jsfiddle.net/Hpyer/Lxd8mfmf/ (访问慢的自行翻墙)