灵光一闪!帮你使用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的初心,反而把简单问题复杂化了。

今天的分享到这里就结束啦,后续还会为大家带来更多严肃和有趣的内容~
你有什么在开发中"忘记初心"的事情吗?
灵光一闪!帮你使用Vue,搞定无法解决的“动态挂载”的更多相关文章
- Gulp帮你自己主动搞定coffee和scss的compile
今天继续说说gulp的watch,能够自己主动搞定非常多事情.不用每次都去敲命令了! 上次说到用gulp能够非常方便的进行css,js,html的压缩.而且能够对coffee和scss进行编译. cs ...
- 重磅教程!帮你全面彻底搞定Material design的学习笔记
http://www.uisdc.com/comprehensive-material-design-note
- JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)
前言:关于Vue框架,好几个月之前就听说过,了解一项新技术之后,总是处于观望状态,一直在犹豫要不要系统学习下.正好最近有点空,就去官网了解了下,看上去还不错的一个组件,就抽空研究了下.最近园子里vue ...
- sass笔记-1|Sass是如何帮你又快又好地搞定CSS的
Sass学习笔记持续整理中,开篇不讲怎么安装,sass是什么,这些搜索引擎会告诉你,我们从sass的作用开始讲起,知道sass用来干什么,有什么作用,我们才能相信用sass的好处,并且时时刻刻想着sa ...
- vue+mock.js+element-ui模拟数据搞定分页
效果如图: 前提是搭好vue前端框架,npm install mockjs引入mock.js 当前页全部代码如下,其他有关element-ui的引入未提到,仅作参考用 <!-- 用户管理 --& ...
- 一文搞定Spring Boot + Vue 项目在Linux Mysql环境的部署(强烈建议收藏)
本文介绍Spring Boot.Vue .Vue Element编写的项目,在Linux下的部署,系统采用Mysql数据库.按照本文进行项目部署,不迷路. 1. 前言 典型的软件开发,经过" ...
- 在vue中使用基于d3为基础的dagre-d3.js搞定一个流程图组件
项目中想搞定一个流程图,开始使用了阿里的G6,但是G6目前不支持手势,这样就很郁闷了,因为公司的领导都是使用iPad看的,你不支持手势是不行的,后来又想到了百度的echarts,试了试,感觉还不错,手 ...
- 基于vue+springboot+docker网站搭建【二】搞定服务器
搞定服务器 双11在阿里云用家人的身份证注册账号,买了两台打折的服务器.2核4G一台3年799块:1核2G一台3年229块.机器配置如下图. 1.买的时候注意相同地区的相同可用区.比如我两台机器都选择 ...
- 【API进阶之路】老板给我涨薪30%!如何通过SDK接口搞定千万级流量直播
摘要:看我如何通过API Explorer 的SDK接口搞定千万级流量直播. 最近几个月,我的变化其实还蛮大的,从一个被实习生“无视”的“前浪”,转变成了不仅能够解决技术问题还能解决业务问题(顺手还能 ...
随机推荐
- IKE~多预共享密钥问题~解决方案
原文链接:Configuring more than one Main-Mode Pre-Shared Key (PSK) *dialup* IPSec phase1 可能需要梯子来翻过高墙.文章内容 ...
- FinallShell连接Centos虚拟机
1.虚拟机下输入ip addr查看网络状态,保证ens33下有ip 2.若没有IP的解决办法 方法一················· 1.输入 cd /etc/sysconfig/network-s ...
- java版gRPC实战之二:服务发布和调用
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 除PerfDog之外,还有什么性能测试工具。
除PerfDog之外,还有什么性能测试工具. 高通的Snapdragon Profiler 下载地址:https://developer.qualcomm.com/software/snapdrago ...
- 学习Tomcat(二)之容器概览
Tomcat容器的Server模块有管理容器的启动和关闭.管理了容器内的服务组件Service.管理了全局JNDI资源的功能,对Tomcat容器的生命周期管理有重要意义.Tomcat的服务组件则是To ...
- IIS中配置WCF站点
http://msdn.microsoft.com/zh-cn/library/aa751852.aspx http://blog.csdn.net/hsg77/article/details/389 ...
- 【小程序】微信小程序iOS苹果报错“协议错误”
遇到问题 目前正在开发一个小程序,然后苹果真机测试时发现无法授权并提示,errMsg:"request:fail 未能完成该操作.协议错误" 开发环境下测试没问题,安卓机真机测试没 ...
- python二级 之 第 五套
1. 这里要注意输入的 就是列表 . [1,2,3] 2. 就是你要明白 random.seed() 产生随机种子# 与random.randint() 取 ...
- HTML 网页开发、CSS 基础语法—— 一. HTML概述(了解网页)
1. 网页的本质 ① HTML就是用来制作网页文件的. ② 浏览器查看的网页都是.html或.htm文件. ③ HTML叫做超文本标记语言(Hypertext Markup Language),用于搭 ...
- YbtOJ#853-平面标记【整体二分,凸壳】
正题 题目链接:http://www.ybtoj.com.cn/contest/119/problem/3 题目大意 给出\(n\)个点\((x_i,y_i)\),\(m\)次给出\((k_i,a_i ...