灵光一闪!帮你使用Vue,搞定无法解决的“动态挂载”
Posted 葡萄城技术团队
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了灵光一闪!帮你使用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的初心,反而把简单问题复杂化了。
今天的分享到这里就结束啦,后续还会为大家带来更多严肃和有趣的内容~
你有什么在开发中"忘记初心"的事情吗?
灵光一闪(最近更新于2020/50/3)
灵光一闪主要记录我灵感乍现的感悟
2020年5月3日
今天上厕所时,看了两页《少有人的走的路》里面的一些内容引起了我的共鸣。
最近我一直在思考知识和技能之间的转换,知识不等于技能,知识变成技能需要积累,需要经历生产环境的压力,需要经历痛苦、纠结等情绪才能真正将知识转换成为技能,这是我自己的理解。我发现《少有人走的路》对此的论述更生动,更彻底,更打动人,在这里记录一下。
真正的领悟,不是知识的积累,而不是阅历的丰富,而是在自我破碎的过程当中对生命的觉知。
这种觉知不是理智上的认识,而是真真切切的感受,从头到脚,从里到外,感受到自我的破碎,以及撕心裂肺般的疼痛
这样的感受总是会给你带来巨变。
徒弟:你为什么老是让我把你的话放在心上,而不是放在心里呢?
师傅:我们的心是封闭的,我们无法把别的话放到自己的心里,只能放在心上,等你的心崩溃的时候,这些话就能掉进去了。
我的人生当中经历过两次比较大的疼痛,第一次是精神上的疼痛,经历我在无锡电子厂打工,我认为自己的人生完了,每天都很煎熬,失眠抑郁;第二次是肉体上的疼痛,我的右手臂严重螺旋型骨折,前后做两次手术,而且当中要携带钢板,生活极不方便,内心非常煎熬;后来我从重新回到校园,一直到现在,这两段人生体验对我来说都是非常深刻的,是深入骨子里的深刻。
我没有经历过失恋,其实失恋也并不是全是坏事,如果你全身心的投入的话,失恋一定会让你撕心裂肺,这种疼痛会让你改变对生命的觉知,可能会认识到自己的幼稚和怯懦进而变得成熟起来,可能这种疼痛还会造成一个非常不好的效果,如果这种疼痛过于强烈的话,会伤害到我们的生命内核,生命内核指的是亲密关系,一旦伤害到生命内核就有可能造成性情大变,觉知扭曲,比如有的人失恋之后,会认为男人都不是好东西,可能自己会变成渣男、渣女,专门去伤害别人,并以此为乐。
以上是关于灵光一闪!帮你使用Vue,搞定无法解决的“动态挂载”的主要内容,如果未能解决你的问题,请参考以下文章