简单实现一个vue公式编辑器组件demo
作者:TangJang
这篇文章主要介绍了轻松实现一个简单的vue公式编辑器组件示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
基于vue实现数据统计公式的基本功能
一个基于vue实现数据统计公式的基本功能。
新建一个 formula.vue 组件
使用
<formula ref="formulaPage" :data-list="dataList" ></formula>
完整demo
<template> <div id="formulaPage"> <!-- 公式编辑区域 --> <div class="formulaView" id="formulaView" ref="formulaView" @click.stop="recordPosition()" > <div class="content-item" v-for="(item,index) in formulaList" :key="index" @click.stop="recordPosition(index)" > <div class="num" v-if="item.type == 'num'" > ‍{{item.value}} </div> <div class="plain" v-else-if="item.type == 'plain'" > ‍{{item.value}} </div> <div class="obj" v-else-if="item.type == 'obj'" > ‍{{item.value}} </div> <!--光标--> <div class="cursor" v-if="item.cursor" ></div> </div> </div> <div class="tab mt_10 flex-lr"> <div class=""> <el-select @change="e=>{addItem(e,'obj',)}" style="width: 120px" v-model="dataId" placeholder="选择指标" > <el-option v-for="item in dataList" :label="item.name" :value="item.id" :key="item.id" ></el-option> </el-select> <el-select @change="e=>{addItem(e,'plain',)}" v-model="operatorId" placeholder="选择数学运算符" style="width: 120px" class="ml_20" > <el-option v-for="item in operatorList" :label="item.name" :value="item.id" :key="item.id" > </el-option> </el-select> </div> <div class=""> <span class="mr_10 pointer theme-col" @click="clearAll()" > 清除全部</span> </div> </div> </div> </template> <script> /** * dataList 需要选择数据的集合 * defaultList 初始值的集合 * @change 比变更后回传的数据 * **/ export default { name: '', props:{ dataList:{ type:Array, default() { return []; }, }, defaultList:{ type:Array, default() { return []; }, }, }, data: function () { return { // 公式字符串 formulaStr:'', dataId:'', operatorId:'', formulaList:[], //运算符 operatorList:[ { name:'+', id:'+' }, { name:'-', id:'-' }, { name:'*', id:'*' }, { name:'/', id:'/' }, { name:'()', id:'()' }, ] } }, watch:{ formulaList(val){ this.$emit('change',val) } }, created() { //监听鼠标事件 this.$nextTick(function () { document.addEventListener("keydown", this.keydown, false); document.addEventListener('click',this.formulaBlur); }); }, destroyed () { //移除监听事件 document.removeEventListener("keydown", this.keydown, false); document.removeEventListener('click',this.formulaBlur); }, methods: { // 获取 getFormula: function(){ }, // 点选时记录光标位置 recordPosition(index) { if(this.formulaList && this.formulaList.length >0){ this.formulaList = this.formulaList.map((item,itemIndex)=>{ item.cursor = false; if(index > -1 && index == itemIndex){ item.cursor = true; }else if((index!==0 && !index) && itemIndex == (this.formulaList.length -1)){ item.cursor = true; } return item }); }else { this.formulaList = [ { cursor:true, type:'placeholder', value:'', } ] } // this.$forceUpdate(); }, //失去焦点 formulaBlur(e){ this.formulaList = this.formulaList?.map(item=>{ item.cursor = false; return item }) }, /** * @returns {addItem<*, void, *>} * 添加字段 * type obj 字段 num 数字 plain符号 * place 是否修改光标位置 */ addItem: function (val, type,place = true) { if(!val) return false; let that = this; //插入括号 if(type == 'plain' && val == '()'){ val = '('; setTimeout(function () { that.addItem(')',type,false) },50) } let obj={},data = { value:'', key:val, type:type, }; if(type == 'obj'){ //获取数据 为 value 赋值 obj = this.dataList?.find(item=>item.id == val); data.value = obj.name; }else { data.value = val; } if(this.formulaList && this.formulaList.length>0){ const length = this.formulaList.length; for (let i = 0; i < length; i++) { //查找光标位置 如果光标位置为空 则在最后添加 if(this.formulaList[i].cursor){ this.formulaList.splice(i+1,0,data); place && this.recordPosition(i+1); break; }else if(i === (this.formulaList.length - 1)){ this.formulaList.push(data) this.recordPosition(this.formulaList.length - 1); } } }else { if(!this.formulaList){ this.formulaList = []; } this.formulaList.push(data); this.recordPosition(this.formulaList.length - 1); } }, //清除全部 clearAll(){ this.formulaList = []; let that = this; setTimeout(function () { that.recordPosition(); },100); }, //删除 deleteItem(type){ let arr = JSON.parse(JSON.stringify(this.formulaList)),index = null; const length = arr?.length; for (let i = 0; i < length; i++) { if(arr[i].cursor && arr[i].key){ index = i; if(type == 'del'){ index = i + 1; } if(index > -1){ this.formulaList.splice(index,1); if(type == 'del') { }else { this.recordPosition(index - 1); } } break; } } }, // 键盘输入 keydown(e){ //禁止输入 // 检测光标是否存在 let index,cursorData = this.formulaList?.find((item,itemIndex)=>{ if(item.cursor){ index = itemIndex } return item.cursor }); if(!cursorData){ return false; } //左右移动键控制光标位置 if (e && [37,39].includes(e.keyCode)){ if(e.keyCode == 37){index = index - 1;}else {index = index + 1;} if(index > -1 && index < this.formulaList.length){ this.recordPosition(index); } }else if (e && e.keyCode == 8){ //Backspace 键 删除前面的值 this.deleteItem(); }else if (e && [107,109,106,111].includes(e.keyCode)){ //运算符列表 this.addItem(e.key,'plain') }else if (e && e.shiftKey && [48,57].includes(e.keyCode) ){ //括号 if( e.keyCode == 48) e.key = ')'; if( e.keyCode == 57) e.key = '('; this.addItem(e.key,'plain') }else if (e && e.keyCode == 46){ //delete键删除光标后面的值 this.deleteItem('del'); }else { document.returnValue = false; var tt=/^([1-9]{1}[0-9]{0,7})$/;//能输入正数 if(tt.test(e.key)){ //输入为数字 插入数字 this.addItem(e.key,'num') } } }, /** * 公式转为字符串 * 格式 [id]符号数字 * **/ parsingFormula: function(formulaStr){ let str = '',arr = []; arr = this.formulaList?.map(item=>{ let val = item.key; if(val){ if(item.type == 'obj'){ val = '['+val+']' } str = str+val; } return val }); return str }, /** * 格式效验 * */ formatValidation(){ let objData = null; let arr = this.formulaList?.filter(item=>{ if(item.type == 'obj'){ objData = item; } return item.key; }),data = {type:true,mag:''}; if(!objData){ data.mag = '至少添加一个指标'; }else { for (let i = 0; i < arr.length; i++) { if(i < arr.length-1){ //判断当前类型 if(arr[i].type == 'obj' && arr[i+1].type =='plain' ){ //类型为obj时 后一个 需以 符号结尾 data.mag = '指标后缀'; } } } } if(data.mag){ data.type = false; } return data; }, } } </script> <style lang="scss"> #formulaPage { .formulaView{ padding: 3px 4px; width: 100%; height: 120px; border: 1px solid #eee; line-height: 1.3; font-size: 12px; overflow-y: scroll; .content-item{ position: relative; height: 16px; cursor: text; user-select: none; display: flex; align-items: center; float: left; .cursor{ height: 13px; width: 1px; background: #333; animation:defaultCursor 1s steps(2) infinite; position: absolute; right: 0; } .obj { padding: 0 5px; margin: 0 1px; background: #f1f1f1; border-radius: 3px; } .num{ color: #000; background: #fff; padding: 0 1px 0 0; } } } } @keyframes defaultCursor { 0% { opacity: 1; } 100% { opacity: 0; } } </style>
以上就是简单实现一个vue公式编辑器组件demo的详细内容,更多关于vue公式编辑器组件的资料请关注脚本之家其它相关文章!