1、新建项目
vscode 导航到 VUE+TS项目目录
ctrl+shift+~打开终端
npm create vue@latest
#命名项目为vue-ts-project2-calculator
cd vue-ts-project2-calculator
npm install
2、编写代码创建计算机组件并编写计算器逻辑
在 src/components
目录下创建一个名为 Calculator.vue
的文件,并编写计算器组件的代码。
在 Calculator.vue
中编写计算器的逻辑,包括显示屏、按钮和计算功能。
<template>
<div class="calculator-container">
<div class="calculator" @keydown="handleKeydown" tabindex="0">
<div class="display">{{ displayValue }}</div>
<div class="history">
<div v-for="(entry, index) in history" :key="index" class="history-entry">
{{ entry.expression }} = {{ entry.result }}
</div>
</div>
<div class="buttons">
<button @click="clear">C</button>
<button @click="appendNumber('7')">7</button>
<button @click="appendNumber('8')">8</button>
<button @click="appendNumber('9')">9</button>
<button @click="appendOperation('/')">/</button>
<button @click="appendNumber('4')">4</button>
<button @click="appendNumber('5')">5</button>
<button @click="appendNumber('6')">6</button>
<button @click="appendOperation('*')">*</button>
<button @click="appendNumber('1')">1</button>
<button @click="appendNumber('2')">2</button>
<button @click="appendNumber('3')">3</button>
<button @click="appendOperation('-')">-</button>
<button @click="appendNumber('0')">0</button>
<button @click="appendNumber('.')">.</button>
<button @click="compute">=</button>
<button @click="appendOperation('+')">+</button>
<button @click="appendOperation('^')">^</button>
<button @click="appendOperation('√')">√</button>
<button @click="appendOperation('(')">(</button>
<button @click="appendOperation(')')">)</button>
</div>
</div>
<div class="memo">
<h3>Memo</h3>
<ul>
<li v-for="(entry, index) in memo" :key="index">{{ entry.expression }} = {{ entry.result }}</li>
</ul>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue';
export default defineComponent({
name: 'Calculator',
setup() {
const displayValue = ref('0');
const expression = ref('');
const history = ref<{ expression: string, result: string }[]>([]);
const memo = ref<{ expression: string, result: string }[]>([]);
const clear = () => {
displayValue.value = '0';
expression.value = '';
};
const appendNumber = (number: string) => {
if (number === '.' && expression.value.slice(-1) === '.') return;
expression.value += number;
displayValue.value = expression.value;
};
const appendOperation = (op: string) => {
if (op === '-' && (expression.value === '' || /[\+\-\*\/\(\^√]$/.test(expression.value))) {
expression.value += '-';
displayValue.value = expression.value;
return;
}
if (op === '(' && /[\d\)]$/.test(expression.value)) {
expression.value += '*(';
} else if (op === ')' && /[\+\-\*\/\(\^√]$/.test(expression.value)) {
return;
} else if (/[\+\-\*\/\(\^√]$/.test(expression.value) && op !== '(') {
return;
} else if (op === '√') {
expression.value += 'Math.sqrt(';
} else {
expression.value += op;
}
displayValue.value = expression.value;
};
const compute = () => {
try {
// 使用 eval 计算表达式,替换 ^ 为 JavaScript 可识别的操作
const result = eval(expression.value.replace(/\^/g, '**'));
displayValue.value = result.toString();
// 将表达式和结果添加到历史记录和备忘录
history.value.push({ expression: expression.value, result: result.toString() });
memo.value.push({ expression: expression.value, result: result.toString() });
expression.value = result.toString();
} catch (e) {
displayValue.value = 'Error';
expression.value = '';
}
};
const handleKeydown = (event: KeyboardEvent) => {
const key = event.key;
if (!isNaN(Number(key))) {
appendNumber(key);
} else if (key === '.') {
appendNumber(key);
} else if (key === '+' || key === '-' || key === '*' || key === '/' || key === '^' || key === '√' || key === '(' || key === ')') {
appendOperation(key);
} else if (key === 'Enter' || key === '=') {
compute();
} else if (key === 'Backspace') {
clear();
}
};
onMounted(() => {
const calculatorElement = document.querySelector('.calculator') as HTMLElement;
if (calculatorElement) {
calculatorElement.focus();
}
});
return {
displayValue,
clear,
appendNumber,
appendOperation,
compute,
handleKeydown,
history,
memo,
};
},
});
</script>
<style scoped>
.calculator-container {
display: flex;
justify-content: center;
align-items: flex-start;
margin-top: 50px;
}
.calculator {
display: flex;
flex-direction: column;
align-items: center;
outline: none;
}
.display {
width: 260px;
height: 60px;
background: #222;
color: white;
font-size: 2em;
text-align: right;
padding: 10px;
box-sizing: border-box;
margin-bottom: 10px;
}
.history {
width: 260px;
background: #f0f0f0;
color: #333;
font-size: 1em;
text-align: right;
padding: 10px;
box-sizing: border-box;
margin-bottom: 10px;
max-height: 100px;
overflow-y: auto;
}
.history-entry {
margin-bottom: 5px;
}
.buttons {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
}
button {
width: 60px;
height: 60px;
font-size: 1.5em;
background: #f0f0f0;
border: none;
cursor: pointer;
}
button:active {
background: #ccc;
}
.memo {
margin-left: 20px;
width: 300px; /* 调整宽度 */
}
.memo h3 {
margin: 0;
padding: 0;
}
.memo ul {
list-style-type: none;
padding: 0;
}
.memo li {
background: #f0f0f0;
margin-bottom: 5px;
padding: 5px;
border-radius: 3px;
}
</style>
3、在主应用中使用计算器组件
在 src/App.vue
中引入并使用 Calculator
组件。
<template>
<div id="app">
<Calculator />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import Calculator from './components/Calculator.vue';
export default defineComponent({
name: 'App',
components: {
Calculator,
},
});
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
4、运行项目
npm run dev
5、备忘录
在这个项目中,Vue 和 TypeScript 各自起到了不同的作用,它们共同协作来构建一个功能强大且类型安全的计算器应用。
Vue 的作用
- 组件化开发:
- Vue 提供了组件化开发的方式,使得我们可以将计算器的各个部分(如显示屏、按钮等)封装成独立的组件,便于管理和复用。
- 响应式数据绑定:
- Vue 的响应式系统使得数据和视图保持同步。当数据发生变化时,视图会自动更新,反之亦然。在这个项目中,
displayValue
、currentOperand
等数据的变化会自动反映在视图上。
- 模板语法:
- Vue 提供了简洁的模板语法,使得我们可以方便地将数据绑定到 HTML 元素上。在这个项目中,我们使用模板语法来定义按钮的点击事件和显示屏的内容。
- 指令和事件处理:
- Vue 提供了丰富的指令(如
v-on
、v-bind
等)和事件处理机制,使得我们可以轻松地处理用户交互。在这个项目中,我们使用@click
指令来处理按钮的点击事件。
TypeScript 的作用
- 类型安全:
- TypeScript 是 JavaScript 的超集,提供了静态类型检查。通过使用 TypeScript,我们可以在编写代码时发现潜在的类型错误,提高代码的可靠性和可维护性。在这个项目中,我们定义了
ref
的类型,如const displayValue = ref<string>('0');
。
- 增强的开发体验:
- TypeScript 提供了丰富的类型推断和智能提示功能,使得开发过程更加高效和愉快。在这个项目中,TypeScript 帮助我们在编写代码时获得更好的代码补全和错误提示。
- 接口和类型定义:
- TypeScript 允许我们定义接口和类型,使得代码更加清晰和易于理解。在这个项目中,我们定义了
operation
的类型为string | null
,确保操作符的类型安全。
- 模块化:
- TypeScript 支持 ES6 模块化,使得我们可以将代码拆分成多个模块,便于管理和复用。在这个项目中,我们将计算器的逻辑封装在
Calculator.vue
组件中,并在App.vue
中引入和使用。
总结
- Vue 提供了强大的前端框架,使得我们可以方便地进行组件化开发、响应式数据绑定和事件处理。
- TypeScript 提供了静态类型检查和增强的开发体验,使得代码更加可靠和易于维护。
通过结合 Vue 和 TypeScript,我们可以构建一个功能强大、类型安全且易于维护的计算器应用。