动态渲染.vue文件其实存在于很多地方,例如近期做的表单设计器就是其中一个,生成vue代码后,应用在其它地方。要求下载完vue文件在其它项目中引入即可使用。那么动态渲染.vue项目如何去做呢?

1. 我们需要一个模板页面,这个页面用来处理传递进来的代码,我们最后通过之前有说过的 extend 以及$mount 来进行实例化挂载。

那么,我们先第一步,创建一个动态渲染.vue的模板页面。

<!-- display.vue -->
<template><div ref="display"></div>
</template>
<script>export default {props: {code: {type: String,default: ''}},data () {return {html: '',js: '',css: ''}},}</script>

在上述模板中,我们传入了一个code,这个code 指的就是外部传递给这个页面的动态.vue文件的内容。

那么,第二步我们则就是来处理传递进来的.vue文件里的内容(代码)。

2. 处理传入的.vue 文件内容

export default {methods: {getSource (source, type) {const regex = new RegExp(`<${type}[^>]*>`);let openingTag = source.match(regex);if (!openingTag) return '';else openingTag = openingTag[0];return source.slice(source.indexOf(openingTag) + openingTag.length, source.lastIndexOf(`</${type}>`));},splitCode () {const script = this.getSource(this.code, 'script').replace(/export default/, 'return ');const style = this.getSource(this.code, 'style');const template = '<div id="app">' + this.getSource(this.code, 'template') + '</div>';this.js = script;this.css = style;this.html = template;},}
}

在上述代码中,我们声明了两个方法,一个是 splitCode ,我们用来分隔传递进来的需要动态渲染的.vue文件的内容。在分割内容的时候为了方便,我们则单独封装了一个方法 getSource方法。这个方法接收两个参数。

  • source:.vue 文件代码,即 props: code;
  • type:分割的部分,也就是 template、script、style。

所以上述的splitCode的方法的目的就是,来分割出我们所需要的三个内容,分别为:模板文件(html)template,js ,css。

分割后,返回的内容不再包含  等标签,直接是对应的内容,在 splitCode 方法中,把分割好的代码分别赋值给 data 中声明的 html、js、css。

有两个细节需要注意:

1. vue的 <script> 部分一般都是以export default 开始的,但是在上述splitCode中,我们把它替换成了return。这里我们需要注意,分割完的代码,仍然是字符串。

2. 在分割的  外层套了一个 <div id="app"> ,这是为了容错,有时使用者传递的 code 可能会忘记在外层包一个节点,没有根节点的组件,是会报错的。

当我们准备好以上之后,就可以使用extend渲染组件了,但是在这之前,我们必须要注意到当前的this.js 是字符串,而extend的说法,接收的选项必须是一个对象类型。那么这时候我们就必须要先把this.js 转为一个对象

我们在这里使用new Function 来进行转化,如下:

const sum = new Function('a', 'b', 'return a + b')
console.log(2, 6) // 8

new Function 的语法:

new Function ([arg1[, arg2[, ...argN]],] functionBody)

arg1, arg2, ... argN 是被函数使用的参数名称,functionBody 是一个含有包括函数定义的 JavaScript 语句的字符串。也就是说,示例中的字符串 return a + b 被当做语句执行了。

this.js 中是将 export default 替换为 return 的,如果将 this.js 传入 new Function 里,那么 this.js 就执行了,这时因为有 return,返回的就是一个对象类型的 this.js 了。

如果你还不是很理解 new Function,可以自行搜索其使用方法。除了 new Function,你熟悉的 eval 函数也可以使用,它与 new Function 功能类似。

所以目前的代码如下:

<template><div ref="display"></div>
</template>
<script>import Vue from 'vue';export default {data () {return {component: null}},methods: {renderCode () {this.splitCode();if (this.html !== '' && this.js !== '') {const parseStrToFunc = new Function(this.js)();parseStrToFunc.template =  this.html;const Component = Vue.extend( parseStrToFunc );this.component = new Component().$mount();this.$refs.display.appendChild(this.component.$el);}}},mounted () {this.renderCode();}}</script>

extend 构造的实例通过 $mount 渲染后,挂载到了组件唯一的一个节点 <div ref="display">上。

到现在为止,html和 js 都有了,还剩下css,加载css 没有什么其它方法,就是创建一个<style>

标签,然后把css 放进去,再插入到前面的 <head> 中,这样css就被游览器给成功解析了,为了便于后面 this.code 变化或组件销毁时移除动态创建的 <style> 的标签,我们给每个style 标签都增加了一个随机ID 表示。

新建工具random_str.js 文件,并写入以下内容:

// 生成随机字符串
export default function (len = 32) {const $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';const maxPos = $chars.length;let str = '';for (let i = 0; i < len; i++) {str += $chars.charAt(Math.floor(Math.random() * maxPos));}return str;
}

这个方法是从指定的 a-zA-Z0-9 中随机生成 32 位的字符串。

我们这时候可以补全之前的代码:

import randomStr from '../../utils/random_str.js';export default {data () {return {id: randomStr()}},methods: {renderCode () {if (this.html !== '' && this.js !== '') {// ...if (this.css !== '') {const style = document.createElement('style');style.type = 'text/css';style.id = this.id;style.innerHTML = this.css;document.getElementsByTagName('head')[0].appendChild(style);}}}}
}

当 Display 组件销毁时,也要手动销毁 extend 创建的实例以及上面的 css:

export default {methods: {destroyCode () {const $target = document.getElementById(this.id);if ($target) $target.parentNode.removeChild($target);if (this.component) {this.$refs.display.removeChild(this.component.$el);this.component.$destroy();this.component = null;}}},beforeDestroy () {this.destroyCode();}
}

当 this.code 更新时,整个过程要重新来一次,所以要对 code 进行 watch 监听:

// display.vue,部分代码省略
export default {watch: {code () {this.destroyCode();this.renderCode();}}
}

以上就是我们动态渲染.vue文件的整个过程了。

此处各位伙伴还需要注意的是版本问题。

在vue2时候,有独立构建和运行时构建两种版本可以选择。

但是vue cli3 的时候,使用了vue.runtime.js 不允许编译template模板。因为我们在vue.extend构造实例的时候,用了 template 选项。所以会报错。所以,解决办法就是,对vue.config 做以修改。

// vue.config.jsmodule.exports = {runtimeCompiler: true
}

而它的意思就是,是否使用包含运行时编译器的Vue构建版本,设置为true后就可以在vue组件中使用 template选项了。

Vue之如何动态渲染.vue文件相关推荐

  1. layui select动态赋值_layui与 VUE 配合使用时动态渲染 select 坑

    使用v-model 动态渲染元素后, 刷新from:layui.form.render(), 一定要刷新from <form class="layui-form" actio ...

  2. 七十、Vue城市页面Ajax动态渲染和兄弟组件数据传递

    2020/10/29. 周四.今天又是奋斗的一天. @Author:Runsen 写在前面:我是「Runsen」,热爱技术.热爱开源.热爱编程.技术是开源的.知识是共享的.大四弃算法转前端,需要每天的 ...

  3. Vue实战篇五:实现文件上传

    系列文章目录 Vue基础篇一:编写第一个Vue程序 Vue基础篇二:Vue组件的核心概念 Vue基础篇三:Vue的计算属性与侦听器 Vue基础篇四:Vue的生命周期(秒杀案例实战) Vue基础篇五:V ...

  4. vue路由与动态路由

    1.vue路由与动态路由 Vue是一个流行的JavaScript框架,提供了一种称为Vue Router的插件,用于管理单页面应用程序的路由.Vue Router允许开发人员定义应用程序的不同页面,并 ...

  5. Vue为何采用异步渲染

    Vue为何采用异步渲染 Vue在更新DOM时是异步执行的,只要侦听到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更,如果同一个watcher被多次触发,只会被推入到队列中一次 ...

  6. Vue每日签到日历渲染

    Vue每日签到日历渲染 `Vue每日签到日历渲染` `先上图` `template` `script` `style` Vue每日签到日历渲染 先上图 template <template> ...

  7. express模板引擎 html,Express新手入坑笔记之动态渲染HTML

    在日常项目中,我喜欢用Django做后端, 因为大而全 如果只是写一个简单服务的话, Express是更好的选择, Express是基于nodejs的一个后端框架,特点是简单,轻量, 容易搭建, 而且 ...

  8. 自己解决在Vue中动态渲染图片不显示的问题

    乐于助人 前言 分析思路 1. 绝对路径 2. 相对路径 总结 本篇文章记录的是自己在 Vue-Cli2 中如何去解决的这个问题,心里路程比较多,所以话比较多哈哈,感谢阅读,大概耗时2分钟 前言 如上 ...

  9. vue项目中引入阿里 iconfont 图标 动态渲染导航菜单图标

    vue + element 后台项目,项目中都是用的 element-ui 的图标 但是导航菜单是通过后台数据渲染的,所以在阿里图标库找了图标给后台,再渲染 步骤一: 在图标库找到想要的图标,加入购物 ...

最新文章

  1. IT兄弟连 JavaWeb教程 监听器3
  2. android:imeOptions属性
  3. 设计模式_4_原型模式(对象的拷贝)
  4. MySQL 学习一:新手一学就会,MySQL 零基础增删改查简单入门教程
  5. think php 3.2.3 环境,ThinkPHP 3.2.3 入口文件配置
  6. 拯救天使 (BFS)
  7. 请慎用ASP.Net的validateRequest=false属性
  8. 基于Multisim的12小时制电子时钟仿真
  9. 数据库索引是什么?为什么要使用索引?
  10. libreelec投屏_低配置主机安装Kodi操作系统 - LibreELEC
  11. 百度地图获取数据库点的坐标,并定时刷新到页面上 jsp
  12. jQuery诞生记-原理与机制
  13. 2.VIM文本编辑器的下载与使用
  14. creo5.0安装教程
  15. 进程间通信的六大方式
  16. 讲解MySQL最详细的一步一步安装教程
  17. OSD的主要实现方法和类型
  18. Java多线程-将全量用户表70万数据压缩并生成CSV文件和推送到FTP上(最快快方式)
  19. 逾期怎么处理_信用卡逾期怎么和银行协商_信用卡逾期协商处理方法
  20. [VOT12](2017CVPR) CSR-DCF: Discriminative Correlation Filter Tracker with Channel and Spatial

热门文章

  1. JAVA设计模式--建造者模式
  2. 量化选股模型—一致预期模型
  3. 【C语言】剖析函数递归(3)
  4. 实践《如何使用Seata保证Dubbo微服务间的一致性》
  5. 使用C++代码创建一个Windows桌面应用程序
  6. js层级轮播图兼容IE8及以上浏览器
  7. iOS多线程的初步研究(三)-- NSRunLoop
  8. 永不服输的Java之路---重学Java (第一章)
  9. STM32用一个定时器封装多个定时函数调用
  10. ASAM让你减肥成为一种乐趣