Last time, handsome Koha introduced the back-end construction of the live broadcast platform project to the old iron, this time let Koha take you to build the front frame.

1. Create front-end projects

Of course, the first step in building the framework of a project is to create a project. CMD, type vue create myLive, then press Enter. Then, after a few moments, our initialization project is created.

Next we use the editor to open the project we just created. I don’t have to remind you that VS Code is the best. This is the project we just created. Below is our project catalog.

Then we can type NPM run serve in CMD, and then we can open the relevant website by prompting to see our initial configuration.

2. Initialize the project

Did you guys see that screen up there? Is it totally inconsistent with our ultimate goal? Let’s have a plastic surgery on the stick and slowly shape it into what we want to see in the end.

2.1 Initializing related plug-in modules

Replace the contents of package.json file. In this case, we installed all the plug-in modules, so we don’t need to install them one by one. Enter CNPM install to install the plugin.

{
  "name": "mylive"."version": "0.1.0 from"."private": true."scripts": {
    "serve": "vue-cli-service serve --open"."build": "vue-cli-service build"."lint": "vue-cli-service lint"
  },
  "dependencies": {
    "axios": "^ 0.20.0"."core-js": "^ 3.6.5." "."feather-common": "^ 1.0.0"."flv.js": "^ 1.5.0." "."less": "^ 3.12.2"."less-loader": "^ 7.0.0." "."node-sass": "^ 4.13.1." "."sass-loader": "^ 8.0.2." "."socket.io-client": "^ 2.3.0." "."view-design": "^ 4.4.1"."vue": "^ 2.6.10"."vue-baberrage": "^ 3.1.0"."vue-router": "^ 3.1.3"."vue-video-player": "^ 5.0.2"."vuex": "^ 3.5.1 track of"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~ 4.5.0." "."@vue/cli-plugin-eslint": "~ 4.5.0." "."@vue/cli-service": "~ 4.5.0." "."babel-eslint": "^ 10.1.0"."eslint": "^ 6.7.2." "."eslint-plugin-vue": "^ 6.2.2." "."node-sass": "^ 4.13.1." "."style-resources-loader": "^ 1.3.3." "."vue-template-compiler": "^ 2.6.11." "
  },
  "eslintConfig": {
    "root": true."env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential"."eslint:recommended"]."parserOptions": {
      "parser": "babel-eslint"
    },
    "rules": {}},"browserslist": [
    "1%" >."last 2 versions"."not dead"]}Copy the code

2.2 Initializing the UI Framework

Clothes make the man. Both let our old iron are so handsome, the total can not let their own procedures become ugly, that can not foil our noble temperament. So, we used one of the best iViews in the industry. Add the following lines to main.js (before new Vue()).

/ / into the iview
import ViewUI from 'view-design';
import 'view-design/dist/styles/iview.css';
Vue.use(ViewUI);
Copy the code

With such beautiful UI components, why not test them? Add a Button component to app.vue. Then open the web page to see the effect ~

2.3 Initializing Axios

Create http.js in SRC/Assets /js and initialize axios.

/* * @description: * @author: Koha * @lasteditors: Koha * @date: 2020-08-31 15:49:05 * @LasteditTime: 2020-09-03 10:33:20 * @Copyright: 1.0.0 */
import axios from 'axios'; / / introduce axios
import Qs from 'qs'; // Introduce the QS module to serialize post data
let myAxios = axios.create({})
myAxios.defaults.headers.post['Content-Type'] = 'application/json';

// HTTP request interceptor
myAxios.interceptors.request.use(async config => {
        /* const token = await getSync("token").then(res=>{ return res.token }) */ 
        let token = localStorage.getItem("living_token")
        if (token) { // Determine whether a token exists, and if so, add a token to each HTTP header
            config.headers.authorization = decodeURI(token)  // Request header with token
        }
        return config
    },
    err= > {
        return Promise.reject(err)
    }
)

// HTTP Response interceptor
myAxios.interceptors.response.use(
    response= > {
        // Intercept the response and do unified processing
        //console.log("response.data", response.data)
        if (response.data.code) {
            switch (response.data.code) {
                case 1002:
                    store.state.isLogin = false
                    router.replace({
                    path: 'login'.query: {
                            redirect: router.currentRoute.fullPath
                        }
                    })
                }
        }
        return response
    },
    // Interface error status handling, that is, when no response
    error= > {
        return Promise.reject(error) // Return the error message returned by the interface})export default myAxios
Copy the code

2.4 Replace the relevant files of the web page

Against 2.4.1 replace the favicon. Ico

Replace the favicon.ico file under public with your favorite image. In fact, you just need to change your favorite picture into this name and then throw it in, you can not tell others oh ~ then restart vue, you can see our icon changed, found no change friends can CTRL + F5 (clear cache refresh).

2.4.2 Changing the TAB title

Public under index.html, modify the content in the title tag to Koha live.

<! DOCTYPE html> <html lang="en"> <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 %> The < title > kohane live < / title > < / head > < body > < noscript > < strong > We 'r e sorry but % > < % = htmlWebpackPlugin. The options. The 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> </html>Copy the code

The end result is as follows

2.5 Importing relevant JS files

2.5.1 Importing bus Threads

What is a bus thread? In my understanding of bus threads, bus threads are an implementation of the publish-subscribe pattern. Because at present the old iron people are building their own live broadcast room, so Koyu will use live broadcast room for example, what is the analysis of subscription model. For example, old iron likes playing fast music man, and then sees a fast music man playing a handsome anchor (such as Koba, crazy hint), and then can’t sleep a day without watching. But this anchor has a habit of not liking regular live broadcasts. Now the audience can’t always be in the studio, right? So what to do? This is where the publish-subscribe model comes in. Suppose passer-by A and B both subscribe to anchor A, while passer-by A and passer-by C subscribe to another anchor B. At this point, there will be the following two situations:

1. When anchor A goes online, it will automatically send A message to passer-by A and passer-by B, while passer-by C will not receive any information.

2. When anchor B goes online, it will automatically send a message to passer-by A and passer-by B, while passer-by C will not receive any information.

These are my thoughts on the publish-subscribe model and bus threads.

Add bus.js under SRC /assets/js

import Vue from "vue";
const bus = new Vue();
export default bus;
Copy the code

2.5.2 introduced common. Js

Common.js are some of the commonly used methods for feather encapsulation. Add common.js under SRC /assets/js

/* * @description: Public method * @author: Koha * @lasteditors: Koha * @date: 2020-09-06 15:24:07 * @lasteditTime: 2020-09-06 16:25:28 * @Copyright: 1.0.0 */

class Common{
    // Generate len bits of random string
    getCode(len){
        var chars = ['0'.'1'.'2'.'3'.'4'.'5'.'6'.'7'.'8'.'9'.'A'.'B'.'C'.'D'.'E'.'F'.'G'.'H'.'I'.'J'.'K'.'L'.'M'.'N'.'O'.'P'.'Q'.'R'.'S'.'T'.'U'.'V'.'W'.'X'.'Y'.'Z'.'a'.'b'.'c'.'d'.'e'.'f'.'g'.'h'.'i'.'j'.'k'.'l'.'m'.'n'.'o'.'p'.'q'.'r'.'s'.'t'.'u'.'v'.'w'.'x'.'y'.'z'];
        var nums = "";
        for (var i = 0; i < len; i++) {
        var id = parseInt(Math.random() * 62);
        nums += chars[id];
        }
        return nums;
    }

    // Get the single data in the URL
    getUrlParam(name){
        var reg = new RegExp("(^ | &)"+ name +"= (/ ^ & *) (& | $)");
        var r = window.location.search.substr(1).match(reg);
        if(r! =null)return decodeURI(r[2]); return null;
    }

    // Get all the data in the URL
    getUrlParams(){
        let url = window.location.search;  / / in the url? The rest of it
        console.log(window.location)
        url = url.substring(1);    / / remove?
        let dataObj = {};
        if(url.indexOf('&') > -1){
            url = url.split('&');
            for(let i=0; i<url.length; i++){
                let arr = url[i].split('=');
                dataObj[arr[0]] = arr[1]; }}else{
            url = url.split('=');
            dataObj[url[0]]= url[1];
        }
        return dataObj;
    }

    / / the queue
    myQueue(){
        let items = []
        this.list = () = >{
            return items
        }
        // Add elements to the end of the queue
        this.enqueue = (ele) = >{
            items.push(ele)
        }
        // Remove the element from the head of the queue
        this.dequeue = (ele) = >{
            items.shift()
        }
        // return the first item in the queue
        this.front = () = >{
            return items[0]}// return the last item in the queue
        this.end = () = >{
            return items[items.length-1]}// Returns whether the queue is empty
        this.isEmpty = () = >{
            return items.length === 0
        }
        Return the length of the queue
        this.size = () = >{
            return items.length
        }
        // Prints the queue
        this.print = () = >{
            console.log(items.toString())
        }
    }
}


// Buffeting (only perform last click)
export const Debounce = (fn, t) = > {
    let delay = t || 500;
    let timer;
    return function () {
        let args = arguments;
        if(timer){
            clearTimeout(timer);
        }
        timer = setTimeout(() = > {
            timer = null;
            fn.apply(this, args); }, delay); }};// Throttling (execute once first, execute again after t/1000 seconds))
export const Throttle = (fn, t) = > {
    let last;
    let timer;
    let interval = t || 500;
    return function () {
        let args = arguments;
        let now = +new Date(a);if (last && now - last < interval) {
            clearTimeout(timer);
            timer = setTimeout(() = > {
                last = now;
                fn.apply(this, args);
            }, interval);
        } else {
            last = now;
            fn.apply(this, args); }}};const common = new Common();
export {common}
Copy the code

In main.js, inject common.js into the vue prototype.

2.5.3 into config. Js

Config.js is a configuration file used to configure non-urls in production and development environments

/ @ description: * * * @ author: kohane * @ making: https://github.com/lyff1006 * @ lastEditors: kohane * @ the Date: 2020-09-01 20:20:07 * @lasteditTime: 2020-09-07 15:24:43 * @copyright: 1.0.0 */
const env = process.env
const baseUrl = env.NODE_ENV==="development"?"http://127.0.0.1":"http://www.example.com"
const baseEnv = {
    env:env.NODE_ENV,// Current environment
    mode:env.VUE_APP_CURRENTMODE,// Current mode
    webUrl : env.VUE_APP_CURRENTMODE==="electron"?`${baseUrl}: 8512 `:"/webserve".socketUrl : {
        //barrage:`${baseUrl}:8511/barrage`,
        barrage:env.NODE_ENV==="development"?`${baseUrl}:8511/barrage`:`${baseUrl}/barrage`,},//livingUrl : env.NODE_ENV==="development"? `${baseUrl}:8000/live`:`${baseUrl}/live/live`
    livingUrl : env.NODE_ENV==="development"?`${baseUrl}:8000/live`:`${baseUrl}/live/live`

}

export default baseEnv
Copy the code

Inject config.js into the vue prototype in main.js.

3. Configure the vue. Config. Js

Create vue.config.js in the root directory. As anyone who has used Vuecli3 knows, this file is the default for vuecli and is mainly used to configure webPack-related content.

/ @ description: * * * @ author: kohane * @ making: https://github.com/lyff1006 * @ lastEditors: kohane * @ the Date: 2019-10-09 21:55:04 * @lasteditTime: 2020-09-07 15:31:10 * @copyright: 1.0.0 */

const path = require('path');

function addStyleResource(rule) {
    rule.use('style-resource')
        .loader('style-resources-loader')
        .options({
            patterns: [path.resolve(__dirname, "./src/assets/style/common.less")]})}module.exports = {
    / / eslint switch
    lintOnSave: false.// The generation environment determines whether to generate a map file
    productionSourceMap: false.devServer: {
        host: '0.0.0.0'.// Proxy configuration
        proxy: {
            '/webserve': {
                target: 'http://127.0.0.1:8512'.ws: true.changeOrigin: true.pathRewrite: {
                    '^/webserve': ' '}}},},chainWebpack: (config) = > {
        / / configuration is less
        const types = ['vue-modules'.'vue'.'normal-modules'.'normal']
        types.forEach(type= > addStyleResource(config.module.rule('less').oneOf(type)))
    },
}
Copy the code

4. Configuration. Gitinore

This is a git configuration file that reminds Git which files need to be uploaded to the Git repository and which files do not. This is a non-essential item and can be ignored if you do not use git

.DS_Store
node_modules
/dist


# local env files
.env.local
.env.*.local

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

Copy the code

summary

This section mainly introduces how to build a front-end engineering, and some initial configuration of the project. I was going to go straight to the interface, but on second thought, it would have been better to follow normal development logic. That is to say, build the framework first and then polish the code (a good framework can really make the development process much more efficient), so the interface has been pushed back.

Think koba taught also broad to get words to wave praise and attention ~

Ps: pure original, reproduced please indicate the source