Create front-end project under vue-cli4

Keywords: Front-end Nginx Vue.js vue-cli4

Upper connection Create front-end projects (routing, vuex and axios applications) under vue-cli4 , this article solves some problems encountered in the coding process.

1. Set global template

The global template is used to display all pages according to a certain layout, such as advertisements or operation dials fixed on both sides, and only the actual displayed content is in the middle. Here I use bootstrap to realize the layout.

1.1. Reference bootstrap

Directly reference the css and js files of CDN in index.html, which should work globally.

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title><%= htmlWebpackPlugin.options.title %></title>

    <!-- Bootstrap core CSS -->
    <link href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.13/dist/css/bootstrap.min.css" rel="stylesheet">

    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <link href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.13/assets/css/ie10-viewport-bug-workaround.css" rel="stylesheet">
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
  <script src="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.13/assets/js/ie-emulation-modes-warning.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.13/dist/js/bootstrap.min.js"></script>
  <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
  <script src="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.13/assets/js/ie10-viewport-bug-workaround.js"></script>
</html>

1.2. Add global template file

Create a new layout.vue under views and write the following contents. Here, you only need to set the middle as router view to display sub pages

<template>
    <div class="col-md-1" style="font-size: 30px;">
        >_:
    </div>
    <div class="col-md-10">
        <router-view></router-view>
    </div>
    <div class="col-md-1"></div>
</template>

<script>
    export default {
        name: "layout"
    }
</script>
<style>
</style>

1.3. Modify route

The effect of starting the project after adding is that when accessing localhost:8080, you will get a note/list nested under the layout, that is, inject the content of the real note/list into the < router View > of the layout page.

import {createRouter, createWebHistory} from "vue-router";
import Layout from '@/views/layout/layout.vue'
const constantRouterMap = [
    {
        path: '',
        redirect: '/note/list'
    },
    {
        path: '/note',
        component: Layout,
        // redirect: '',
        name: 'note',
        meta: { title: 'Article list' },
        children: [
            {
                path: 'list',
                name: 'list',
                component: () => import('@/views/note/list.vue')
            }
        ]
    },
    {
        path: '/detail/:id',
        component: () => import('@/views/detail.vue')
    },
    // 404 information page display
    { 
        path: '/:pathMatch(.*)*', 
        name: 'NotFound', 
        component: () => import('@/views/notFound.vue')
    }
]
export default new createRouter({
    history: createWebHistory(),
    routes: constantRouterMap
});
//# sourceMappingURL=router.js.map

2. Reference static resources (pictures, CSS, etc.)

First, put static resources into assets.

Pictures can be referenced as follows:

<img class="icon" src="@/assets/icon/folder.svg" v-if="node.dir">
<img class="icon" src="@/assets/icon/file.svg" v-if="!node.dir">

CSS can be referenced like this

<style>
  @import "assets/css/zekdot.css";
</style>

3. Pass reference to the page

First, define props on the corresponding page, here is detail.vue

export default {
  name: 'list',
  props: ['address'],
  data() {
    return {
        nodes : [{"address":"/nginx/Load balancing implementation.md","dir":false,"name":"Load balancing implementation.md"},{"address":"/nginx/url.txt","dir":false,"name":"url.txt"},{"address":"/nginx/note.md","dir":false,"name":"note.md"},{"address":"/nginx/test","dir":true,"name":"test"}],
    }
  },
  created() {
    console.log(this.address)
  }
}

Then modify the corresponding route and set props to true.

    {
        path: '/note',
        component: Layout,
        // redirect: '',
        name: 'note',
        meta: { title: 'Article list' },
        children: [
			...
            {
                path: 'detail/:address',
                name: 'detail',
                component: () => import('@/views/note/detail.vue'),
                props: true
            },
        ]
    },

Then visit localhost:8080/note/detail/test.txt to print out test.txt in the console.

4. Set page access permissions

4.1. Method of realizing login request

First, you need to implement a login request method. When calling, you will log in and obtain a successful login token.

import request from '@/utils/request';

// After login, the token object is returned
export function login(user) {
    return request({
        url: '/user/login',
        method: 'post',
        data: user
    })
}
// Log in
export function isLogin() {
    return request({
        url: '/user/isLogin',
        method: 'get'
    })
}

4.2. Implement user's store

Here, because session is used as the login credential, the browser will automatically manage it, so there is no need to store the contents related to the token.

actions.js:

import { login }from "@/api/user";
export const actions = {
  // User login
  async login({ commit }, user) {
   try {
       await login(user);
       commit('SET_USERNAME', user.username);
   }catch (e) {
       return Promise.reject(e);
   }
  }
};

getter.js:

export const getters = {
    username: state => state.username
};

mutations.js:

export const mutations = {
    SET_USERNAME: (state, username) => {
        state.username = username;
    }
};

index.js:

import { getters } from './getters';
import { actions } from './actions';
import { mutations } from './mutations';
export const state = {
    username: ''
};
const namespaced = true;
export const note = {
    namespaced,
    state,
    getters,
    actions,
    mutations
};

Next, you only need to call actions and commit in the corresponding places.

methods: {
	confirm: function() {
    	try {
        	let user = {'username' : this.userInput, 'password' : this.passInput};
            let that = this;
            this.$store.dispatch('user/login', user).then(() => {
            	that.showLogin = false;
            });
	    } catch (err) {
    		alert(err);
		}
    },
    logout: function() {
    	this.$store.commit('user/SET_USERNAME', null);
    }
}

4.3. Set automatic page Jump without login

Some pages can only be accessed after logging in. If you don't log in, you need to let him jump directly to the login page. This is a common operation. Previously, it was realized by directly if adding window.location.href. However, under the current framework, we can realize this requirement through Vue router metadata configuration and navigation guard, Here, take a note editing page editNode.vue as an example. Only logged in users can access this page, otherwise they will jump to the note list.

First, configure this route in router.js and add a metadata requireligin to it, indicating that login is required to access this page.

path: '/note',
component: Layout,
// redirect: '',
name: 'note',
meta: { title: 'Note List' },
children: [
	...
    {
    	path: 'editNote/:address',
        name: 'editNote',
        component: () => import('@/views/note/editNote.vue'),
        meta: { requireLogin: true },
        props: true
	}
]

Then write the filtering logic. Here, we judge whether to log in according to whether the user.uesrname in the store is empty. If it is in router.js, the reference to the store cannot be obtained (it may also be possible, but I don't know how to do it at present). Therefore, I write the filtering logic to main.js, where there is an existing store instance:

const app = createApp(App)
router.beforeEach((to) => {
    if(to.meta.requireLogin && !store.state.user.username) {
        return {
            path: '/note/list'
        }
    }
});
app.use(router);
app.use(store);
app.mount('#app');

The effect of this is that if you visit localhost:8080/note/editNote without logging in, you will directly jump to / note/list.

5. Reference marked.js and highlight.js

These two technologies may not be particularly common. They are used in my project. The former can parse the markdown text into html text, and the latter can highlight the code fields in html. Therefore, I think there should be a lot of combinations of the two.

5.1. Installation

The installation is simple. Use the following command under the project root directory:

npm install marked --save
npm install highlight --save

5.2. Use

The following code should be in the < script > section of the vue file of the component.

  import marked from "marked";
  import hljs from 'highlight.js';
  // Change the highlight style of code by introducing different css
  import 'highlight.js/styles/atom-one-dark.css'
  var rendererMD = new marked.Renderer();
  marked.setOptions({
    renderer: rendererMD,
    gfm: true,
    tables: true,
    breaks: false,
    pedantic: false,
    sanitize: false,
    smartLists: true,
    smartypants: false
  });
  // Sets the code to highlight with highlight
  marked.setOptions({
    highlight: function (code) {
      return hljs.highlightAuto(code).value;
    }
  });
  export default {
    name: 'list',
    props: ['address'],
    data() {
      return {
        detail: '',
        picSrc: ''
      }
    },
    created() {
      let that = this;
      getNoteDetail(this.address).then(res => {
		// Here is the rewriting of the image parsing method, converting it from a relative address to the absolute address of the image server
        rendererMD.image = function(href) {
          return '<image src="noteraw/' + that.address.substr(0, that.address.lastIndexOf('/')) + '/' + href.replace("./", "") + '">'
        };
        that.detail = marked(res);
      })

    }
  }

Posted by jjbarnone on Sun, 19 Sep 2021 01:48:38 -0700