唠唠叨叨
对不起我有罪!!!!! 在草稿箱发现好多没填好的坑,一篇也发不了,我竟然断更都这么长时间了!! 【跪】俺有罪......
所以先整这个比较好整的先输出一篇~(整整六个月没更新,我的良心也痛!)
HTML代码
JavaScript
<div class="ml-50 calculator">
<div class="result" style="grid-area: result">{{ state.equation }}</div>
<el-button style="grid-area: ac" @click="clear">AC</el-button>
<el-button style="grid-area: plus-minus" @click="calculateToggle">±</el-button>
<el-button style="grid-area: percent" @click="calculatePercentage">%</el-button>
<el-button style="grid-area: add" @click="append('+')">+</el-button>
<el-button style="grid-area: subtract" @click="append('-')">-</el-button>
<el-button style="grid-area: multiply" @click="append('×')">×</el-button>
<el-button style="grid-area: divide" @click="append('÷')">÷</el-button>
<el-button style="grid-area: equal" @click="calculate">=</el-button>
<el-button style="grid-area: number-1" @click="append(1)">1</el-button>
<el-button style="grid-area: number-2" @click="append(2)">2</el-button>
<el-button style="grid-area: number-3" @click="append(3)">3</el-button>
<el-button style="grid-area: number-4" @click="append(4)">4</el-button>
<el-button style="grid-area: number-5" @click="append(5)">5</el-button>
<el-button style="grid-area: number-6" @click="append(6)">6</el-button>
<el-button style="grid-area: number-7" @click="append(7)">7</el-button>
<el-button style="grid-area: number-8" @click="append(8)">8</el-button>
<el-button style="grid-area: number-9" @click="append(9)">9</el-button>
<el-button style="grid-area: number-0" @click="append(0)">0</el-button>
<el-button style="grid-area: dot" @click="append('.')">.</el-button>
<el-button style="grid-area: del" @click="onDelete"><el-icon><Delete /></el-icon></el-button>
</div>
在页面中自定义一块区域,放上你需要在计算器中展示的按钮以及计算器的显示屏。 此处我们放置的是最基础的正负号、四则运算符号,以及AC清除、百分号、小数点和单个删除键,显示屏则是定义一个div。
实现效果
初始完成效果:
如图所示,我们在html中编写的按钮以及显示屏初步展示出来了,但是我们此时并无法通过它们完成任何操作,显示屏也只是我们最初默认设置的0。
(我知道很简陋啦)
因此接下来我们要在script中创建每个按钮的点击事件,把显示屏中的结果在state中定义一下,初始状态为0。 这里我还定义了方法中会用到的三个判断boolean值,初始状态均为false。
JS代码
定义响应式参数
javascript
const state = reactive({
equation: "0",
isOperatorAdded: false,
isDecimalAdded: false,
isStarted: false,
})
1.判断输入为四则运算符:
javascript
//输入+ - x /
const isOperator = (character) => {
return ["+", "-", "×", "÷"].indexOf(character) > -1;
}
2.运算符和数字放入显示屏:
javascript
const append = (character) => {
if (state.equation.length >= 10) {
alert("超出长度限制");
clear();
return;
}
//首次输入时不为操作符
if (state.equation === "0" && !isOperator(character)) {
if (character === ".") {
state.equation += "" + character; //引号的作用将其转换成字符串
state.isDecimalAdded = true;
} else {
state.equation = "" + character;
}
state.isStarted = true;
return;
}
//if NUmber
if (!isOperator(character)) {
//防止连续输入.
if (character === "." && state.isDecimalAdded) {
return;
}
if (character === ".") {
state.isDecimalAdded = true;
state.isOperatorAdded = true;
} else {
state.isOperatorAdded = false;
}
state.equation += "" + character;
}
//Add Operator
if (isOperator(character) && !state.isOperatorAdded) {
state.equation += "" + character;
state.isDecimalAdded = false;
state.isOperatorAdded = true;
}
}
3.点击=号时的算式计算:
javascript
//=
const calculate = () => {
let result = state.equation
.replace(new RegExp("×", "g"), "*")
.replace(new RegExp("÷", "g"), "/");
state.equation = parseFloat(eval(result).toFixed(9)).toString();
state.isDecimalAdded = false;
state.isOperatorAdded = false;
}
4.点击正负号后的运算:
javascript
/正负号+/-
const calculateToggle = () => {
if (state.isOperatorAdded || !state.isStarted) {
return;
}
state.equation = state.equation + "* -1";
calculate();
}
5.点击百分号后的运算:
javascript
//%
const calculatePercentage = () => {
if (state.isOperatorAdded || !state.isStarted) {
return;
}
state.equation = state.equation + "* 0.01";
calculate();
}
6..清除按钮:
javascript
//AC
const clear = () => {
state.equation = "0"
state.isDecimalAdded = false
state.isOperatorAdded = false
state.isStarted = false
}
7.单个字符删除的运算:
javascript
/Del退格
const onDelete = () => {
state.equation = state.equation.substring(0,state.equation.length-1);
if (state.equation.length == 0) {
state.equation = 0
}
}
那么经过这些方法的运算,一个有着基本功能的计算器就初具雏形了,我们还可以根据自己的需要定制我们需要的符号,比如"("、")"、e、log、ln等。 我这边是由于项目需求定制了"("、")"和tag列表。
界面展示
算式:
结果:
百分号:
AC清除:
CSS实现
但是看起来是不是不太对劲,虽然看着功能实现了,但是样子看起来确实是差强人意,太丑了! 因此我们需要运用到css的样式和布局来给我们的计算器装修一番。我们在html中给显示屏以及各个按钮放上了style绑定了独一无二的grid-area属性。 在外部容器和显示屏的div中也绑定了样式类名。 grid-area 属性指定网格元素在网格布局中的大小和位置。 比如以下的例子: 以下实例 item1 命名为 "myArea", 并跨越五列: 实例
JavaScript
.item1 { grid-area: myArea; }
.grid-container { grid-template-areas: 'myArea myArea myArea myArea myArea'; }
实现代码
可以看到item1所占的列数为5列。
JavaScript
.calculator {
--el-button-width: 80px;
--el-button-height: 60px;
display: grid; //网格布局
grid-template-areas:
"result result result result"
"ac plus-minus percent divide"
"number-7 number-8 number-9 multiply"
"number-4 number-5 number-6 subtract"
"number-1 number-2 number-3 add"
"number-0 dot equal del";
grid-template-columns: repeat(4, var(--el-button-width)); //repeat向xx方向重复数量
grid-template-rows: repeat(5, var(--el-button-height));
box-shadow: -8px -8px 16px -10px rgb(71, 66, 66),
8px 8px 16px -10px rgba(0, 0, 0, 0.15);
padding: 24px;
border-radius: 20px; //圆角边框弧度
.el-button {
margin: 8px;
padding: 0;
border: 0;
display: block;
outline: none;
border-radius: calc(var(--el-button-height) / 2);
font-size: 24px;
font-family: Helvetica;
color: #999;
background: linear-gradient( //linear-gradient()函数:渐变颜色
135deg,
rgba(230, 230, 230, 1) 0%,
rgba(246, 246, 246, 1) 100%
);
box-shadow: -4px -4px 10px -8px rgba(255, 255, 255, 1), //阴影
4px 4px 10px -8px rgba(0, 0, 0, 0.3);
}
.el-button:active {
box-shadow: -4px -4px 10px -8px rgb(255, 255, 255, 1) inset,
4px 4px 10px -8px rgba(0, 0, 0, 0.3) inset;
}
}
.result {
text-align: right;
line-height: 60px;
font-size: 48px;
font-family: Arial, Helvetica, sans-serif;
padding: 0 20px; //填充边距:上下0 左右20
color: rgb(194, 190, 190);
background: linear-gradient(
135deg,
rgb(156, 131, 131) 0%,
rgb(96, 100, 143) 100%
);
}
实现效果
总结和完整代码
经过一系列进化和调整,我把之前的代码bug修复了一番并且根据需求和设计美化了一下俺滴计算器。 以下就是这个计算器组件的完整代码和展示样式。
javascript
<template>
<el-dialog
v-model="popVisible"
:title="id ? '公式编辑器(编辑)' : '公式编辑器'"
width="900px"
:close-on-click-modal="false"
:before-close="onCancel"
><el-row>
<el-col :span="state.span">
<el-form ref="ruleFormRef" :rules="rules" :model="formObj" label-width="auto" class="ml-20 pr-10" label-position="left">
<el-form-item label="label1" prop="value1">
<el-select v-model="formObj.value1" minlength="2" maxlength="20" show-word-limit placeholder="请选择名称" style="width:240px; padding: 0 20px;" disabled>
<el-option v-for="item in state.typeList" :key="item.id" :label="item.label" :value="item.value" />
</el-select>id
</el-form-item>
<el-form-item label="label2" prop="value2">
<el-input v-model="formObj.value2" disabled style="width:240px; padding: 0 20px;"/>
</el-form-item>
<el-form-item :label="state.label">
<el-button v-if="state.label" type="primary" @click="onEdit1">编辑{{state.label}}</el-button>
</el-form-item>
<div class="clappp mt-5">
{{ formObj.aniCN }}
</div>
<el-form-item label="label3">
<el-button type="primary" @click="onEdit2">编辑标准公式</el-button>
</el-form-item>
<div class="clappp mt-5">
{{ formObj.bniCN }}
</div>
<div class="ml-20 mt-5"
style="font-size: 8px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #CE2E2E;
line-height: 15px;"
>
<h5>*公式计算器使用说明:</h5>
<p>点击编辑按钮=》在计算器中输入自定义公式=》点击等于号=》点击修改=》提交成功</p>
</div>
</el-form>
</el-col>
<el-col :span="state.span">
<div class="ml-50 mr-50 calculator">
<div class="result" style="grid-area: result">{{ state.equation }}</div>
<el-button style="grid-area: ac" @click="clear">AC</el-button>
<!-- <el-button style="grid-area: plus-minus" @click="calculateToggle">±</el-button> -->
<!-- <el-button style="grid-area: percent" @click="calculatePercentage">%</el-button> -->
<el-button style="grid-area: l-bracket" @click="append('(','(')">(</el-button>
<el-button style="grid-area: r-bracket" @click="append(')',')')">)</el-button>
<el-button style="grid-area: divide" @click="append('/','/')">/</el-button>
<div class="tag-list" style="grid-area: tag-list">
<el-tag
v-for="tag in state.tagList"
:key="tag.id"
:value="tag.sign"
class="tag-style cursor-pointer"
:checked="state.checked"
@click="append(tag.name,tag.sign)"
>
{{ tag.name }}
</el-tag>
</div>
<el-button style="grid-area: add" @click="append('+','+')">+</el-button>
<el-button style="grid-area: subtract" @click="append('-','-')">-</el-button>
<el-button style="grid-area: multiply" @click="append('*','*')">*</el-button>
<el-button style="grid-area: number-1" @click="append(1,1)">1</el-button>
<el-button style="grid-area: number-2" @click="append(2,2)">2</el-button>
<el-button style="grid-area: number-3" @click="append(3,3)">3</el-button>
<el-button style="grid-area: number-4" @click="append(4,4)">4</el-button>
<el-button style="grid-area: number-5" @click="append(5,5)">5</el-button>
<el-button style="grid-area: number-6" @click="append(6,6)">6</el-button>
<el-button style="grid-area: number-7" @click="append(7,7)">7</el-button>
<el-button style="grid-area: number-8" @click="append(8,8)">8</el-button>
<el-button style="grid-area: number-9" @click="append(9,9)">9</el-button>
<el-button style="grid-area: number-0" @click="append(0,0)">0</el-button>
<el-button style="grid-area: dot" @click="append('.','.')">.</el-button>
<el-button style="grid-area: equal;" @click="calculate">=</el-button>
<!-- <el-button style="grid-area: del" @click="onDelete"><el-icon><Delete /></el-icon></el-button> -->
</div>
</el-col>
</el-row>
<!-- <el-alert class="mt-5" title="公式计算器使用说明" type="warning" show-icon>
点击编辑按钮=》在计算器中输入自定义公式=》点击等于号=》点击修改=》提交成功
</el-alert> -->
<template #footer>
<span class="dialog-footer">
<el-button @click="onCancel">取消</el-button>
<el-button type="primary" @click="onCommit">修改</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { reactive, getCurrentInstance, watch, computed, ref, onMounted } from "vue";
import { WarningFilled, Plus, Search, Delete } from '@element-plus/icons-vue'
import { ElMessage } from "element-plus";
import { ApiConstant } from '@/constants/ApiConstant/index.js'
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
id: {
type: [Number, String],
default: null,
},
})
const emit = defineEmits(["close", "getData"])
const { proxy } = getCurrentInstance();
const state = reactive({
checked: false,
span: 12,
equation: "0",
label: '',
isDecimalAdded: false,
isOperatorAdded: false,
isStarted: false,
tagList: [],
typeList: [],
ani: false,
bni: false,
formula: "0"
});
const popVisible = computed(() => props.visible);
const id = computed(() => props.id);
const formObj = reactive({
id: props.id,
value1: '',
value2: '',
aniCN: '',
bniCM: '',
ani: '',
bni: '',
});
const rules = reactive({
ani: [
{
required: true,
message: "请配置公式",
trigger: "blur",
},
],
bni: [
{
required: true,
message: "请配置公式",
trigger: "change",
},
],
pointFormula: [
{
required: true,
message: "请选择",
trigger: "change",
},
],
onlyOnce: [
{
type: "array",
required: true,
message: "请勾选至少一个",
trigger: "change",
},
],
});
const onEdit1 = () => {
state.ani= true
state.bni= false
state.equation = formObj.aniCN
state.formula = formObj.ani
}
const onEdit2 = () => {
state.bni= true
state.ani = false
state.equation = formObj.bniCN
state.formula = formObj.bni
}
const onCancel = () => {
proxy.$refs.ruleFormRef.resetFields();
emit("close");
};
const onCommit = () => {
console.log(formObj);
proxy.$refs.ruleFormRef.validate((valid) => {
if (valid) {
if (props.id) {
proxy.$axios.post(`${ url }/update`, formObj)
.then((res) => {
let resq = res.data;
if (resq.code == 0) {
ElMessage.success("修改成功");
onCancel()
emit("getData");
} else {
ElMessage.error(resq.msg);
}
});
}
}
});
};
const resetForm = () => {
proxy.$refs.ruleFormRef.resetFields();
};
//输入+ - x /
const isOperator = (character) => {
return ["+", "-", "*", "/"].indexOf(character) > -1;
}
//输入tag
const isTags = (character) => {
return (/[^\u4E00-\u9FA5]/g).indexOf(character) > -1;
}
// operators or Numbers
const append = (character,x) => {
console.log(character,x);
if (state.equation.length >= 100) {
alert("超出长度限制");
clear();
return;
}
//首次输入时不为操作符
if (state.equation === "0" && !isOperator(character)) {
if (character === ".") {
state.equation += "" + character; //引号的作用将其转换成字符串
state.formula += "" + x
state.isDecimalAdded = true;
} else {
state.equation = "" + character;
state.formula = "" + x;
}
state.isStarted = true;
return;
}
//if NUmber
if (!isOperator(character)) {
//防止连续输入.
if (character === "." && state.isDecimalAdded) {
return;
}
if (character === ".") {
state.isDecimalAdded = true;
state.isOperatorAdded = true;
} else {
state.isOperatorAdded = false;
}
state.equation += "" + character;
state.formula += "" + x
}
//Add Operator
if (isOperator(character) && !state.isOperatorAdded) {
state.equation += "" + character;
state.formula += "" + character;
state.isDecimalAdded = false;
state.isOperatorAdded = true;
}
}
//=
const calculate = () => {
// let result = state.equation
// .replace(new RegExp("*", "g"), "*")
// .replace(new RegExp("/", "g"), "/");
// state.equation = parseFloat(eval(result).toFixed(9)).toString();
// state.isDecimalAdded = false;
// state.isOperatorAdded = false;
if (state.ani) {
formObj.aniCN = state.equation
formObj.ani = state.formula
} else if (state.bni) {
formObj.bniCN = state.equation
formObj.bni = state.formula
}
}
//正负号+/-
const calculateToggle = () => {
if (state.isOperatorAdded || !state.isStarted) {
return;
}
state.equation = state.equation + "* -1";
state.formula = state.formula + "* -1";
calculate();
}
//%
const calculatePercentage = () => {
if (state.isOperatorAdded || !state.isStarted) {
return;
}
state.equation = state.equation + "* 0.01";
state.formula = state.formula + "* 0.01";
calculate();
}
//AC
const clear = () => {
state.equation = "0"
state.formula = "0"
state.isDecimalAdded = false
state.isOperatorAdded = false
state.isStarted = false
}
//Del退格
const onDelete = () => {
state.equation = state.equation.substring(0,state.equation.length-1);
if (state.equation.length == 0) {
state.equation = 0
}
state.formula = state.formula.substring(0,state.formula.length-1);
if (state.formula.length == 0) {
state.formula = 0
}
}
const getSelect = () => {
proxy.$axios.get(`${ url }/param`)
.then((res) => {
let resq = res.data;
if (resq.code == 0) {
state.tagList = resq.data
} else {
ElMessage.error(resq.msg);
}
});
let params={
current: 1,
size: 9999
}
proxy.$axios.post(`${ url }/get-page`,params)
.then((res) => {
let resq = res.data
if(resq.code == 0){
state.typeList=resq.data.records
state.typeList.map((item) => {
if (item.value1== formObj.value) {
formObj.label1 = item.label
}
})
}else{
ElMessage.error(resq.msg)
}
});
}
const tryOut = (row) => {
var str = row;
var arrayElement = []
for (var i = 0; i < state.tagList.length ; i++) {
arrayElement.push([state.tagList[i].sign, state.tagList[i].name], [0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9]);
}
var lookup = arrayElement.reduce(function(acc, arr) {
acc[arr[0]] = arr[1];
return acc;
}, {});
var res = str.replace(/[A-Za-z_]+/g, function(m) {
return " " + lookup[m] + " ";
}).trim();
return res
}
watch(() => {
state.equation = 0
state.formula = 0
return props.visible;
},(newVal) => {
if (newVal) {
getSelect()
if (props.id) {
// 根据id查询
proxy.$axios.get(`${ url }/detail?id=${props.id}`)
.then((res) => {
let resq = res.data;
if (resq.code == 0) {
Object.assign(formObj , resq.data)
} else {
ElMessage.error(resq.msg);
}
});
}
}
});
onMounted(() => {
getSelect()
});
</script>
<style lang="scss" scoped>
.calculator {
--el-button-width: 70px;
--el-button-height: 45px;
display: grid;
grid-template-areas:
"result result result result"
"result result result result"
"tag-list tag-list tag-list tag-list"
"tag-list tag-list tag-list tag-list"
"tag-list tag-list tag-list tag-list"
"ac l-bracket r-bracket divide"
"number-7 number-8 number-9 multiply"
"number-4 number-5 number-6 subtract"
"number-1 number-2 number-3 add"
"number-0 dot equal equal";
grid-template-columns: repeat(4, var(--el-button-width));
grid-template-rows: repeat(6, var(--el-button-height));
padding: 20px;
border-radius: 11px;
border: 2px solid #3C5EB3;
.el-button {
margin: 8px;
padding: 0;
border: 0;
display: block;
outline: none;
border-radius: 3px;
font-size: 15px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 20px;
background: #F0F0F0;
border-radius: 3px;
box-shadow: -4px -4px 10px -8px rgba(255, 255, 255, 1),
4px 4px 10px -8px rgba(0, 0, 0, 0.3);
}
.tag-list{
.tag-style{
margin: 5px;
width: 83px;
height: 24px;
font-size: 9px;
font-size: 9px;
justify-content: center;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3C5EB3;
line-height: 13px;
}
}
.el-button:active {
box-shadow: -4px -4px 10px -8px rgb(255, 255, 255, 1) inset,
4px 4px 10px -8px rgba(0, 0, 0, 0.3) inset;
}
}
.clappp{
margin: 20px;
padding: 10px;
width: 90%;
height: 94px;
text-align: right;
font-size: 8px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3C5EB3;
line-height: 16px;
background: #EFEFEF;
}
.result {
text-align: right;
font-size: 20px;
margin-bottom: 5px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3C5EB3;
line-height: 28px;
padding: 0 20px;
background: #F1F5FF;
border-radius: 3px;
}
</style>
调整后完成效果: