使用Vue创建计算器

发布于 大漠

学习Vue有一段时间了,但真正的实战并不是很多。师父告诉我,要学好就得多动手。为了能把动手写的案例有一个集中的地方放置,我在Github上创建了一个仓库**VueStudy**。这里将会不断的添加一些练习过的案例,如果你感兴趣的话,欢迎提交你写过的案例。

今天我们来写一个案例:使用Vue创建计算器Github有对应的示例代码。如果你想在本地运行,看到对应的效果,可以把这个项目下载到你的本地,然后进入对应的目录,执行下面的命令:

npm i
npm run dev

然后在浏览器地址中输入http://localhost:8080就能看到了。接下来我们来看看怎么用Vue创建这个计算器。

今天的目标

今天的目标,就是使用Vue做一个计算器,如下图所示:

使用Vue创建计算器

这个计算器我们有两个版本,一个简单版本:

使用Vue创建计算器

另一个是高级版本:

使用Vue创建计算器

当我们使用Vue把计算器做好之后,可以帮你执行一些任务。而通过这个教程,可以学到Vue一些相关知识:

  • 处理用户输入
  • 使用模板语法将数据渲染到DOM
  • 熟悉处理数据的基本指令
  • 创建Vue实例

一些准备工作

虽然说我们这里是使用Vue来创建一个计算器,但始终还是脱离不开JavaScript方面的知识。也就是说,有关于计算器功能方面的实现,还是需要通过JavaScript来实现。如果你和我一样,JavaScript知识比较单薄的话,建议先补充一些有关这方面的知识。个人建议你可以看看@dunizb写的一个计算器,或者学习一下math.js库中的一些知识。接下来的内容假设你已经对这方面有所了解,可以使用JavaScript完成计算器相关的知识。

回到Vue的世界中来。使用Vue创建计算器,也相当于我们开始一个新项目,那么在Vue中,创建这样的项目有多种方式。或者说创建我们的计算器有多种方式。比如前面《Vue的运行环境》文中提到的。可以在一个单独的文件中使用Vue,也可以在在线的Codepen中创建。不过我们今天采用的是一种新的方式,采用Vue官方提供的项目构建工程Vue CLI

要正常使用Vue CLI得先确保你的环境中已经安装了Node和NPM。然后在你的命令终端执行:

npm i vue-cli -g

也就是在本地电脑中全局安装Vue CLI。假设你按上面的命令已成功安装好了,那么接下来通过其构建我们需要的Vue项目。

进入你的工作环境,然后执行:

vue init webpack vue-calculator

这样我们就创建了vue-calculator项目,然后进入这个项目,安装项目所需的依赖关系:

cd vue-calculator
npm i

这样在你的本地,可以看到项目对应的目录结构:

使用Vue创建计算器

而且项目所需要的依赖关系都在package.json文件中。接下来运行:

npm run dev

在浏览器中运行http://localhost:8080/就可以浏览项目的效果。

Vue项目

通过Vue CLI构建的Vue项目,其入口文件是main.js。在这个文件中引入Vue和创建Vue实例:

import Vue from 'vue'
import App from './App'

new Vue({
    el: '#app',
    template: '<App/>',
    components: { App }
})

上面的代码是引入了vue和一个App组件,然后通过下面的方式创建了一个Vue实例,然后将Vue控制的部分视图挂载在el属性上进行跟踪。而el属性值对应的是index.html文件中的div#app元素:

<div id="app>
    <!-- HTML都将会塞到这里 -->
</div>

创建Vue组件

我们的目标是创建一个计算器,那么我们把这个计算器称作Vue的一个组件。所以我们首要的条件就是先创建一个组件,我们这里一个叫calculator组件。在项目中,进入/src/components目录中创建一个calculator.vue文件。我们有关于计算器相关的东西都将放在这个文件中。他的格式一般如下:

<template>
    <div>
        <!-- 需要用一个容器包裹组件中用到的所有元素 -->
    </div>
</tempalte>

<script>
    export default {
        // 逻辑代码写在这
    }
</script>

<style>
    /* 组件样式写在这里 */
</sytle>

也就是说一个组件包含三个部分:

  • <template>:用来放置组件相关的模板
  • <script>:用来放置组件逻辑相关的代码,通过export default{}输出
  • <style>:用来放置组件相关的样式

创建组件之后,在App.vue中引入创建好的组件:

<template>
    <div id="app">
        <Calculator />
    </div>
</template>

<script>
    import Calculator from './components/calculator'

    export default {
        name: 'app',
        components: {
            Calculator
        }
    }
</script>

<style>
    // ....
</style>

这样整个链路就通了。当然,现在这个时候,你在浏览器中还看不到任何的东西。那是因为我们的calculator.vue中还未写任何有关于组件相关的东西。接下来我们就专心写组件相关的东西。

添加计算器需要的元素

计算器首先需要一个输入屏,在这里使用input来表示。而他的功能是,用户点击计算器中的按钮时,input中对应的value值会有更新。这需要使用到前面所介绍的v-model指令进行数据双向绑定。在input元素中通过v-model绑定data数据对象中的current属性:

<div class="results">
    <input class="input" v-model="current">
</div>

视图绑定的值存储在data对象中,如下所示:

export default {
    name: 'Calculator',
    data () {
        return{ 
            current: ''
        }
    }
}

接下来我们需要给计算器添加按钮。这里我们使用button元素来做。

<button class="button">7</button>

在Vue中,允许我们在实例中创建方法,提供无缝的事件处理和状态更改触发器。我们可以通过v-on(简写@)指令在我们的HTML中元素绑定对应的事件。在这里我们使用的是click事件,而这个事件绑定的是一个叫press的方法:

<button class="button" @click="press">7</button>

对应的脚本中,添加methods方法:

export default {
    name: 'Calculator',
    data () {
        return{ 
            current: ''
        }
    },
    methods: {
        press: function(event) {
            // 计算器按钮的click事件
        }
    }
}

methods中我们添加了press函数,这个函数将处理计算器按钮的点击的一些事情。具体做些什么事情,咱们先别说,后面的内容将会完善这部分。

文章开头提到过,我们的计算器分为两个部分,一个是简易版的计算器,另一个是高级版的计算器。在Vue中我们可以通过v-if(当然也可以使用v-show)来判断显示哪个版本。这个时候需要在data中创建一个changeMode属性,当这个属性的值为true时显示简易版计算器,反则为false时显示高级版本计算器。

<div class="mode" v-if="changeMode">
    <!-- 简易版本计算器 -->
    <button class="button" @click="press">7</button>
    ...
    <button class="button equal-sign" @click="press">=</button>  
</div>
<div class="mode" v-else>
    <!-- 高级版本计算器 -->
    <button class="button" @click="press">7</button>
    ...
    <button class="button equal-sign" @click="press">=</button>  
</div>

export default {
    name: 'Calculator',
    data () {
        return{ 
            current: '',
            changeMode: true
        }
    },
    methods: {
        press: function(event) {
            // 计算器按钮的click事件
        }
    }
}

这个时候,我们需要一个类似button一样的东东,能触发显示哪个版本的计算器:

<button @click="changeModeEvent" class="toggle-button">
    <p v-if="changeMode">Show Advanced Mode &nbsp; &nbsp; &#9864;</p>
    <p v-else>Show Basic Mode &nbsp; &nbsp; &#9862;</p>
</button>

同样的,在button上通过v-on绑定changeModeEvent方法,这个方法主要任务就是修改changeMode的值。这个方法和press方法一样,都将放置在methods:{}中。这个时候你看到的效果如下:

上面我们看到的是简易版本的效果。如果app.changeMode换成false时,看到的是高级版本的。

使用Vue创建计算器

没有样式,看得实在难受。这个时候在<style>中添加样式,我们的计算器就会好看得多:

添加JavaScript

现在万事都具备了,就欠东风了。为了更好的完善计算器功能,在Vue中methods:{}中的presschangeModeEvent中添加对应的功能代码:

export default {
    name: 'Calculator',
    data () {
        return{ 
        current: '',
        changeMode: true
        }
    },
    methods: {
        press: function (event) {
            let me = this
            let key = event.target.textContent

            if (
                key != '=' && 
                key != 'C' &&
                key != '*' &&
                key != '/' &&
                key != '√' &&
                key != "x ²" &&
                key != "%" &&
                key != "<=" && 
                key != "±" && 
                key != "sin" && 
                key != "cos" && 
                key != "tan" && 
                key != "log" && 
                key != "ln" && 
                key != "x^" && 
                key != "x !" && 
                key != "π" && 
                key != "e" && 
                key != "rad" && 
                key != "∘"
            ) {
                me.current += key
                
            } else if (key === '=') {
                
                if ((me.current).indexOf('^') > -1) {
                    let base = (me.current).slice(0, (me.current).indexOf('^'))
                    let exponent = (me.current).slice((me.current).indexOf('^') + 1)
                    me.current = eval('Math.pow(' + base + ',' + exponent + ')')
                } else {
                    me.current = eval(me.current)
                }
            
            } else if (key === 'C') {
                
                me.current = ''

            } else if (key === '*') {
                
                me.current += '*'

            } else if (key === '/') {
                
                me.current += '/'

            } else if (key === '+') {
                
                me.current += '+'

            } else if (key === '-') {
                
                me.current += '-'

            } else if (key === '±') {
                
                if ((me.current).charAt(0) === '-') {
                    me.current = (me.current).slice(1)
                } else {
                    me.current = '-' + me.current
                }

            } else if (key === '<=') {
                
                me.current = me.current.substring(0, me.current.length - 1)

            } else if (key === '%') {
                
                me.current = me.current / 100

            } else if (key === 'π') {
                
                me.current = me.current * Math.PI

            } else if (key === 'x ²') {
                
                me.current = eval(me.current * me.current)

            } else if (key === '√') {
                
                me.current = Math.sqrt(me.current)

            } else if (key === 'sin') {
                
                me.current = Math.sin(me.current)

            } else if (key === 'cos') {
                
                me.current = Math.cos(me.current)

            } else if (key === 'tan') {
                
                me.current = Math.tan(me.current)

            } else if (key === 'log') {
                
                me.current = Math.log10(me.current)

            } else if (key === 'ln') {
                
                me.current = Math.log(me.current)

            } else if (key === 'x^') {
                
                me.current += '^'

            } else if (key === 'x !') {

                let number = 1
                if (me.current === 0) {
                    me.current = '1'
                } else if (me.current < 0) {
                    me.current = NaN
                } else {
                    let number = 1
                    for (let i = me.current; i > 0; i--) {
                        number *= i
                    }
                    me.current = number
                }

            } else if (key === 'e') {
                
                me.current = Math.exp(me.current)

            } else if (key === 'rad') {
                
                me.current = me.current * (Math.PI / 180)

            } else if (key === '∘') {

                me.current = me.current * (180 / Math.PI)

            }
        },
        changeModeEvent: function() {
            let me = this
            me.changeMode = !me.changeMode
        }
    }
}

整体代码就不做过多阐述了。我想大家一看就能明白其中的意思。当然你也可以把每个功能提取出来,成为一个函数,比如:

//our ' C ' button
function clear() {
    app.current = "";
}

//our ' <= ' button
function backspace() {
    app.current = app.current.substring(0, app.current.length - 1);
}

这个时候,你浏览器将看到一个完整的计算器效果:

体验一下吧!

总结

这篇文章主要以创建一个计算器为例,来学习Vue相关的知识。在这篇文章中我们学习了怎么使用Vue CLI这样的构建工具创建一个Vue项目。又是怎么通过一个单独的文件创建Vue组件,并且将组件调用。同时在完成整个Vue版本的计算器,我们还使用了v-on指令来绑定事件,v-model实现数据双向绑定,v-if控制模板的显示与否等。当然还学习了怎么在methods中创建方法,让其无缝的事件处理和状态更改触发器。

通过这个实例,再次感觉到与Vue一起工作带来的优势。而我们这个示例的效果可以在Codepen上看到(采用另外创建计算器的方式),也可以在Github上查看代码。由于作者是Vue的初学者,如果文章中有不对之处,还请各路大婶指正。如果你有更好的实现方案或思路,欢迎在下面的评论中与我们一起分享。

特别声明:这篇文章中的计算器示例效果是根据@Raphael Ugwu的教程中案例写的。

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/vue/build-a-scientific-calculator-with-vuejs.htmlYeezy 350 Boost