共计 5744 个字符,预计需要花费 15 分钟才能阅读完成。
示例
一个基于 vue 实现数据统计公式的基本功能。
新建一个 formula.vue 组件,
应用 <formula ref=”formulaPage” :data-list=”dataList” ></formula>
<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> |
正文完