簡(jiǎn)單實(shí)現(xiàn)一個(gè)vue公式編輯器組件demo
基于vue實(shí)現(xiàn)數(shù)據(jù)統(tǒng)計(jì)公式的基本功能
一個(gè)基于vue實(shí)現(xiàn)數(shù)據(jù)統(tǒng)計(jì)公式的基本功能。
新建一個(gè) formula.vue 組件
使用
<formula ref="formulaPage" :data-list="dataList" ></formula>
完整demo
<template> <div id="formulaPage"> <!-- 公式編輯區(qū)域 --> <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> <!--光標(biāo)--> <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="選擇指標(biāo)" > <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="選擇數(shù)學(xué)運(yùn)算符" 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 需要選擇數(shù)據(jù)的集合 * defaultList 初始值的集合 * @change 比變更后回傳的數(shù)據(jù) * **/ export default { name: '', props:{ dataList:{ type:Array, default() { return []; }, }, defaultList:{ type:Array, default() { return []; }, }, }, data: function () { return { // 公式字符串 formulaStr:'', dataId:'', operatorId:'', formulaList:[], //運(yùn)算符 operatorList:[ { name:'+', id:'+' }, { name:'-', id:'-' }, { name:'*', id:'*' }, { name:'/', id:'/' }, { name:'()', id:'()' }, ] } }, watch:{ formulaList(val){ this.$emit('change',val) } }, created() { //監(jiān)聽(tīng)鼠標(biāo)事件 this.$nextTick(function () { document.addEventListener("keydown", this.keydown, false); document.addEventListener('click',this.formulaBlur); }); }, destroyed () { //移除監(jiān)聽(tīng)事件 document.removeEventListener("keydown", this.keydown, false); document.removeEventListener('click',this.formulaBlur); }, methods: { // 獲取 getFormula: function(){ }, // 點(diǎn)選時(shí)記錄光標(biāo)位置 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(); }, //失去焦點(diǎn) formulaBlur(e){ this.formulaList = this.formulaList?.map(item=>{ item.cursor = false; return item }) }, /** * @returns {addItem<*, void, *>} * 添加字段 * type obj 字段 num 數(shù)字 plain符號(hào) * place 是否修改光標(biāo)位置 */ addItem: function (val, type,place = true) { if(!val) return false; let that = this; //插入括號(hào) if(type == 'plain' && val == '()'){ val = '('; setTimeout(function () { that.addItem(')',type,false) },50) } let obj={},data = { value:'', key:val, type:type, }; if(type == 'obj'){ //獲取數(shù)據(jù) 為 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++) { //查找光標(biāo)位置 如果光標(biāo)位置為空 則在最后添加 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; } } }, // 鍵盤(pán)輸入 keydown(e){ //禁止輸入 // 檢測(cè)光標(biāo)是否存在 let index,cursorData = this.formulaList?.find((item,itemIndex)=>{ if(item.cursor){ index = itemIndex } return item.cursor }); if(!cursorData){ return false; } //左右移動(dòng)鍵控制光標(biāo)位置 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)){ //運(yùn)算符列表 this.addItem(e.key,'plain') }else if (e && e.shiftKey && [48,57].includes(e.keyCode) ){ //括號(hào) if( e.keyCode == 48) e.key = ')'; if( e.keyCode == 57) e.key = '('; this.addItem(e.key,'plain') }else if (e && e.keyCode == 46){ //delete鍵刪除光標(biāo)后面的值 this.deleteItem('del'); }else { document.returnValue = false; var tt=/^([1-9]{1}[0-9]{0,7})$/;//能輸入正數(shù) if(tt.test(e.key)){ //輸入為數(shù)字 插入數(shù)字 this.addItem(e.key,'num') } } }, /** * 公式轉(zhuǎn)為字符串 * 格式 [id]符號(hào)數(shù)字 * **/ 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 }, /** * 格式效驗(yàn) * */ 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 = '至少添加一個(gè)指標(biāo)'; }else { for (let i = 0; i < arr.length; i++) { if(i < arr.length-1){ //判斷當(dāng)前類型 if(arr[i].type == 'obj' && arr[i+1].type =='plain' ){ //類型為obj時(shí) 后一個(gè) 需以 符號(hào)結(jié)尾 data.mag = '指標(biāo)后綴'; } } } } 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>
以上就是簡(jiǎn)單實(shí)現(xiàn)一個(gè)vue公式編輯器組件demo的詳細(xì)內(nèi)容,更多關(guān)于vue公式編輯器組件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在Vue3中實(shí)現(xiàn)拖拽文件上傳功能的過(guò)程詳解
文件上傳是我們?cè)陂_(kāi)發(fā)Web應(yīng)用時(shí)經(jīng)常遇到的功能之一,為了提升用戶體驗(yàn),我們可以利用HTML5的拖放API來(lái)實(shí)現(xiàn)拖拽文件上傳的功能,本文將介紹如何在Vue3中實(shí)現(xiàn)這一功能,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2023-12-12Element plus實(shí)現(xiàn)圖片手動(dòng)上傳與回顯的過(guò)程
近期,發(fā)現(xiàn)點(diǎn)擊修改,element ui 的圖片沒(méi)有回顯到框中,所以本文給大家介紹了Element plus實(shí)現(xiàn)圖片手動(dòng)上傳與回顯的過(guò)程,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2024-09-09詳解Vue返回值動(dòng)態(tài)生成表單及提交數(shù)據(jù)的辦法
這篇文章主要為大家介紹了Vue返回值動(dòng)態(tài)生成表單及提交數(shù)據(jù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2021-12-12VUE使用vue?create命令創(chuàng)建vue2.0項(xiàng)目的全過(guò)程
vue-cli是創(chuàng)建Vue項(xiàng)目的一個(gè)腳手架工具,vue-cli提供了vue create等命令,下面這篇文章主要給大家介紹了關(guān)于VUE使用vue?create命令創(chuàng)建vue2.0項(xiàng)目的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07vue中watch和computed為什么能監(jiān)聽(tīng)到數(shù)據(jù)的改變以及不同之處
這篇文章主要介紹了vue中watch和computed為什么能監(jiān)聽(tīng)到數(shù)據(jù)的改變以及不同之處,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12Vue3 + Vue-PDF 實(shí)現(xiàn)PDF 文件在線預(yù)覽實(shí)戰(zhàn)
這篇文章主要介紹了Vue3 + Vue-PDF 實(shí)現(xiàn)PDF 文件在線預(yù)覽實(shí)戰(zhàn),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-06-06詳解vue與后端數(shù)據(jù)交互(ajax):vue-resource
本篇文章主要介紹了詳解vue與后端數(shù)據(jù)交互(ajax):vue-resource,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03Vue項(xiàng)目中大文件切片上傳實(shí)現(xiàn)秒傳與斷點(diǎn)續(xù)傳的詳細(xì)實(shí)現(xiàn)過(guò)程
這篇文章主要給大家介紹了關(guān)于Vue項(xiàng)目中大文件切片上傳實(shí)現(xiàn)秒傳與斷點(diǎn)續(xù)傳的詳細(xì)實(shí)現(xiàn)過(guò)程, 在開(kāi)發(fā)中,如果上傳的文件過(guò)大,可以考慮分片上傳,分片就是說(shuō)將文件拆分來(lái)進(jìn)行上傳,將各個(gè)文件的切片傳遞給后臺(tái),然后后臺(tái)再進(jìn)行合并,需要的朋友可以參考下2023-08-08Vue實(shí)例創(chuàng)建和掛載的詳細(xì)過(guò)程
在 Vue.js 中,實(shí)例的掛載是一個(gè)非常重要的過(guò)程,它決定了 Vue 實(shí)例如何與 DOM 進(jìn)行交互,通過(guò)分析 Vue 源碼,特別是 Vue 的構(gòu)建函數(shù)和生命周期,我們可以了解掛載過(guò)程的詳細(xì)步驟,需要的朋友可以參考下2024-11-11