Series of articles:

  • Hand touch Hands Electron + Vue Combat tutorial (1)

1 Electron upgrade

On May 19, 2020, Electron released the latest version 9.0.0 with a number of improvements that I won’t go into here, but you can check out the official introduction: github.com/electron/el…

Do you want to upgrade the yarn add electron project to the latest version of electron? 2, deleting background in the SRC directory. Js code within the app. AllowRendererProcessReuse = true, this line of code is actually we add in the last lesson, version 9.0 has been set to the default value, so we don’t need here.

2 Project Introduction

It is estimated that everyone can not help but see here: you BB so long, what on earth do you want to do the project…… Cough cough, my pot my pot, from the beginning should introduce the first, drag to now… This actual combat tutorial is not what difficult project, is imitation cloud notes, yes is imitation so-and-so routine. Of course, given the time, I probably won’t copy all of it and just pick the Markdown documentation. Here, I have a small suggestion: “Don’t copy for the sake of copying, but for the purpose of integrating your knowledge and skills into a project. That’s the ultimate goal.”

He that would do a good work must sharpen his tools

Before you start writing code, it’s worth checking out one of the best front-end editorsVisual Studio CodeOf course, it’s a matter of opinion — what’s best for you is best! If you choose not to use the editor, you can skip this section. Will install the pluginESLintandPrettier - Code formatterTo recommend my common code style and ESLint Settings, create three new files in the project root directory.editorconfig,.eslintrc.js,.prettierrc.js, as shown in the figure below: Here is the code presentation, which only shows the esLint and code style styles used in the current project, you can choose whether to use them or not.

This is the contents of the.editorConfig fileCopy the code

[*.{js,jsx,ts,tsx,vue}] indent_style = space indent_size = 2 end_of_line = lf trim_trailing_whitespace = true insert_final_newline = true max_line_length = 120

// This is the.eslintrc.js file
module.exports = {
  root: true.  env: {
    node: true
 },  extends: ['plugin:vue/essential'.'@vue/airbnb']. parserOptions: {  parser: 'babel-eslint'  },  rules: {  'no-console': 0. 'no-debugger': 0. semi: ['error'.'never'].// Disable semicolons  'no-multiple-empty-lines': ['error'].// Number of blank lines  'linebreak-style': [0.'error'.'windows'].// Use Windows newline  'comma-dangle': [2.'never'].// The last of the object array does not have a comma  'no-trailing-spaces': 0.// Disable verification codes with Spaces at the end  'import/no-dynamic-require': 0.// disable dynamic require  'import/no-unresolved': 0. 'no-param-reassign': 0.// Variables declared as function parameters can be misleading  'max-len': ['error'.120].// Maximum length of a single line of code  'guard-for-in': 0.// Disable Disables the for in loop  'no-shadow': 0.// disable Disables compatible parameter names in pages  'object-shorthand': 0.// Disable Disables the use of quoted strings within objects  'no-restricted-syntax': 0. 'no-plusplus': 0./ / disable + +  'consistent-return': 0.// Close arrow function must return  'no-return-assign': 0.// Return statements cannot have assignment expressions  'global-require': 0.// Disable requrie  'prefer-promise-reject-errors': 0.// This rule aims to ensure that promises are rejected only by Error objects.  'import/extensions': 'off'.// Disable filename details file type suffixes  'import/no-extraneous-dependencies': ['error', { devDependencies: true}]. 'arrow-parens': ['error'.'as-needed'].// arrow function parameter parentheses, optional always :(default) arguments are required in all cases; As-needed: Parameters can be omitted when there is only one parameter  'no-undef': 0.// Turn off the requirement to explicitly declare global variables  'class-methods-use-this': 0. 'no-underscore-dangle': ['error', { allow: ['_id']}],// Allows the specified identifier to have a hanging underscore  camelcase: 0.// Turn off the camel spelling  'no-global-assign': 0.// Allow modification of read-only global variables,  'space-before-function-paren': [  'error'. {  anonymous: 'never'. named: 'never'. asyncArrow: 'always'  } ]. // Object deconstruction does not require line breaks  'object-curly-newline': [  'error'. {  ObjectPattern: {  multiline: true  }  } ]. 'no-unused-expressions': ['error', { allowShortCircuit: true.allowTernary: true }] // Allow ternary operators in expressions, similar to short-circuit evaluation  } }  Copy the code
// This is the content of the.prettierrc.js file
module.exports = {
  semi: false.// Remove the semicolon
  singleQuote: true.// Use single quotes
  printWidth: 120.// Maximum length of a single line of code
 trailingComma: 'none' // Remove the trailing comma (object, array, etc.) }  Copy the code

Done! Now we can have fun…

4 left panel development

Screenshot of Youdao Cloud Note

As you can see, the left panel is a list of files. Here, we not only need to make the list in the picture, but also add a search bar at the top of the list, so that we can search the list notes easily and quickly. At present, we also need to have the function of adding and importing notes. Let’s take a look at the finished image of this section:

4.1 Overall Layout

We first remove extra pages and components of the project: the vue – electron – notes/SRC/components/HelloWorld vue vue – electron – notes/SRC/views/About. Vue cuts after routing file:

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [  {  path: '/'. name: 'Home'. component: (a)= > import('@/views/Home')  } ]  const router = new VueRouter({  mode: 'history'. base: process.env.BASE_URL,  routes })  export default router Copy the code

Deleted app. vue file:

<template>
  <div id="app">
    <router-view />
  </div>
</template>
 <style lang="less"> * {  margin: 0;  padding: 0;  outline: none;  box-sizing: border-box; } #app {  font-family: Avenir, Helvetica, Arial, sans-serif;  -webkit-font-smoothing: antialiased;  -moz-osx-font-smoothing: grayscale;  color: #2c3e50; } </style>  Copy the code

The CSS wildcard * is used for simplicity and convenience, but it is recommended that you do not do this in real projects.

We continue to modify the home.vue file in the View directory, using Flex layout to set it to the most common two-column layout (I won’t say much about flex, not to mention CSS compatibility here), left panel fixed width, right content editing area adaptive:

<template>
  <div class="app-wrapper">
    <div class="sidebar-container"></div>
    <div class="main-container"></div>
  </div>
</template>  <script> export default {  name: 'Home' } </script>  <style lang="less" scoped> .app-wrapper {  display: flex;  .sidebar-container {  width: 300px;  height: 100vh;  border-right: 1px solid #eaeefb;  }  .main-container {  flex: 1;  } } </style> Copy the code

4.2 Introducing the Element-UI and Fontawesome icon libraries

Create the plugin folder in the SRC directory, where all the external frameworks and plug-ins we will introduce will be stored. Install elemental-ui using yarn add elemental-ui and create a new file elemental-ui.js in the plugin file:

/ ** @description: Introduce the element-UI framework * @Author: sufen
 * @Date: 2020-05-21 09:58:49
 * @LastEditTime: 2020-05-21 09:59:20  * @LastEditors: sufen * / import Vue from 'vue' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css'  Vue.use(ElementUI, { size: 'small' }) Copy the code

Continue to install the Fontawesome Icon library by installing all icon dependencies first and then introducing the ICONS we need as needed.

MacBook-Pro:vue-electron-notes Bill$ yarn add @fortawesome/vue-fontawesome @fortawesome/free-solid-svg-icons @fortawesome/fontawesome-svg-core @fortawesome/free-brands-svg-icons @fortawesome/free-regular-svg-icons
Copy the code

Then create a new file fortawesome. Js in the plugin file. FaMarkdown and faUserSecret are the ICONS we introduce as needed.

/ ** @description: Fortawesome Icon Library * @Author: sufen
 * @Date: 2020-05-21 09:55:29
 * @LastEditTime: 2020-05-21 10:06:46  * @LastEditors: sufen * / import Vue from 'vue' import { library } from '@fortawesome/fontawesome-svg-core' import { faUserSecret } from '@fortawesome/free-solid-svg-icons' import { faMarkdown } from '@fortawesome/free-brands-svg-icons' // import { faUserSecret } from '@fortawesome/free-regular-svg-icons' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'  library.add(faUserSecret, faMarkdown)  Vue.component('font-awesome-icon', FontAwesomeIcon) Copy the code

We’re not done with the above two, but finally we need to introduce in our main.js file:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import '@/plugin/element-ui'
import '@/plugin/fortawesome'  Vue.config.productionTip = false  new Vue({  router,  store,  render: h= > h(App) }).$mount('#app') Copy the code

At this point, we have completed the introduction of Element – UI and Fortawesome, can happily use in the project, do not believe you have a try 😊

4.2 FileSearch Search Component

Add it in the Components directoryFileSearchComponent. This component consists of an input box and a drop-down menu, both of which we can use directly from Element’s component. Note that we are using the new component in Vue V2.4$attrsand$listenersProperties.

Attrs: contains feature bindings (except class and style) that are not considered (and not expected to be) props in the parent scope. When a component doesn’t declare any props, this includes all parent-scoped bindings (except class and style), and internal components can be passed in via V-bind = “$attrs” — useful when creating higher-level components.

Listeners: Contains V-on event listeners in the parent scope (without.native modifiers). It can be passed into internal components via V-on = “$Listeners” — useful when creating higher-level components.

In our writing of vUE advanced components, these two properties are just magic, it is not too cool!!

FileSearch component calls directly use v-model binding to search for content, new files and import files through $emit call custom events, these are vUE basics, not to mention here. Take a look at the FileSearch component source code we have completed:

<! --* @description: Left file search component * @Author: sufen
 * @Date: 2020-05-20 16:08:49
 * @LastEditTime: 2020-05-21 10:36:49  * @LastEditors: sufen  --> <template>  <div class="search-container">  <el-input placeholder="Please enter the content" v-bind="$attrs" v-on="$listeners">  <el-button slot="append" icon="el-icon-search" />  </el-input>  <el-dropdown>  <el-button type="primary" icon="el-icon-circle-plus-outline" circle />  <el-dropdown-menu slot="dropdown">  <el-dropdown-item @click="createFile()">New notes</el-dropdown-item>  <el-dropdown-item divided @click="importFile()">The import file</el-dropdown-item>  </el-dropdown-menu>  </el-dropdown>  </div> </template>  <script> export default {  name: 'FileSearch'. methods: {  // Create a new note  createFile() {  this.$emit('create')  },  // Import the file  importFile() {  this.$emit('import')  }  } } </script>  <style lang="less" scoped> .search-container {  display: flex;  align-items: center;  padding: 12px 10px;  background: #daecfe;   .el-dropdown {  .el-button--small {  margin-left: 10px;  padding: 6px;  font-size: 14px;  border-radius: 30%;  }  } } </style> Copy the code

4.3 FileList FileList component

Add it in the Components directoryFileListComponent, we this section is mainly to complete such a list, as for the use of the right button menu and so on, to our subsequent use to say, the road to go step by step.

As you can see, our component props accepts onefileListArray, and then throughv-forI rendered it straight away. eachliAll useflexThe layout,liIncluding our file title and the last modification time of the file, Flex is really a layout wizard and always uses it straight! The fortawesome icon library is the only way to use the fortawesome icon library.

import { faMarkdown } from '@fortawesome/free-brands-svg-icons'
library.add(faMarkdown)
Copy the code

Then we use the Fortawesome component directly in the FileList component, and the Markdown icon is displayed. We can use the fortawesome component directly in the FileList component to display the Markdown icon.

<font-awesome-icon :icon="['fab', 'markdown']" />
Copy the code

If that’s the end of it, then this component is pretty low-tech.

As our files get bigger and bigger, the list will get longer and longer, and the scroll bar will inevitably appear. As an aspiring programmer, I can’t accept the browser’s native scroll bar. It’s ugly and not elegant. To solve this problem without having to build my own wheels, I used elementary-UI’s hidden component, el-ScrollBar. See the official documentation for how it works:

Although this component is not given in the official documentation, it is available in the source code. So we can just use:

<el-scrollbar></el-scrollbar>
Copy the code

The use of this component is still some holes to pay attention to, you can refer to this article, which has been written very clearly, I will not repeat this wordy.

Take a look at our final complete component code:

<! --* @description: Left file list component * @Author: sufen
 * @Date: 2020-05-20 16:18:34
 * @LastEditTime: 2020-05-21 10:37:18  * @LastEditors: sufen  --> <template>  <el-scrollbar class="file-list" wrap-class="scrollbar-filelist" :noresize="false" tag="ul">  <li v-for="(item, index) in fileList" :key="index" class="file-item">  <font-awesome-icon :icon="['fab', 'markdown']" class="item-icon" />  <p class="item-title">{{ item.title }}</p>  <p class="item-time">{{ item.time }}</p>  </li>  </el-scrollbar> </template>  <script> export default {  name: 'FileList'. props: {  fileList: {  type: Array. default: (a)= > []  }  },  data() {  return {}  } } </script>  <style lang="less" scoped> .file-list {  user-select: none;  .file-item {  display: flex;  align-items: center;  height: 55px;  border-bottom: 1px solid #eaeefb;   .item-icon {  margin-left: 20px;  margin-right: 12px;  }   .item-title {  flex: 1;  margin-right: 5px;  font-size: 14px;  text-overflow: ellipsis;  white-space: nowrap;  overflow: hidden;  }  .item-time {  width: 80px;  font-size: 12px;  }  } } </style> <style lang="less"> .scrollbar-filelist {  height: calc(100vh - 56px); overflow-x: hidden ! important;} .el-scrollbar__bar {  opacity: 1;   &.is-vertical {  right: 0px;  width: 5px;  .el-scrollbar__thumb { Background: rgba(144, 147, 153, 0.5); }  } } </style> Copy the code

4.4 Importing Components

Now that the two components needed for the left panel are complete, it’s time to introduce the final effect to the Home page, in the home.vue Home file in the View directory:

<template>
  <div class="app-wrapper">
    <div class="sidebar-container">
      <file-search v-model="searchTitle" />
      <file-list :fileList="fileList" />
 </div>  <div class="main-container"></div>  </div> </template>  <script> import FileSearch from '@/components/FileSearch' import FileList from '@/components/FileList'  export default {  name: 'Home'. components: { FileSearch, FileList },  data() {  return {  searchTitle: ' '. fileList: [  { id: 1.title: 'File name 1'.time: '2020-06-21' },  { id: 2.title: 'File name 2'.time: '2020-06-21' },  { id: 3.title: 'File name 3'.time: '2020-06-21' },  { id: 4.title: 'File name 4'.time: '2020-06-21' },  { id: 5.title: 'File name 5'.time: '2020-06-21' },  { id: 6.title: 'File name 6'.time: '2020-06-21' },  { id: 1.title: 'File name 1'.time: '2020-06-21' },  { id: 2.title: 'File name 2'.time: '2020-06-21' },  { id: 3.title: 'File name 3'.time: '2020-06-21' },  { id: 4.title: 'File name 4'.time: '2020-06-21' },  { id: 5.title: 'File name 5'.time: '2020-06-21' },  { id: 6.title: 'File name 6'.time: '2020-06-21' }  ]  }  } } </script>  <style lang="less" scoped> .app-wrapper {  display: flex;  .sidebar-container {  width: 300px;  height: 100vh;  border-right: 1px solid #eaeefb;  }  .main-container {  flex: 1;  } } </style> Copy the code

List the final file tree:

├ ─ ─ the public│ ├ ─ ─ the favicon. Ico│ └ ─ ─ index. HTML├ ─ ─ the SRC│ ├ ─ ─ assets│ │ └ ─ ─ logo. PNG│ ├ ─ ─ the components│ │ ├ ─ ─ the FileList│ ├ ─ ├ ─ garbage│ │ └ ─ ─ FileSearch│ │ └ ─ ─ index. Vue│ ├ ─ ─ the plugin│ │ ├ ─ ─ element - UI. Js│ │ └ ─ ─ fortawesome. Js│ ├ ─ ─ the router│ │ └ ─ ─ index. Js│ ├ ─ ─ store│ │ └ ─ ─ index. Js│ ├ ─ ─ views│ │ └ ─ ─ Home. Vue│ ├ ─ ─ App. Vue│ ├ ─ ─ background. Js│ └ ─ ─ the main js├ ─ ─ editorconfig├ ─ ─. Eslintrc. Js├ ─ ─ gitignore├ ─ ─. Prettierrc. Js├ ─ ─ the README, md├ ─ ─ Babel. Config. Js└ ─ ─ package. JsonCopy the code

Done! Here is our final look on the left panel:


If you think that this article is also ok, the old man here has the audacity to ask for a compliment! 😉