每日一博 | 使用 Vue 搞定无法解决的“动态挂载”
在一些特殊场景下,使用组件的时机无法确定,或者无法在Vue的template中确定要我们要使用的组件,这时就需要动态的挂载组件,或者使用运行时编译动态创建组件并挂载。
今天我们将带大家从实际项目出发,看看在实际解决客户问题时,如何将组件进行动态挂载,并为大家展示一个完整的解决动态挂载问题的完整过程。
无法解决的“动态挂载”
我们的电子表格控件SpreadJS在运行时,存在这样一个功能:当用户双击单元格会显示一个输入框用于编辑单元格的内容,用户可以根据需求按照自定义单元格类型的规范自定义输入框的形式,集成任何Form表单输入类型。
这个输入框的创建销毁都是通过继承单元格类型对应方法实现的,因此这里就存在一个问题——这个动态的创建方式并不能简单在VUE template中配置,然后直接使用。
而就在前不久,客户问然询问我:你家控件的自定义单元格是否支持Vue组件比如ElementUI的AutoComplete?
由于前面提到的这个问题:
沉思许久,我认真给客户回复:“组件运行生命周期不一致,用不了”,但又话锋一转,表示可以使用通用组件解决这个问题。
问题呢,是顺利解决了。
但是这个无奈的"用不了",却也成为我这几天午夜梦回跨不去的坎。
后来,某天看Vue文档时,我想到App是运行时挂载到#app上的。,从理论上来说,其他组件也应该能动态挂载到需要的Dom上,这样创建时机的问题不就解决了嘛!
正式开启动态挂载
让我们继续查看文档,全局APIVue.extend( options )是通过extend创建的。Vue实例可以使用$mount方法直接挂载到DOM元素上——这正是我们需要的。
<div id="mount-point"></div> // 创建构造器 var Profile = Vue.extend({ template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>', data: function () { return { firstName: 'Walter', lastName: 'White', alias: 'Heisenberg' } } }) // 创建 Profile 实例,并挂载到一个元素上。 new Profile().$mount('#mount-point')
按照SpreadJS自定义单元格示例创建AutoCompleteCellType,并设置到单元格中:
function AutoComplateCellType() { } AutoComplateCellType.prototype = new GC.Spread.Sheets.CellTypes.Base(); AutoComplateCellType.prototype.createEditorElement = function (context, cellWrapperElement) { // cellWrapperElement.setAttribute("gcUIElement", "gcEditingInput"); cellWrapperElement.style.overflow = 'visible' let editorContext = document.createElement("div") editorContext.setAttribute("gcUIElement", "gcEditingInput"); let editor = document.createElement("div"); // 自定义单元格中editorContext作为容器,需要在创建一个child用于挂载,不能直接挂载到editorContext上 editorContext.appendChild(editor); return editorContext; } AutoComplateCellType.prototype.activateEditor = function (editorContext, cellStyle, cellRect, context) { let width = cellRect.width > 180 ? cellRect.width : 180; if (editorContext) { // 创建构造器 var Profile = Vue.extend({ template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>', data: function () { return { firstName: 'Walter', lastName: 'White', alias: 'Heisenberg' } } }) // 创建 Profile 实例,并挂载到一个元素上。 new Profile().$mount(editorContext.firstChild); } };
运行,双击进入编辑状态,结果却发现报错了
[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
根据报错提示,此时候我们有两种解决办法:
- 开启runtimeCompiler,在vue.config.js中加入runtimeCompiler: true的配置,允许运行时编译,这样可以动态生成template,满足动态组件的需求
- 提前编译模板仅动态挂载,autocomplete的组件是确定的,我们可以使用这种方法
新建AutoComplete.vue组件用于动态挂载,这样可以挂载编译好的组件。
<template> <div> <p>{{ firstName }} {{ lastName }} aka {{ alias }}</p> </div> </template> <script> export default { data: function () { return { firstName: "Walter", lastName: "White", alias: "Heisenberg", }; }, }; </script> import AutoComplate from './AutoComplate.vue' AutoComplateCellType.prototype.activateEditor = function (editorContext, cellStyle, cellRect, context) { let width = cellRect.width > 180 ? cellRect.width : 180; if (editorContext) { // 创建构造器 var Profile = Vue.extend(AutoComplate); // 创建 Profile 实例,并挂载到一个元素上。 new Profile().$mount(editorContext.firstChild); } };
双击进入编辑状态,看到组件中的内容
下一步,对于自定义单元格还需要设置和获取组件中的编辑内容,这时通过给组件添加props,同时在挂载时创建的VueComponent实例上直接获取到所有props内容,对应操作即可实现数据获取设置。
更新AutoComplate.vue,添加props,增加input用于编辑
<template> <div> <p>{{ firstName }} {{ lastName }} aka {{ alias }}</p> <input type="text" v-model="value"> </div> </template> <script> export default { props:["value"], data: function () { return { firstName: "Walter", lastName: "White", alias: "Heisenberg", }; }, }; </script>
通过this.vm存储VueComponent实例,在getEditorValue 和setEditorValue 方法中获取和给VUE组件设置Value。编辑结束,通过调用$destroy()方法销毁动态创建的组件。
AutoComplateCellType.prototype.activateEditor = function (editorContext, cellStyle, cellRect, context) { let width = cellRect.width > 180 ? cellRect.width : 180; if (editorContext) { // 创建构造器 var Profile = Vue.extend(MyInput); // 创建 Profile 实例,并挂载到一个元素上。 this.vm = new Profile().$mount(editorContext.firstChild); } }; AutoComplateCellType.prototype.getEditorValue = function (editorContext) { // 设置组件默认值 if (this.vm) { return this.vm.value; } }; AutoComplateCellType.prototype.setEditorValue = function (editorContext, value) { // 获取组件编辑后的值 if (editorContext) { this.vm.value = value; } }; AutoComplateCellType.prototype.deactivateEditor = function (editorContext, context) { // 销毁组件 this.vm.$destroy(); this.vm = undefined; };
整个流程跑通了,下来只需要在AutoComplate.vue中,将input替换成ElementUI 的el- autocomplete并实现对应方法就好了。
结果
让我们看看效果吧。
其实动态挂载并不是什么复杂操作,理解了Vue示例,通过vm来操作实例,灵活的运用动态挂载或者运行时编译的组件就不是什么难事了。
其实一切的解决方案就在Vue教程入门教程中,但是脚手架的使用和各种工具的使用让我们忘记了Vue的初心,反而把简单问题复杂化了。
今天的分享到这里就结束啦,后续还会为大家带来更多严肃和有趣的内容~
你有什么在开发中"忘记初心"的事情吗?

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Hive 勒索软件变种:针对 Linux 服务器、使用 Go 编写
根据 BleepingComputer 的报道,Hive 勒索软件组织针对 Linux 和 FreeBSD 平台开发了新的恶意软件变种来进行加密。不过新变种还处于开发阶段,功能缺乏。 安全公司 ESET 研究实验室发现,Hive 的 Linux 变种存在许多严重的 bug,例如当它以显式路径执行时,加密会完全失败。Linux 变种只支持单个命令行参数(-no-wipe),而它的 Windows 版本支持 5 个执行选项,包括杀死进程、跳过磁盘清理、绕过不感兴趣的文件和旧文件等。此外,如果 Hive 的 Linux 变种在没有 root 权限的情况下执行,同样无法触发加密,因为它试图将赎金记录放在受感染设备的根文件系统上。 研究人员还提到,这些恶意软件的 Linux 变体使用 Go 语言编写,但字符串、包名和函数名都经过了混淆,很可能是使用 gobfuscate 实现。 Hive 勒索软件组织从今年 6 月开始活跃,到目前为止攻击了 30 多个组织,是众多开始将 Linux 服务器作为攻击目标的勒索软件组织之一。通过以虚拟机为目标,勒索软件组织可以使用单个命令一次加密多个服务器。Emsi...
- 下一篇
Salvo —— Rust 编写的 Web 后端框架
Salvo 是一个极其简单易用却又功能强大的 Rust Web 后端框架. 目标是让 Rust 下的 Web 后端开发能像 Go 等其他语言里的一样简单. 源码地址: https://github.com/salvo-rs/salvo 🎯 功能特色 基于hyper, tokio 的异步 Web 后端框架; 支持 Websocket; 统一的中间件和句柄接口, 中间件系统支持在句柄之前或者之后运行; 简单易用的路由系统, 支持路由嵌套, 在任何嵌套层都可以添加中间件; 集成 multipart 表单处理, 处理上传文件变得非常简单; 支持从多个本地目录映射成一个虚拟目录提供服务. ⚡️ 快速开始 你可以查看实例代码, 或者访问网站. 创建一个全新的项目: cargo new hello_salvo --bin 添加依赖项到 Cargo.toml [dependencies] salvo = { version = "0.13", features = ["full"] } tokio = { version = "1.5", features = ["full"] } 在 ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Linux系统CentOS6、CentOS7手动修改IP地址
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Red5直播服务器,属于Java语言的直播服务器
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS6,CentOS7官方镜像安装Oracle11G