因为公司需要一个特定的拖动插件 用来作为计算公式用 所以老大就让我去写了一个.
主要功能是验证公式的合法性,还有就是可拖动性. 话不多说上代码.(ui框架用的是Ant Design of Vue)
//用到了Vue 的npm install awe-dnd --save拖动插件
//注意 引用组件的时候要在main.js中注册一下组件 避免拖动无效
mainjs 代码
//import VueDND from 'awe-dnd'
//Vue.use(VueDND)
以下是实现功能代码
class="color-item"
v-for="(color,index) in colors"
v-dragging="{ item: color, list: colors, group: group}"
:key="index"
@click="selected(index,color.text)"
>
:class="{active:index==isShow}" @change="event => onChangeText(event,index)" :value="color.value" v-if="color.text == '>_'" :maxLength="6" style="width: 70px;text-align: center;" v-on:blur="changeNumFun()" /> :class="{active:index==isShow}" type="link" ghost :key="index" v-on:blur="changeNumFun()" v-else >{{color.text}}
v-for="value in variables" :value="value" @click="btn(value)" :key="value" >{{value}}
{{item.Content}}
Delete
Delete
请正确填写公式内容
import { values } from 'mockjs2'
import { consoleApplyNumByDay } from '../../api/console'
export default {
// 公式数组
props: {
formulaEle: {
type: Array
}
},
data() {
return {
// 渲染公式序列
colors: [],
// 按钮名称
btns: [
{
btn: '()',
Content: '圆括号'
},
{
btn: '+',
Content: '加'
},
{
btn: '-',
Content: '减'
},
{
btn: '*',
Content: '乘'
},
{
btn: '÷',
Content: '除'
},
{
btn: '>_',
Content: '值'
}
],
// 公式内容
texts: [],
// 选中的下标
index: -1,
// 选中的按钮内容
selectedVlaue: '',
// 下拉默认数据
variables: [
'本金'
// 'Interest'
],
backgroundColor: '',
// 存输入值
value: new Map(),
mark: 0,
values: [],
isShow: -1,
onclickRed: '',
// 整合
integrate: [],
hint: false,
markedWords: '',
group:''
}
},
watch: {
formulaEle:{
immediate:true,
handler(val){
this.colors = []
let shuzu = val;
if (shuzu && shuzu.length > 0) {
for (let i = 0; i < shuzu.length; i++) {
if (isNaN(shuzu[i])) {
this.colors.push({
text: shuzu[i],
value: ''
})
} else {
this.colors.push({
text: '>_',
value: shuzu[i]
})
}
}
this.integrate = shuzu;
}
}
},
colors:{
immediate:true,
handler(val){
}
},
backgroundColor(){},
},
created() {
// 随机数
this.group = this.randomString(8)
// 回显数据
},
mounted() {
this.$dragging.$on('dragged', ({ value }) => {
// console.log(value.item,"value.item");
// console.log(value.list,"value.list");
// console.log(value.otherData,"value.otherData");
// 取消选中 让删除按钮禁用
// 用于多个组件存在时 相互影响的问题
if(this.group!=value.group){
return;
}
this.index = -1
// 清空之前排序
this.texts = []
this.integrate = []
for (let i = 0; i < value.list.length; i++) {
this.texts.push(value.list[i].text)
// 整合表单数据
if (value.list[i].text == '>_') {
this.integrate.push(value.list[i].value)
} else {
this.integrate.push(value.list[i].text)
}
}
// 逻辑验证
this.handleCheck()
})
// 拖动结束
// this.$dragging.$on('dragend', (value) => {
// console.log(value,"拖动结束之后");
// })
},
methods: {
// 随机数 用于多个组件存在时 相互影响的问题
randomString(len) {
len = len || 32;
var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
var maxPos = $chars.length;
var pwd = '';
for (var i = 0; i < len; i++) {
pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
},
// 操作符
btn(value) {
// 添加新的操作符合变量
if (value == '()') {
this.colors.push(
{
text: '(',
value: ''
},
{
text: ')',
value: ''
}
)
this.texts.push('(', ')')
} else {
this.colors.push({
text: value,
value: ''
})
this.texts.push(value)
}
// 取消选中 让删除按钮禁用
this.index = -1
this.handleCheck()
if (value == '>_') {
this.backgroundColor = 'backgroundRed'
}
// 数据整合
this.integrate = []
for (let i = 0; i < this.colors.length; i++) {
if (this.colors[i].text == '>_') {
this.integrate.push(this.colors[i].value)
} else {
this.integrate.push(this.colors[i].text)
}
}
},
// 下拉
handleChange(value) {
// console.log(`selected ${value}`);
},
// 选中
selected(index, value) {
this.isShow = index
this.index = index
this.selectedVlaue = value
this.onclickRed = 'onclickRed'
},
// 输入的值
onChangeText(e, index) {
let str = e.target.value
let strPing = ''
// .replace(/[^-\d.]/g, ""); //清除"-","数字"和"."以外的字符
// .replace(/^[.]/, ""); //禁止第一个字符为.
// .replace("-.", ""); //禁止前两个字符为-.
// .replace(/\-{2,}/g, "-"); //只保留第一个-, 清除多余的
// .replace("-", "$##$##$")
//.replace(/\-/g, "").replace("$##$##$", "-");
// .replace(/\.{2,}/g, "."); //只保留第一个., 清除多余的
// .replace(".", "$#$").replace(/\./g, "").replace("$#$", ".");
// .replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3'); //只能输入两个小数
// .replace(/\d{4}/,'') 限制连续数字不能超过三个
//超级正则
strPing = str
.replace(/[^-\d.]/g, '')
.replace(/^[.]/, '')
.replace('-.', '')
.replace(/\-{2,}/g, '-')
.replace('-', '$##$##$')
.replace(/\-/g, '')
.replace('$##$##$', '-')
.replace(/\.{2,}/g, '.')
.replace('.', '$#$')
.replace(/\./g, '')
.replace('$#$', '.')
.replace(/^(\-)*(\d+)\.(\d\d\d).*$/, '$1$2.$2')
.replace(/\d{4}/,'')
// 此处是个坑 不能使用e.data 因为e.data的值只是获取的最后一个输入的内容 切记
this.colors[index].value = strPing
// 整合数据
this.integrate = []
for (let i = 0; i < this.colors.length; i++) {
if (this.colors[i].text == '>_') {
this.integrate.push(this.colors[i].value)
} else {
this.integrate.push(this.colors[i].text)
}
}
for (let i = 0; i < this.integrate.length; i++) {
if (this.integrate[i] == '') {
this.backgroundColor = 'backgroundRed'
if(this.backgroundColor == 'backgroundRed'){
return
}
} else {
this.backgroundColor = 'backgroundGrey'
}
}
this.handleCheck()
},
// 删除
remove() {
if (this.index != -1) {
this.colors.splice(this.index, 1)
// 取消选中 让删除按钮禁用
this.index = -1
}
// 重新获取最新公式
this.texts = []
for (let y = 0; y < this.colors.length; y++) {
this.texts.push(this.colors[y].text)
}
this.handleCheck()
this.integrate = []
for (let i = 0; i < this.colors.length; i++) {
if (this.colors[i].text === '>_') {
this.integrate.push(this.colors[i].value)
} else {
this.integrate.push(this.colors[i].text)
}
}
},
// 按钮失去焦点 取消选中 让删除按钮禁用
changeNumFun() {
setTimeout(() => {
this.index = -1
}, 100)
this.isShow = -1
this.onclickRed = ''
},
// 验证逻辑
handleCheck() {
let array = this.texts
if (!array) {
return
}
//括号对称
let parentheses_left = 0
let parentheses_right = 0
for (let j = 0; j < array.length; j++) {
let item = array[j]
if ('(' == item) {
++parentheses_left
} else if (')' == item) {
++parentheses_right
}
}
if (parentheses_left != parentheses_right) {
// 背景变红 报错
this.backgroundColor = 'backgroundRed'
return
}
//操作逻辑
for (let i = 0; i < array.length; i++) {
let item = array[i]
let prev = array[i - 1]
let next = array[i + 1]
//是变量
if (this.cehckVariable(item)) {
// 如果是变量,且处于第1位,这时,第2位如果有,不能是(和)
if (i == 0 && next && (next == '(' || next == ')')) {
// 背景变红 报错
this.backgroundColor = 'backgroundRed'
return
}
// 如果是变量,不在第1位,这时,前1位若有,不能是变量,后1位若有,不能是变量且不能是(
else {
if (prev && this.cehckVariable(prev)) {
// 背景变红 报错
this.backgroundColor = 'backgroundRed'
return
} else if (next && this.cehckVariable(next)) {
// 背景变红 报错
this.backgroundColor = 'backgroundRed'
return
} else if (next && (this.cehckVariable(next) || next == '(')) {
// 背景变红 报错
this.backgroundColor = 'backgroundRed'
return
}
}
} else {
//操作符
// 如果是操作符,且处于第1位,只能是(
if (i == 0 && item != '(') {
// 背景变红 报错
this.backgroundColor = 'backgroundRed'
return
}
// 如果是操作符,且是(,后1位如果有,只能是变量或者(
else if (item == '(' && next && !this.cehckVariable(next) && next != '(') {
// 背景变红 报错
this.backgroundColor = 'backgroundRed'
return
}
// 如果是操作符,且是),前1位如果有,只能是变量或者),后1位如果有,只能是操作符且不能是(
else if (
item == ')' &&
((prev && !this.cehckVariable(prev) && prev != ')') || (next && this.cehckVariable(next) && next != '('))
) {
// 背景变红 报错
this.backgroundColor = 'backgroundRed'
return
}
// 如果是操作符,且不是(和),前1位如果有,只能是变量或者),后1位如果有,只能是变量或者(
else if (
item != '(' &&
item != ')' &&
((prev && !this.cehckVariable(prev) && prev != ')') || (next && !this.cehckVariable(next) && next != '('))
) {
// 背景变红 报错
this.backgroundColor = 'backgroundRed'
return
}
// 如果是操作符,且处于最后1位,只能是)
else if (i == array.length - 1 && item != ')') {
// 背景变红 报错
this.backgroundColor = 'backgroundRed'
return
}
}
}
for (let i = 0; i < this.integrate.length; i++) {
if (this.integrate[i] == '') {
this.backgroundColor = 'backgroundRed'
if(this.backgroundColor == 'backgroundRed'){
return
}
} else {
this.backgroundColor = 'backgroundGrey'
}
}
// 公式正确
this.backgroundColor = 'backgroundGrey'
},
// 表单是否为空验证
inputNull(){
if(this.integrate.length > 0){
for(let i=0;i < this.integrate.length;i++){
}
}
},
// 检查是否变量
cehckVariable(value) {
if (['(', ')', '+', '-', '*', '÷'].indexOf(value) == -1) {
return true
} else {
return false
}
},
}
}
.color-list {
width: 100%;
border: 1px solid #d9d9d9;
display: flex;
flex-direction: row;
padding: 10px;
height: 45px;
align-items: center;
background: #f0f2f5;
}
.color-item {
height: 30px;
line-height: 30px;
text-align: center;
}
.button-btn {
margin-top: 2px;
margin-bottom: 5px;
}
.button-btn .btn_marke {
margin-left: 10px;
}
#backgroundRed {
background: #f3c2c4;
}
#backgroundGrey {
background: #f0f2f5;
}
.button-btn .delete_change {
display: inline-block;
margin-left: 10px;
}
/* .button-btn .ant-popover-inner-content{background-color: rgba(0, 0, 0, 0.75) !important;} */
.button-btn .ant-popover-inner-content span {
color: #fff;
}
.ant-popover-inner {
background: #fff !important;
}
.ant-popover-arrow {
background: #fff !important;
}
.delete_change .delete {
width: 32px;
padding: 0 0 !important;
}
.color-item .ant-btn:focus,
.color-item .ant-btn:active {
border: none !important;
}
.ant-btn.ant-btn-link.ant-btn-background-ghost.active {
border: 1px solid #1890ff !important;
}
.color-item .ant-btn {
border: none !important;
color: #b1afb2 !important;
}
.color-item .ant-input {
background: none;
border: none;
border-bottom: 1px solid #999;
border-radius: 0 !important;
}
.color-item .ant-input:hover {
border-bottom: 1px solid #fff;
}
#backgroundRed .ant-input {
border: none;
border-bottom: 1px solid #fff;
border-radius: 0 !important;
}
.delete_change .onclickRed {
background: #ff4d4f;
border: 1px solid white;
color: white;
}
.button-btn .ant-popover-placement-top > .ant-popover-content > .ant-popover-arrow,
.ant-popover-placement-topLeft > .ant-popover-content > .ant-popover-arrow,
.ant-popover-placement-topRight > .ant-popover-content > .ant-popover-arrow {
top: 40px !important;
}