赞
踩
一、业务需求
最近项目上有个需求是:开发一个简洁版的在线sql编辑器,其中一个要实现的功能是:当选中页面中一段sql语句,进行脚本转换,在弹窗里面也要显示选中的sql语句,并且可编辑,同时也要动态显示行号。
最终实现的效果如图所示:
二、思路及功能实现
本项目使用CodeMirror5x版本,因为用到编辑器的地方很多,所以我封装了一个CodeMirror编辑器组件,在需要引用的地方引入编辑器子组件就可以了。
要实现上述需求,我的思路是:在弹窗和页面中都引入了编辑器子组件。当选中页面中的编辑器子组件里的一段文本时、触发CodeMirror的cursorActivity事件,通过此事件把选中的代码、传入弹窗里的编辑器子组件v-model绑定的值,这样就会与之对应。编辑时如果想要获取实时代码、可通过CodeMirror的input事件给v-model绑定的值赋值。
页面中引入编辑器子组件如下所示:
- <codemirror-editor
- ref="myCm"
- :mode="cmMode"
- @input="onEditorInput"
- @selectRange="handleSelectChange">
- </codemirror-editor>
弹窗里引入编辑器子组件如下所示:
- <FormDialog
- title="脚本转换"
- :dialogFlag.sync="showReplaceModal"
- width="50%"
- @cancel="replaceCancel">
- <div class="formDialog" slot="content">
- <el-form class="translateScriptForm">
- <el-form-item label="选中的脚本:" class="selectedScriptItem" >
- <codemirror-editor ref="replaceCodemirrorCm" v-model="selectedText" @input="onSelectedInput"></codemirror-editor>
- </el-form-item>
- <el-form-item class="translateBtnTextItem">
- <el-button type="text" @click="handleTranslate">转换</el-button>
- </el-form-item>
- <el-form-item label="脚本转换结果:" class="translateResultItem">
- <el-input type="textarea" v-model="replacedText" readonly class="replaceTextarea"></el-input>
- </el-form-item>
- </el-form>
- </div>
- <div slot="footer" class="dataDialog-footer">
- <el-button class="confirmBtn " v-show="isFature" type="primary" @click="replaceConfirm">替换</el-button>
- <el-button class="confirmBtn singleSelectBtn" @click="replaceCancel">关闭</el-button>
- </div>
- </FormDialog>
三、问题描述
需求是实现了,但是遇到一个问题:当我选中一段sql语句时,弹窗里初次显示的值是选中的,但是当我再次选中时,弹窗里的子组件值显示的还是上次选中的值。
四、原因分析
经过排查,发现弹窗里的子组件值改变了,视图没变化,所以需要刷新子组件视图,更新dom
五、解决方案
首先我想到了Vue.nextTick()回调函数
(1)监听编辑器子组件的值变化,使用Vue的nextTick异步更新dom
我以为子组件可以刷新视图了,结果还是没有
emma~~
突然想到选中的代码要在弹窗中相对应的显示,这是一个实时更新的过程,异步更新是不起作用的,soga
然后我就想到了第二种方案
(2)Vue有个特殊的attribute key,key的作用是:高效更新虚拟dom,可以强制替换元素/组件而不是重复的使用它。key值变化之后,会自动重新渲染组件。
于是我在弹窗编辑器子组件里加个key属性,key属性的值可以是字符串、时间戳、布尔值等,这里我设置的是时间戳timer。然后我在弹窗出现事件里给timer赋值,在弹窗关闭事件里给timer置空。这样问题就解决了,每次选中一段代码,弹窗中就实时显示选中的代码了。
- <codemirror-editor ref="replaceCodemirrorCm" :key="timer" v-model="selectedText" @input="onSelectedInput">
- </codemirror-editor>
- // 脚本转换按钮事件
- handleCodeTranslate(){
- this.showReplaceModal = true;
- //根据时间戳标识,刷新子组件
- this.timer = new Date().getTime();
- },
- // 脚本转换弹窗取消事件
- replaceCancel(){
- // 清空脚本转换弹窗里的数据
- this.selectedText = '';
- this.replacedText = '';
- this.timer = null;
- // 去除页面上编辑器选中的标记
- let editor = this.variableEditor;
- // 设置光标位置,取消原来的选中状态
- editor.setCursor({line:0,ch:0})
- // 关闭弹窗
- this.showReplaceModal = false;
- },
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。