CQU Web开发实验2 计算器 vue+ts

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 的作用

  1. 组件化开发
  • Vue 提供了组件化开发的方式,使得我们可以将计算器的各个部分(如显示屏、按钮等)封装成独立的组件,便于管理和复用。
  1. 响应式数据绑定
  • Vue 的响应式系统使得数据和视图保持同步。当数据发生变化时,视图会自动更新,反之亦然。在这个项目中,displayValuecurrentOperand 等数据的变化会自动反映在视图上。
  1. 模板语法
  • Vue 提供了简洁的模板语法,使得我们可以方便地将数据绑定到 HTML 元素上。在这个项目中,我们使用模板语法来定义按钮的点击事件和显示屏的内容。
  1. 指令和事件处理
  • Vue 提供了丰富的指令(如 v-onv-bind 等)和事件处理机制,使得我们可以轻松地处理用户交互。在这个项目中,我们使用 @click 指令来处理按钮的点击事件。

TypeScript 的作用

  1. 类型安全
  • TypeScript 是 JavaScript 的超集,提供了静态类型检查。通过使用 TypeScript,我们可以在编写代码时发现潜在的类型错误,提高代码的可靠性和可维护性。在这个项目中,我们定义了 ref 的类型,如 const displayValue = ref<string>('0');
  1. 增强的开发体验
  • TypeScript 提供了丰富的类型推断和智能提示功能,使得开发过程更加高效和愉快。在这个项目中,TypeScript 帮助我们在编写代码时获得更好的代码补全和错误提示。
  1. 接口和类型定义
  • TypeScript 允许我们定义接口和类型,使得代码更加清晰和易于理解。在这个项目中,我们定义了 operation 的类型为 string | null,确保操作符的类型安全。
  1. 模块化
  • TypeScript 支持 ES6 模块化,使得我们可以将代码拆分成多个模块,便于管理和复用。在这个项目中,我们将计算器的逻辑封装在 Calculator.vue 组件中,并在 App.vue 中引入和使用。

总结

  • Vue 提供了强大的前端框架,使得我们可以方便地进行组件化开发、响应式数据绑定和事件处理。
  • TypeScript 提供了静态类型检查和增强的开发体验,使得代码更加可靠和易于维护。

通过结合 Vue 和 TypeScript,我们可以构建一个功能强大、类型安全且易于维护的计算器应用。

7、代码仓库

https://github.com/mozhongzhou/vue-ts-project-total

本技术内容仅供学习和交流使用,如有疑问请联系qq2014160588并注明来意。请确保在使用过程中遵守相关法律法规。任何因使用本技术内容而导致的直接或间接损失,作者概不负责。用户需自行承担因使用本技术内容而产生的所有风险和责任。请勿将本技术内容用于任何非法用途。
上一篇
下一篇