使用Vue.js和Electron创建桌面测验应用程序

Today, I would be explaining how to build a desktop quiz application using Electron and Vue.js.

今天,我将解释如何使用Electron和Vue.js构建桌面测验应用程序。

Vue.js is a library for building interactive web interfaces. It provides data-reactive components with a simple and flexible API.

Vue.js是用于构建交互式Web界面的库。 它通过简单灵活的API提供了对数据敏感的组件。

The reason why I chose to use Vue is because it is a lightweight alternative to Angular, and it is very easy for any developer at an intermediate level to pick up.

之所以选择使用Vue,是因为它是Angular的轻量级替代品,对于中级水平的任何开发人员来说都很容易上手。

Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It takes care of the hard parts so you can focus on the core of your application. It is based on Node.js and Chromium and is used by the Atom editor.

Electron是一个框架,用于使用JavaScript,HTML和CSS等Web技术创建本机应用程序。 它负责处理硬部分,因此您可以专注于应用程序的核心。 它基于Node.js和Chromium,并由Atom编辑器使用。

If you are familiar with technologies such as C# or Java, you know that building desktop apps can be a bit tedious, and sometimes you might have to write DLL (dynamic-link library) files yourself.

如果您熟悉C#或Java之类的技术,那么您就会知道构建桌面应用程序可能有点乏味,有时您可能必须自己编写DLL(动态链接库)文件。

Electron, on the other hand, takes care of all of these for you, and may I mention, it is also cross platform. I.e one code base, all three platforms.

另一方面,Electron会为您解决所有这些问题,我想说,它也是跨平台的。 即一个代码库,所有三个平台。

我们将建立什么 ( What We Will Build )

We will be building a desktop application that allows people to take quiz questions, and at the end of the questions, see their total score.

我们将构建一个桌面应用程序,使人们可以进行测验问题,并在问题末尾看到他们的总成绩。

Here is a quick view of what we will be building:

这是我们将要构建的内容的快速视图:

For the purpose of this tutorial, the term Vue refers to Vue 2.X versions unless stated otherwise.

就本教程而言,除非另有说明,否则术语Vue指的是Vue 2.X版本。

This tutorial, however, hopes that you do understand the basics of Vue.js

但是,本教程希望您确实了解Vue.js的基础

Vue-Cli入门 ( Getting Started With The Vue-Cli )

To get started easily and also skip the process of configuring Webpack for the compilation from ES2016 to ES15, we will use the Vue CLI. If you do not have the Vue CLI installed, we can install it by running the command below:

为了轻松上手,并且跳过从ES2016到ES15的编译配置Webpack的过程,我们将使用Vue CLI。 如果您尚未安装Vue CLI,我们可以通过运行以下命令进行安装:

sudo npm install -g vue-cli

After installing the Vue-cli, we will proceed to create a Vue project. To do that, we run the following command.

安装Vue-cli后,我们将继续创建Vue项目。 为此,我们运行以下命令。

Note: for the purposes of this tutorial, while running the command below, I choose no when asked if to lint the code.

注意:出于本教程的目的,在运行下面的命令时,当系统询问是否抹掉代码时,我选择否。

Code linting will ensure that the code is indented and empty spaces are not left. But I like to leave empty spaces in my code to keep it organized.

代码整理将确保代码缩进并且不留空格。 但是我喜欢在代码中保留空白以使代码井井有条。

vue init webpack electron-vue

Now we will need to install the NPM dependencies for the application to work.

现在,我们将需要安装NPM依赖关系才能使应用程序正常工作。

We would have to change directory to the working folder and then run npm install.

我们必须将目录更改为工作文件夹,然后运行npm install。

//change directory into the foldercd electron-vue
//install the npm dependencies
npm install

After installing these modules, we need to install Electron on our system.

安装完这些模块后,我们需要在系统上安装Electron。

安装和配置电子 ( Installing And Configuring Electron )

I usually prefer running Electron globally, but you can install locally.

我通常更喜欢在全球运行Electron,但是您可以在本地安装。

To install globally, we can run:

要全局安装,我们可以运行:

sudo npm install -g electron

To install locally, we can run:

要在本地安装,我们可以运行:

npm install electron

At this point, if we run the electron command, we should get an error like this:

在这一点上,如果运行电子命令,我们将得到如下错误:

electron.
Error launching app
Unable to find Electron app at /home/samuel/electron-vue
Cannot find module '/home/samuel/electron-vue'

This error is because you have not created the main script that starts the Electron app. So let's move into our package.json file which has been created by our cue-cli and add a new line to it under the first object block, which defines name, version, description, author, private. Just before the scripts also, we would add a key pair called "main" with a value of "elect.js" .

该错误是因为您尚未创建启动Electron应用程序的主脚本。 因此,让我们进入由cue-cli创建的package.json文件,并在第一个对象块下添加新行,该对象块定义了名称,版本,描述,作者,私有。 在脚本之前,我们还将添加一个名为"main"的键对,其值为"elect.js"

{
  //name of the application
  "name": "electron-vue",
  //version of the application
  "version": "1.0.0",
  //description of the application
  "description": "A Vue.js project",
  //author of the application
  "author": "samuelayo <ayoogundipe2005@gmail.com>",
  "private": true,
  //main entry point for electron
  "main": "elect.js",
  //vue js defined scripts
  "scripts": {
  "dev": "node build/dev-server.js",
  "build": "node build/build.js"
  }

We have defined elect.js as the starting point for Electron to run its application, but the file hasn’t been created yet.

我们已经定义了lectlect.js作为Electron运行其应用程序的起点,但是该文件尚未创建。

So in our root folder, we will create a file called elect.js and put in the following content:

因此,在我们的根文件夹中,我们将创建一个名为elect.js的文件,并放入以下内容:

// ./main.js
const {app, BrowserWindow} = require('electron')

let win = null;

app.on('ready', function () {

  // Initialize the window to our specified dimensions
  win = new BrowserWindow({width: 1000, height: 600});

  // Specify entry point to default entry point of vue.js
  win.loadURL('http://localhost:8080');

  // Remove window once app is closed
  win.on('closed', function () {
  win = null;
  });

});
//create the application window if the window variable is null
app.on('activate', () => {
  if (win === null) {
  createWindow()
  }
})
//quit the app once closed
app.on('window-all-closed', function () {
  if (process.platform != 'darwin') {
  app.quit();
  }
});

The above created file is the elect.js file which will now run the application. At the beginning of this file, we required Electron and set the values of two different constants to it, namely: app and browserwindow;

上面创建的文件是elec.js文件,该文件现在将运行该应用程序。 在此文件的开头,我们需要Electron并为其设置两个不同常量的值,即: appbrowserwindow

We then set the variable win to null by default. At this point, we put in three listeners to listen the activate, ready and windows-all-closed events.

然后,我们默认将变量win设置为null。 在这一点上,我们放入了三个侦听器来侦听activatereadywindows-all-closed事件。

The main focus here is the ready event, where we set a new dimension for our app, load the entry point, which could be a direct URL or a file URL. But for now, we are loading the development URL for Vue.

这里的主要焦点是ready事件,在该事件中,我们为应用设置了新的维度,加载了入口点,入口点可以是直接URL或文件URL。 但是目前,我们正在加载Vue的开发URL。

At this point, we can open up two terminals to the root of our project.

此时,我们可以在项目的根目录下打开两个终端。

In the first terminal, we want to serve our Vue application, So we run:

在第一个终端中,我们想为Vue应用程序提供服务,因此我们运行:

npm run dev

On the second terminal, we want to run the Electron application, so we run:

在第二个终端上,我们要运行Electron应用程序,因此我们运行:

electron.

If all goes well, we should be seeing this:

如果一切顺利,我们应该会看到:

At this point, we are all set to go. All we need to do now is focus on our Vue application.

至此,我们已经准备就绪。 现在我们需要做的就是专注于我们的Vue应用程序。

创建测验应用程序 ( Creating The Quiz Application )

It's time to move into our src/App.vue to do the main quiz application.

现在是时候进入我们的src/App.vue测验应用程序了。

At this point, let's deal with the script part of our App.vue file. We'll replace the script file with the following:

此时,让我们处理App.vue文件的脚本部分。 我们将脚本文件替换为以下内容:

<script>
// an array of questions to be asked. Length of 10 questions.
var quiz_questions = [
  {
  "category": "Entertainment: Film",
  "type": "multiple",
  "difficulty": "easy",
  "question": "Who directed "E.T. the Extra-Terrestrial" (1982)?",
  "correct_answer": "Steven Spielberg",
  "incorrect_answers": [
  "Steven Spielberg",
  "Stanley Kubrick",
  "James Cameron",
  "Tim Burton"
  ]
  },
  {
  "category": "Entertainment: Video Games",
  "type": "multiple",
  "difficulty": "medium",
  "question": "What is the main character of Metal Gear Solid 2?",
  "correct_answer": "Raiden",
  "incorrect_answers": [
  "Raiden",
  "Solidus Snake",
  "Big Boss",
  "Venom Snake"
  ]
  },
  {
  "category": "Science & Nature",
  "type": "multiple",
  "difficulty": "easy",
  "question": "What is the hottest planet in the Solar System?",
  "correct_answer": "Venus",
  "incorrect_answers": [
  "Venus",
  "Mars",
  "Mercury",
  "Jupiter"
  ]
  },
  {
  "category": "Entertainment: Books",
  "type": "multiple",
  "difficulty": "hard",
  "question": "What is Ron Weasley's middle name?",
  "correct_answer": "Bilius",
  "incorrect_answers": [
  "Bilius",
  "Arthur",
  "John",
  "Dominic"
  ]
  },
  {
  "category": "Politics",
  "type": "multiple",
  "difficulty": "medium",
  "question": "Before 2011, "True Capitalist Radio" was known by a different name. What was that name?",
  "correct_answer": "True Conservative Radio",
  "incorrect_answers": [
  "True Conservative Radio",
  "True Republican Radio",
  "Texan Capitalist Radio",
  "United Capitalists"
  ]
  },
  {
  "category": "Entertainment: Film",
  "type": "multiple",
  "difficulty": "medium",
  "question": "This movie contains the quote, "I love the smell of napalm in the morning!"",
  "correct_answer": "Apocalypse Now",
  "incorrect_answers": [
  "Apocalypse Now",
  "Platoon",
  "The Deer Hunter",
  "Full Metal Jacket"
  ]
  },
  {
  "category": "History",
  "type": "multiple",
  "difficulty": "medium",
  "question": "The Herero genocide was perpetrated in Africa by which of the following colonial nations?",
  "correct_answer": "Germany",
  "incorrect_answers": [
  "Germany",
  "Britain",
  "Belgium",
  "France"
  ]
  },
  {
  "category": "Entertainment: Music",
  "type": "boolean",
  "difficulty": "medium",
  "question": "Ashley Frangipane performs under the stage name Halsey.",
  "correct_answer": "True",
  "incorrect_answers": [
  "True",
  "False"
  ]
  },
  {
  "category": "Entertainment: Books",
  "type": "multiple",
  "difficulty": "easy",
  "question": "Under what pseudonym did Stephen King publish five novels between 1977 and 1984?",
  "correct_answer": "Richard Bachman",
  "incorrect_answers": [
  "Richard Bachman",
  "J. D. Robb",
  "Mark Twain",
  "Lewis Carroll"
  ]
  },
  {
  "category": "History",
  "type": "multiple",
  "difficulty": "medium",
  "question": "In what prison was Adolf Hitler held in 1924?",
  "correct_answer": "Landsberg Prison",
  "incorrect_answers": [
  "Landsberg Prison",
  "Spandau Prison",
  "Ebrach Abbey",
  "Hohenasperg"
  ]
  }
]
export default {
//name of the component
  name: 'app',
  //function that returns data to the components
  data : function (){
  return{
//question index, used to show the current question
  questionindex:0,
//set the variable quizez to the questions defined earlier
  quizez:quiz_questions,
//create an array of the length of the questions, and assign them to an empty value.
answers:Array(quiz_questions.length).fill(''),
  }
  },
  //methods to be called in the component
  methods: {
  // Go to next question
  next: function() {
  this.questionindex++;
  },
  // Go to previous question
  prev: function() {
  this.questionindex--;
  }
 },
 computed:{
 //calculate total score of the quiz person.
  score: function() {
  var total = 0;
  for (var i =0; i <this.answers.length; i++) {
  if(this.answers[i]==this.quizez[i].correct_answer){
  total +=1;
  }
  }
  return total;
  }
 }
}
</script>

In the above code, we declared a variable called quiz_questions and gave it an array of objects which are the intended questions. The objects had a key for category of the question, the type of the question, the difficulty level of the question, the question itself, the correct_answer, and an array of incorrect answers, which consist of all the options to all questions.

在上面的代码中,我们声明了一个名为quiz_questions的变量,并给了它一个对象数组,这些对象是预期的问题。 这些对象具有问题category ,问题type ,问题difficulty levelquestion本身, correct_answer和不正确答案数组的correct_answer ,这些错误答案包含所有问题的所有选项。

After this, we then go ahead to declare our component properties, such as the name, the data needed, our methods and a computed property.

之后,我们继续声明我们的组件属性,例如name ,所需dataour methods和一个computed property

The data block consist of the questionindex which refers to the current question being shown, the quizez which represent the questions available to be shown, which is set to the value of the quiz_questions, and another property called answers which is instantiated to an array with a length of the current amount of questions, and their values are all set to an empty string.

数据块由questionindex (指向显示的当前问题), quizez (代表可显示的问题)(设置为quiz_questions的值)和另一个称为answers由带有一个实例的数组)的属性组成。当前问题数量的长度以及它们的值都设置为空字符串。

The methods block consist of two methods, namely: next and previous, which increases and decreases the value of the questionindex, which would be used when the person clicks previous and next.

方法块由两种方法组成,即: nextprevious ,它增加和减小questionindex的值,当人们单击previous和next时将使用该值。

The computed block, consists of one computed property, which checks all the answers given to the questions using their index, which will tally to the index of the quiz questions, then check if the values are equal to the correct_answer key of the question, and if correct, scores the person for each question.

计算块由一个计算属性组成,该属性使用其索引检查对问题给出的所有答案,该索引将与测验问题的索引相符,然后检查值是否等于问题的correct_answer键,以及如果正确,则为每个问题的人评分。

At this point, we are ready to change the template section and have it display our quiz questions.

此时,我们准备更改模板部分,并显示我们的测验问题。

Let's replace the content of the <template></template> tag with this:

让我们用以下内容替换<template></template>标记的内容:

<template>
  <div id="app">
  <!-- Questions: display a div for each question -->
<!-- show only if the index of the quetion is equal to the question index -->
  <div v-for="(quiz, index) in quizez" v-show="index === questionindex">
<!-- display the quiz Category -->
  <h1>{{ quiz.category }}</h1>
<!-- display the quiz question -->
  <h2>{{ quiz.question }}</h2>
  <!-- Responses: display a li for each possible response with a radio button -->
  <ol>
<!--display the quiz options -->
  <li v-for="answer in quiz.incorrect_answers">
  <label>
<!-- bind the options to the array index of the answers array that matches this index -->
  <input type="radio" name="answer" v-model="answers[index]" :value="answer"> {{answer}}
  </label>
  </li>
  </ol>

  </div>
  <!-- do not display if the question index exceeds the length of all quizez -->
  <div v-if="questionindex < quizez.length">
  <!-- display only if the question index is greater than zero -->
  <!-- onclick of this button, call the previous function, and show last question -->
  <button v-if="questionindex > 0" v-on:click="prev">
  prev
  </button>
 <!-- onclick of this button, call the next function, and show next question -->
  <button v-on:click="next">
  next
</button>
</div>
<!-- show total score, if the questions are completed -->
<span v-if="questionindex == quizez.length">Your Total score is {{score}} / {{quizez.length}}</span>

</div>
</template>

If we take a look at the template above, what we are doing is very simple.

如果我们看一下上面的模板,我们正在做的事情很简单。

We use the v-for loop to loop through all our questions, we then put a v-show condition, to show only the current question. Within the loop, we then display the category, after which we display the question, then we proceed to loop through all the options in that question using another v-for loop, binding all current questions to the index of the answers we have already created for them, and also binding their values, to the option itself.

我们使用v-for循环遍历所有问题,然后放置v-show条件,以仅显示当前问题。 然后在循环中显示category ,然后显示question ,然后使用另一个v-for循环遍历该问题中的所有选项,将所有当前问题绑定到我们已经创建的answers的索引中对于他们,并将其值绑定到选项本身。

After this, we put up a condition that does not display the next and previous buttons if all the questions have been completed.

此后,我们提出了一个条件,如果所有问题都已完成,则不显示下一个和上一个按钮。

We also put a condition on the previous button, to only show if the current question isn't the first question in the array. After this, we bind the click event, to the Prev method we had defined earlier.

我们还在上一个按钮上放置了一个条件,以仅显示当前问题不是数组中的第一个问题。 此后,我们将click事件绑定到我们先前定义的Prev方法。

Similarly, we will add a click event to the next button and bind it to the next function we had defined earlier too.

同样,我们将click事件添加到next按钮,并将其绑定到我们之前定义的next函数。

Finally, we will create a span that shows the total amount of points scored once there are no more questions to create.

最后,我们将创建一个跨度,该跨度将显示没有更多问题可创建的总得分。

At this point, our quiz app is completed and looks this way:

至此,我们的测验应用程序已完成,外观如下:

包装电子以使用生产就绪应用程序 ( Packaging Electron To Use The Production Ready App )

Right now, the application still runs from the development server. It is now time to run the app from the file directly, to be packaged with Electron.

现在,该应用程序仍从开发服务器运行。 现在是时候直接从文件中运行应用程序了,该文件将与Electron打包在一起。

On the terminal running the Vue server, hit ctrl+c, then run the following command:

在运行Vue服务器的终端上,按ctrl+c ,然后运行以下命令:

npm run build

After running this, a file would be created in your root folder, under dist/index.html. Open up the file, remove all leading / from all references to JS or CSS files, then close. If we don't do this, our application would load only an empty screen, as it would not be able to locate our CSS and JavaScript files.

运行此命令后,将在您的根文件夹dist/index.html下创建一个文件。 打开文件,从所有对JS或CSS文件的引用中删除所有前导/ ,然后关闭。 如果我们不这样做,我们的应用程序将仅加载一个空白屏幕,因为它无法找到我们CSS和JavaScript文件。

At this point, let's go back into our elect.js, and add some configurations to make it serve from the file. At the top of the file, add these two imports:

至此,让我们回到elect.js ,并添加一些配置以使其从文件中进行服务。 在文件顶部,添加以下两个导入:

var url= require('url')
const path = require('path');

Here, we are just defining some imports. Lets see how we'll use them later:

在这里,我们仅定义一些导入。 让我们看看以后如何使用它们:

Lets replace the part that says win.loadURL('http://localhost:8080') with the code below:

让我们用下面的代码替换表示win.loadURL('http://localhost:8080')的部分:

win.loadURL(url.format({
  pathname: path.join(__dirname, 'dist/index.html'),
  protocol: 'file:',
  slashes: true
  }));

What we have done here is to tell Electron to load the index.html in our dist folder, and it should attempt to load it as a file rather than an actual url.

我们在这里所做的是告诉Electron将index.html加载到我们的dist文件夹中,并且它应该尝试将其加载为文件而不是实际的url。

Once done, save and hit electron .

完成后,保存并击中electron .

At this point, we have our app running as seen below:

To distribute to various platforms, you can follow the official guide on Electron's Github page on how to package for various distributions
here

此时,我们的应用程序正在运行,如下所示:

结论 ( Conclusion )

At this point, we have seen how to build a desktop application using Electron and Vue.

至此,我们已经了解了如何使用Electron和Vue构建桌面应用程序。

In the course of our tutorial, we learned that Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. We also learned that we chose to use Electron because it is cross platform and is easier to use than the likes of C# or Java.

在本教程的过程中,我们了解到Electron是一个框架,用于使用JavaScript,HTML和CSS等Web技术创建本机应用程序。 我们还了解到,我们选择使用Electron是因为它是跨平台的,并且比C#或Java更易于使用。

At this point, we should be able to build amazing cross platform applications using Electron and Vue in less time while aiming for perfection.

在这一点上,我们应该能够在较短的时间内使用Electron和Vue构建出色的跨平台应用程序,同时追求完美。

翻译自: https://scotch.io/tutorials/create-a-desktop-quiz-application-using-vue-js-and-electron

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值