提问:如何在vue运行时把SFC Descriptor或者Vue SFC字符串转成vue组件并挂载或渲染出来?

新手上路,请多包涵

最近在做一个项目,需要通过拖拽等一系列操作生成一个页面,这个页面是用代码拼出来的一段vue代码,想把它存到后端,所有的页面组在一起做成独立系统,现在的问题在于如何把vue代码从后端拿过来并转成组件后渲染出来?通过调用vue3packages里的@vue/compiler-sfc可以把vue字符串转成SFC Descriptor,但怎么最后解析成页面或者vue组件呢?[基于vue2或vue3的解决办法都可以]

const str = `
<template>
  <h1>……</h1>
  …………
</template>
<script>
  @import ……
  export default {}
</script>
<style lang="less" scoped>
  h1 {}
</style>`

如上,这是一段简单的vue sfc的字符串,通过parse方法解析后的结果是
image.png

问题在于怎么样把它或者说换一种方式把sfc字符串转成vue组件?
【不能用iframe+html,尽可能地就用vue组件的形式,因为要和全局样式挂钩】

阅读 4.6k
4 个回答

根据你的题意,我想你需要看下这个API用法vue.compile。以下是一个demo:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>demo</title>
  <link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.14.1/theme-chalk/index.min.css" rel="stylesheet">
  <style>
    .import-popover-box p {
      overflow-y: auto;
      white-space: normal;
      word-break: break-all;
      width: 100%;
      height: 350px;
      overflow-x: hidden;
    }
  </style>
</head>

<body>
  <div id="app"></div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.14.1/index.js"></script>
  <script>
    let msg = `数据校验错误,行号:2,3,5,6,7,9,10,11,13,14,15,17,18,19,21,22,23,25,26,27,29,30,31,33,34,35,37,38,39,41,42,43,45,46,47,49,50,51,53,54,55,57,58,59,61,62,63,65,66,67,69,70,71,73,74,75,77,78,79,81,82,83,85,86,87,89,90,91,93,94,95,97,98,99,101,102,103,105,106,107,109,110,111,113,114,115,117,118,119,121,122,123,125,126,127,129,130,131,133,134,135,137,138,139,141,142,143,145,146,147,149,150,151,153,154,155,157,158,159,161,162,163,165,166,167,169,170,171,173,174,175,177,178,179,181,182,183,185,186,187,189,190,191,193,194,195,197,198,199,201,202,203,205,206,207,209,210,211,213,214,215,217,218,219,221,222,223,225,226,227,229,230,231,233,234,235,237,238,239,241,242,243,245,246,247,249,250,251,253,254,255,257,258,259,261,262,263,265,266,267,269,270,271,273,274,275,277,278,279,281,282,283,285,286,287,289,290,291,293,294,295,297,298,299,301,302,303,305,306,307,309,310,311,313,314,315,317,318,319,321,322,323,325,326,327,329,330,331,333,334,335,337,338,339,341,342,343,345,346,347,349,350,351,353,354,355,357,358,359,361,362,363,365,366,367,369,370,371,373,374,375,377,378,379,381,382,383,385,386,387,389,390,391,393,394,395,397,398,399,401,402,403,405,406,407,409,410,411,413,414,415,417,418,419,421,422,423,425,426,427,429,430,431,433,434,435,437,438,439,441,442,443,445,446,447,449,450,451,453,454,455,457,458,459,461,462,463,465,466,467,469,470,471,473,474,475,477,478,479,481,482,483,485,486,487,489,490,491,493,494,495,497,498,499,501,502,503,505,506,507,509,510,511,513,514,515,517,518,519,521,522,523,525,526,527,529,530,531,533,534,535,537,538,539,541,542,543,545,546,547,549,550,551,553,554,555,557,558,559,561,562,563,565,566,567,569,570,571,573,574,575,577,578,579,581,582,583,585,586,587,589,590,591,593,594,595,597,598,599,601,602,603,605,606,607,609,610,611,613,614,615,617,618,619,621,622,623,625,626,627,629,630,631,633,634,635,637,638,639,641,642,643,645,646,647,649,650,651,653,654,655,657,658,659,661,662,663,665,666,667,669,670,671,673,674,675,677,678,679,681,682,683,685,686,687,689,690,691,693,694,695,697,698,699,701,702,703,705,706,707,709,710,711,713,714,715,717,718,719,721,722,723,725,726,727,729,730,731,733,734,735,737,738,739,741,742,743,745,746,747,749,750,751,753,754,755,757,758,759,761,762,763,765,766,767,769,770,771,773,774,775,777,778,779,781,782,783,785,786,787,789,790,791,793,794,795,797,798,799,801,802,803,805,806,807,809,810,811,813,814,815,817,818,819,821,822,823,825,826,827,829,830,831,833,834,835,837,838,839,841,842,843,845,846,847,849,850,851,853,854,855,857,858,859,861,862,863,865,866,867,869,870,871,873,874,875,877,878,879,881,882,883,885,886,887,889,890,891,893,894,895,897,898,899,901,902,903,905,906,907,909,910,911,913,914,915,917,918,919,921,922,923,925,926,927,929,930,931,933,934,935,937,938,939,941,942,943,945,946,947,949,950,951,953,954,955,957,958,959,961,962,963,965,966,967,969,970,971,973,974,975,977,978,979,981,982,983,985,986,987,989,990,991,993,994,995,997,998,999;原因:证件类型不存在,请检查!。`;
    const toolTip = Vue.compile(`
    <el-popover
      placement="left"
      width="300"
      trigger="hover"
      popper-class="import-popover-box"
    >
      <p>${ msg }</p>
      <el-button type="text" slot="reference">点击查看详情原因</el-button>
    </el-popover>
    `);
    new Vue({
      el: "#app",
      // render:toolTip.render,
      // staticRenderFns:toolTip.staticRenderFns,
      created() {
        const h = this.$createElement;
        this.$confirm(h(toolTip, null, null), "上传失败", {
          confirmButtonText: "确定",
          showCancelButton: false,
          type: "warning",
          center: true,
          customClass: "import-message-box",
          dangerouslyUseHTMLString: true
        }).then(action => {

        });
      }
    })

  </script>
</body>

</html>
已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。

我看 vue2 有个 vue-code-view 项目

vue3 的话 看下官方的 sfc-playground?

我最近也在做和你一样的需求...

请问解决方案有了吗?现在面临同样的问题。求解答

现在面临同样的问题。求解答

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题