vue3-sfc-loader 加载远程.vue文件(sfc)案例

注意事项

  1. style标签如果增加了lang比如:lang="scss",需要提供scss-loader的处理器,这个暂时没研究,我的处理方式是将动态模版的css放在了全局
  2. 打包暂时还没有测试,后面测试了会同步更新

安装vue3-sfc-loader

npm 复制代码
npm install vue3-sfc-loader

后端vue模版 (sfc案例)

后端我用的是java加Velocity模版引擎(.vm模版)

vm模版引擎位置:

vm模版

复制代码
<template>
  <view class="cus-tab theme theme-page">
    <uniForms ref="formRef" :modelValue="formData" validate-trigger="bind">
      <table class="tableCla">
        <colgroup>
          <col style="width: 20px;">
          <col style="width: 70px;">
          <col style="width: 130px;">
          <!-- <col style="width: 70px;"> -->
        </colgroup>
        <thead>
        <tr>
          <th class="slash-wrap" colspan="2">
            <div class="oline">
              <span class="span1">年级</span>
              <span class="span2">姓名</span>
            </div>
          </th>
          <th>高三二班</th>
          <th>异议数据</th>
        </tr>
        </thead>
        <tbody>
        <tr>
          <td colspan="2">身高</td>
          <td>身高</td>
          <td>
            <uniFormsItem name="sga">
              <view class="input-cla theme-flex">
                <uniEasyinput :clearable="false" v-model="formData.sga"
                               placeholder=""></uniEasyinput>
                <text>cm</text>
              </view>
            </uniFormsItem>
          </td>
        </tr>
        <tr>
          <td colspan="2">体重</td>
          <td>88888888</td>
          <td>
            <uniFormsItem name="tz">
              <view class="input-cla theme-flex">
                <uniEasyinput :clearable="false" v-model="formData.tz"
                               placeholder=""></uniEasyinput>
                <text>kg</text>
              </view>
            </uniFormsItem>
          </td>
        </tr>
        <tr>
          <td colspan="1" rowspan="3">眼科检查</td>
          <td>裸眼视力</td>
          <td>das</td>
          <td>
            <view class="theme-flex">
              <view class="input-cla theme-flex">
                <uniFormsItem name="lyz">
                  <view class="input-cla theme-flex">
                    <text>左</text>
                    <uniEasyinput :clearable="false" v-model="formData.lyz"
                                   placeholder=""></uniEasyinput>
                  </view>
                </uniFormsItem>
                <text>/</text>
                <uniFormsItem name="lyy">
                  <view class="input-cla theme-flex">
                    <text>右</text>
                    <uniEasyinput :clearable="false" v-model="formData.lyy"
                                   placeholder=""></uniEasyinput>
                  </view>
                </uniFormsItem>
              </view>
            </view>

          </td>
        </tr>
        <tr>
          <td>矫正视力</td>
          <td>John</td>
          <td>
            <view class="theme-flex">
              <view class="input-cla theme-flex">
                <uniFormsItem name="jzz">
                  <view class="input-cla theme-flex">
                    <text>左</text>
                    <uniEasyinput :clearable="false" v-model="formData.jzz"
                                   placeholder=""></uniEasyinput>
                  </view>
                </uniFormsItem>
                <text>/</text>
                <uniFormsItem name="jzy">
                  <view class="input-cla theme-flex">
                    <text>右</text>
                    <uniEasyinput :clearable="false" v-model="formData.jzy"
                                   placeholder=""></uniEasyinput>
                  </view>
                </uniFormsItem>
              </view>
            </view>
          </td>
        </tr>
        <tr>
          <td>角膜炎</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <wdCheckbox v-model="formData.jmy" shape="square">有异议</wdCheckbox>
            </view>
          </td>
        </tr>
        <tr>
          <td colspan="1" rowspan="4">内科检查</td>
          <td>心脏</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <wdCheckbox v-model="formData.xz" shape="square">有异议</wdCheckbox>
            </view>
          </td>
        </tr>
        <tr>
          <td>肺</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <wdCheckbox v-model="formData.fei" shape="square">有异议</wdCheckbox>
            </view>
          </td>
        </tr>
        <tr>
          <td>肝</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <wdCheckbox v-model="formData.gan" shape="square">有异议</wdCheckbox>
            </view>
          </td>
        </tr>
        <tr>
          <td>脾</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <wdCheckbox v-model="formData.pi" shape="square">有异议</wdCheckbox>
            </view>
          </td>
        </tr>
        <tr>
          <td colspan="1" rowspan="8">外科检查</td>
          <td>头部</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <wdCheckbox v-model="formData.tb" shape="square">有异议</wdCheckbox>
            </view>
          </td>
        </tr>
        <tr>
          <td>颈部</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <uniEasyinput :clearable="false" v-model="formData.sg" placeholder=""></uniEasyinput>
            </view>
          </td>
        </tr>
        <tr>
          <td>甲状腺</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <uniEasyinput :clearable="false" v-model="formData.sg" placeholder=""></uniEasyinput>
            </view>
          </td>
        </tr>
        <tr>
          <td>胸部</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <uniEasyinput :clearable="false" v-model="formData.sg" placeholder=""></uniEasyinput>
            </view>
          </td>
        </tr>
        <tr>
          <td>脊椎</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <uniEasyinput :clearable="false" v-model="formData.sg" placeholder=""></uniEasyinput>
            </view>
          </td>
        </tr>
        <tr>
          <td>四肢</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <uniEasyinput :clearable="false" v-model="formData.sg" placeholder=""></uniEasyinput>
            </view>
          </td>
        </tr>
        <tr>
          <td>皮肤</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <uniEasyinput :clearable="false" v-model="formData.sg" placeholder=""></uniEasyinput>
            </view>
          </td>
        </tr>
        <tr>
          <td>淋巴结</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <uniEasyinput :clearable="false" v-model="formData.sg" placeholder=""></uniEasyinput>
            </view>
          </td>
        </tr>
        <tr>
          <td colspan="1" rowspan="3">耳鼻喉科</td>
          <td>耳</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <uniEasyinput :clearable="false" v-model="formData.sg" placeholder=""></uniEasyinput>
            </view>
          </td>
        </tr>
        <tr>
          <td>鼻</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <uniEasyinput :clearable="false" v-model="formData.sg" placeholder=""></uniEasyinput>
            </view>
          </td>
        </tr>
        <tr>
          <td>扁桃体</td>
          <td>John</td>
          <td>
            <view class="input-cla theme-flex">
              <uniEasyinput :clearable="false" v-model="formData.sg" placeholder=""></uniEasyinput>
            </view>
          </td>
        </tr>
        <tr>
          <td colspan="4">
            <view class="input-text-cla">
              <uniFormsItem required name="fkyj" :rules="[{required: true,errorMessage: '请填写反馈意见',}]">
                <view class="theme-flex">
                  <uniEasyinput type="textarea" autoHeight :clearable="false" v-model="formData.fkyj"
                                 placeholder="请输入反馈意见"></uniEasyinput>
                </view>
              </uniFormsItem>
            </view>
          </td>
        </tr>
        </tbody>
      </table>
      <view>
        <view class="tips-clas theme-flex">
          <text>1. 请如实填写,填写完成后保存</text>
          <text>2. 异议数据需机构审核,请耐心等待</text>
        </view>
        <view class="bot-box">
          <wdButton @click="submit">提交审核</wdButton>
        </view>
      </view>
    </uniForms>
  </view>
</template>

<script setup name="Abnormal">
  import { ref, reactive } from 'vue'
  import uniForms from 'uniForms'
  import uniFormsItem from 'uniFormsItem'
  import uniEasyinput from 'uniEasyinput'
  import wdCheckbox from 'wdCheckbox'
  import wdButton from 'wdButton'
  const formRef = ref();
  const formData = reactive({
    sga: '',
    sg: '',
    tz: '',
    lyz: '',
    lyy: '',
    jzz: '',
    jzy: '',
    fkyj: '',
    jmy: false,
    xz: false,
    fei: false,
    gan: false,
    pi: false,
    tb: false,
  });
  const submit = () => {
    formRef.value.validate().then((res) => {
      console.log('表单数据信息:', res);
    }).catch((err) => {
      console.log('表单错误信息:', err);
    })
  };
</script>

<style lang="scss">
  .oline {
    border-top: 50px #c5c5c5 solid;
    width: 0px;
    height: 0px;
    border-left: 90px #ffffff solid;
    position: relative;

  }

  .oline::before {
    position: absolute;
    top: -40px;
    left: -80px;
    width: 80px;
    height: 40px;
    /* background: #fff url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiPjxsaW5lIHgxPSIwIiB5MT0iMCIgeDI9IjEwMCUiIHkyPSIxMDAlIiBzdHJva2U9ImJsYWNrIiBzdHJva2Utd2lkdGg9IjEiLz48L3N2Zz4=) no-repeat 100% center; */
    content: '';
  }

  .span1 {
    font-style: normal;
    display: block;
    position: absolute;
    top: -40px;
    left: -40px;
    width: 35px;
  }

  .span2 {
    font-style: normal;
    display: block;
    position: absolute;
    top: -25px;
    left: -70px;
    width: 55px;
  }

  .top {
    padding: 10px;
    border-bottom: 1px solid #e8e8e8;
  }

  .aColor>a {
    color: rgba(0, 0, 0, 0.65);
  }

  .tableCla {
    width: 100%;
    border: 1px solid #e8e8e8;
    border-collapse: collapse;
  }

  .theadCla>tr>th {
    padding: 10px;
    color: rgba(0, 0, 0, 0.85);
    border: 1px solid #e8e8e8;
    background: #fafafa;
    font-weight: normal;
  }

  tbody>tr>td,
  th {
    text-align: center;
    font-weight: normal;
    color: rgba(0, 0, 0, 0.65);
    /* padding: 15px 10px; */
    border: 1px solid #e8e8e8;
    font-size: 12px;
  }



  tr:nth-child(even) {
    /* background: #effefd; */
  }

  td {
    font-size: 15px;
  }

  .input-cla {
    width: 100%;
    // border: 1px solid #888888;
    height: 30px;
    padding: 10px;
    box-sizing: border-box;
    align-items: center;
    text-align: center;
    justify-content: center;

    :deep(.uni-easyinput__content-input) {
      height: 20px;
      font-size: 14px;
      width: 40px;
    }

    :deep(.uni-easyinput__content) {
      height: 20px;
      font-size: 14px;
      width: 100%;
    }

    :deep(.uni-easyinput) {
      height: 20px;
      font-size: 14px;
      flex: 0;
      width: 40px !important;
    }

    :deep(.uni-input-input) {
      font-size: 11px !important;
    }

    :deep(.uni-easyinput__content-input) {
      height: 20px !important;
    }


  }

  .cus-tab {
    :deep(.uni-forms-item) {
      margin-bottom: 0px !important;
    }
  }

  .input-text-cla {
    padding: 10px 5px;
    padding-bottom: 20px;
    box-sizing: border-box;
  }

  .tips-clas {
    flex-direction: column;
    color: red;
    align-items: flex-start;
    gap: 5px;
    font-size: 14px;
    padding: 10px;
    box-sizing: border-box;
  }

  .bot-box {
    width: 100%;
    padding: 10px;
    padding-top: 5px;
    box-sizing: border-box;
    :deep(.wd-button) {
      width: 90%;
      display: block;
      margin: 0 auto;
    }

  }
</style>

后端处理模版数据

之前写过类似的,就直接拿来用了,传送门

前端案例

前端使用的uniapp+vue3+ts+vite

moduleCache中需要存放你的vm模版中的组件及api差不类似运行时的东西,不然标签是不会被解析的,类似下面中的uni-ui的组件,如果不引入就不会被解析,注意:引入的模版key要与vm模板中的名称一致

vue 复制代码
<template>
	<!-- <div style=" margin: 0; padding: 0;overflow-y: scroll;"> -->
		<component :is="dynamicComponent" v-if="templateStr"></component>
		<wd-status-tip image="comment" tip="暂无报告数据~" v-else/>
		<Fab ref="fabRef" @selectAr="selectAr" />
	<!-- </div> -->
</template>
<script setup lang="ts" name="CalendarYear">
	import { onLoad } from '@dcloudio/uni-app'
	import uniForms from '@dcloudio/uni-ui/lib/uni-forms/uni-forms.vue'
	import uniFormsItem from '@dcloudio/uni-ui/lib/uni-forms-item/uni-forms-item.vue'
	import uniDataCheckbox from '@dcloudio/uni-ui/lib/uni-data-checkbox/uni-data-checkbox.vue'
	import uniEasyinput from '@dcloudio/uni-ui/lib/uni-easyinput/uni-easyinput.vue'
	import { abnormalReport } from '@/api/speExamineResService'
	import { loadModule } from "vue3-sfc-loader/dist/vue3-sfc-loader"
	import wdCheckbox from 'wot-design-uni/components/wd-checkbox/wd-checkbox.vue'
	import wdButton from 'wot-design-uni/components/wd-button/wd-button.vue'
	import * as Vue from 'vue'
	import Fab from '@/components/Fab/index.vue'
	import { compile } from 'sass';
	import useUserStore from "@/store/user";
	const fabRef = ref()
	const proxy = getCurrentInstance()?.proxy
	const dynamicComponent = shallowRef();
	const templateStr = ref('')
	const archiveInfo = computed(() => {
		return useUserStore().getSelectArchive()
	})
	const reportFun = (val : any) => {
		if (!val.archivesId) {
			proxy.$pop.toast('请选择学生')
			nextTick(() => {
				fabRef.value.openAr()
			})
			return;
		}
		console.log('uniForms', uniForms)
		abnormalReport(val.archivesId).then(async (res : any) => {
			console.log(res)
			templateStr.value = res.data
			const options = {
				moduleCache: {
					vue: Vue,
					'uniForms': uniForms,
					'uniFormsItem': uniFormsItem,
					'uniEasyinput': uniEasyinput,
					'wdCheckbox': wdCheckbox,
					'wdButton': wdButton,
					'scss': (source) => {
						console.log('======>source',source)
						return Object.assign(compile(source), { deps: () => [] })
					}
				},
				async getFile() {
					return res.data
				},
				addStyle(textContent) {
					console.log('textContent,', textContent)
					const style = Object.assign(document.createElement('style'), { textContent })
					console.log('style,', style)
					const ref = document.head.getElementsByTagName('style')[0] || null
					document.head.insertBefore(style, ref)
				},
				loader: {
					
				}
			};
			dynamicComponent.value = defineAsyncComponent(() => loadModule(res.fileName || "loader.vue", options))
		})
	}
	const selectAr = async (val : any) => {
		reportFun(val)
	}
	onLoad(() => {
		reportFun(archiveInfo.value)
	})
</script>
<style lang="scss">

</style>

页面效果图

相关推荐
崔庆才丨静觅12 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
曹牧13 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
passerby606113 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了13 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅13 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅13 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
爬山算法13 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
kfyty72513 小时前
集成 spring-ai 2.x 实践中遇到的一些问题及解决方案
java·人工智能·spring-ai
猫头虎14 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
李少兄14 小时前
在 IntelliJ IDEA 中修改 Git 远程仓库地址
java·git·intellij-idea