preface

The company has been using Vue2 to develop the project. At the last meeting, the director said, “Let’s use VUE3 for our next backstage project. I told you when the project was not busy before, I don’t know if you have learned…” “And let me build the whole structure. Emm.. I’m just kidding. I hope you can learn something useful from this article. If you have any questions, please correct them.

Create a project

This demo uses only part of the Vite configuration. To learn more about vite configuration, go to vite Configuration

Initialize the

Demo uses the VUE-TS template, so: NPM init @vitejs/app vite-app –template vue-ts: NPM install, NPM run dev, NPM run dev

Install dependencies

Style preprocessing: NPM install sass

To use the nodejs module: NPM install @types/node -d otherwise:

Make some simple changes

The main modification is the configuration of vite.config.ts.

1. Configure the path alias for the module

import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import { resolve } from 'path' export default DefineConfig ({base: '/', // plugins: [vue()], resolve: {alias: {"@": Resolve (__dirname, "SRC"), / / path alias extensions: [' js', 'vue', 'json', 'SCSS' and 'ts',' * '], / / import to omit the extension of the list}}})Copy the code

2. Pack the configuration

Build: {// package configuration assetsDir: './static', // rollupOptions: {input: {// entry file main: Resolve (__dirname, 'index.html'), // other entries // nested: resolve(__dirname, 'xxxx.index')}},Copy the code

3. Local proxy

Server: {host: '0.0.0.0', // Specify the server hostname port: 8084, // specify the server port. Open: false, // Whether the application is automatically opened in the browser when the server starts. The default is false proxy: {'/API: {target: 'do you want the address of the agent, changeOrigin: true, rewrite: (path) = > path. The replace (/ ^ \ / API /,' ')},}},Copy the code

Then change the build command in package.json to: “build”: “vite build”

start

vue-router4.x

NPM install [email protected], let it run first, let’s create a few new folders and files:

  • layouts/error.vue
  • router/index.ts
  • The router/modules/business. Ts / / configure business routing module
  • view/business/manage.vue
  • view/login/login.vue

Once built, the directory should look like this:

Router /index.ts router/index.ts

#### router/index.ts import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' const routes: Array < RouteRecordRaw > = [{path: "/", redirect: "/ login,"}, / / * * * * * * * * * * login * * * * * * * * * * {path: / login, name: "login", component: () => import("@/view/login/login.vue").catch(() => { }) }, // **********404********** { path: "/:catchAll(.*)", name: '404', component: () => import("@/layouts/error.vue").catch(() => { }) }, ]; Const Router = createRouter({history: createWebHistory(), // routes with history mode,}); export default Router;Copy the code

Introduced in main.ts:

#### main.ts import {createApp} from 'vue' import App from './ app. vue' import Router from './ Router '// import const App = CreateApp (App) app.use(Router) // Use app.mount('# App ')Copy the code

Finally, modify the contents of app.vue:

#### App.vue <template> <router-view></router-view> </template> <script lang="ts"> import { defineComponent } from 'vue'  export default defineComponent({ name: 'App', }) </script>Copy the code

I thought it would run without any problems, but it came as a Surprise!Leave it alone. Keep opening itNetworkThe address of the console printed the following thing, good guy ~, did not understand (0.0)!!

The module script is incorrect. This is not mentality?? Then Baidu for nearly half an hour, no fruit ~, and then I would like to be some dependence is not installed or file reference path is wrong? Then open theLocalAs I expected…And then he followed it up and found itnode_modules/vite/dist/client/client.mjs..mjsDocument mess (viteUpdated again when I wasn’t looking)~

Before the update:

After the update:

Because in the viet-env.d.ts file:

#### vite-env.d.ts <reference types="vite/client" /> // The clientCopy the code

So add.mjs to the list of extension names you want to omit when importing.

extensions: ['.js', '.vue', '.json', '.scss', '.ts', '.mjs', '*'],
Copy the code

There should be no problem running it again.

element-plus

NPM install elemental-plus. Elemental-plus components use English by default. Then we need to configure the relevant language in main.ts.

#### main.ts import ElementPlus from 'element-plus'; import 'element-plus/lib/theme-chalk/index.css'; import locale from 'element-plus/lib/locale/lang/zh-cn'; Use (ElementPlus,{locale})Copy the code

Add reset. SCSS to assets to reset the style.

#### assets/reset.scss body,dl,dd,h1,h2,h3,h4,h5,h6,p,form { margin: 0; } ol,ul { margin: 0; padding: 0; } li { list-style: none } input,button,textarea { padding: 0; */ table {/* set border collapse for table */ border collapse: */ table {/* set border collapse for table * collapse; /* Set spacing between table borders */ border-spacing: 0px; } /* a {text-decoration: none; } a:hover { text-decoration: none; } individual browser compatible for semantic labels / * * / header section, footer, value, nav, main, article, figure {display: block; } h1, h2, h3, h4, h5, and h6, em, I, b, cite {/ * font style bold * / not the font - weight: normal; font-style: normal; } a,input,button {/* clear click shadow */ -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } body * {/* Select text Settings */ -weibkit-user-select: none; /* Disable text scaling */ -webkit-text-size-adjust: 100%; } dl,dd,h1,h2,h3,h4,h5,h6,p,div,li,ul,ol{ box-sizing: border-box; }Copy the code

If in useElement font iconWhen, misfortune appearedThe fonts iconDo not display, or display the box case. You can put filesnode_modules/element-plus/lib/theme-chalk/fontsUnder the.ttf,.woffCopy to SRC/Assetsdiystyle.scssHandles the font icon in themain.tsThe introduction of:

#### diystyle.scs @font-face { font-family: 'element-icons'; src: url("./fonts/element-icons.woff") format("woff"), url("./fonts/element-icons.ttf") format("truetype"); font-weight: normal; font-display: "auto"; font-style: normal; } [class^="el-icon-"], [class*=" el-icon-"] { font-family: 'element-icons' ! important; speak: none; font-style: normal; font-weight: normal; font-variant: normal; text-transform: none; line-height: 1; vertical-align: baseline; display: inline-block; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } #### main.ts import '@/assets/diystyle.scss';Copy the code

vuex4.x

Run: NPM install [email protected], create a new directory under SRC:

  • Store /modules/menu.ts // is used to simulate the menu data returned by the back-end interface
  • store/getters.ts
  • store/index.ts

To emulate a menu in store/modules/menu.ts:

#### store/modules/menu.ts interface MENU { name: string; path: string; icon? : string; children? : MENU[]; // Define menus with 1} interface STATE {menus: Array<MENU>; // Define array type 2} const state: state = {menus: [{name: "business", path: "/business", icon: "el-icon-s-shop", children: [{name: "business management", path: "/ business/businessManage," icon: ", "},],}},] const mutations = {SET_MENU: (the state: any, data: any) => { state.menu = data } } const action = {} export default { namespace: true, state, mutations, action }Copy the code

Store/getters. Ts for:

#### store/getters.ts

const getters = {
    menus: (state: any) => state.menu.menus,
}

export default getters
Copy the code

Store /index.ts introduces modules to modules:

#### store/index.ts import { createStore } from 'vuex' import getters from './getters' interface MODULES { [key: string]: any; } const modulesList = require.context("./modules", false, /\.ts$/); const modules: MODULES = {} modulesList.keys().forEach((modulePath:any) => { const moduleName: String = modulePath. Replace (/ ^ \ \ / (. *) \ \ w + $/, '$1') / / filename const value: Any = modulesList(modulePath) // Take the content of the file modules[moduleName] = value.default // assign}) const Store = createStore({modules, getters }) export default StoreCopy the code

A meal operation.. It turned out to be a tragedy…

And then went to Baidu for a long time, the result isviteCan’t userequire, oh my God! I want toImport multiple modules from the file systemHow to do? I did not give up and went to the document, found what I want (-_-)..

It really proves that saying…

I’m wrong, I’ll change, I’ll change it right away.

#### store/index.ts import { createStore } from 'vuex' import getters from './getters' interface MODULES { [key: string]: any; } // const modulesList = require.context("./modules", false, /\.ts$/); const modulesList = import.meta.globEager("./modules/*.ts") const modules: MODULES = {} for (const key in modulesList) { const moduleName: String = key. Replace (/ ^ \. / / modules / / (. *) \ \ w + $/, '$1') / / filename const value: Any = modulesList[key] // Fetch the content of the file modules[moduleName] = value.default // Assign a value} // modulesList.keys().forEach((modulePath:any) => { // const moduleName: String = modulePath. Replace (/ ^ \ \ / (. *) \ \ w + $/, '$1') / / in the file name / / const value: Any = modulesList(modulePath) // modules[moduleName] = value.default // assignment //}) const Store = createStore({modulesPath = modulePath) modules, getters }) export default StoreCopy the code

Well, with all the preparation above, I must write something to reflect it (manual dog head). The structure of the entire page should look like this.

After the overall layout of the interface is planned, the next step is to “assemble” the link, (@_@)~ create several files:

  • Layouts /main.vue // Overall layout
  • Layouts/components/crumbs. Vue / / bread crumbs
  • Layouts/components/header. Vue / / head
  • Layouts /Interface // Is a directory that houses modules’ interfaces.
  • / / SRC/common/beforRouter ts as a simple route to intercept

Route interception uses the beforeEach navigation hook, which is easy to implement and can be introduced in main.ts:

#### common/beforRouter. Ts import Router from '@/ Router '// Intercepting Router. BeforeEach ((to: any, form: any, next: any) => { if (to.path === '/login') { next(); } else { if (localStorage.getItem('token')) { next() } else { next({ path: '/login' }) } } }) #### main.ts import './common/beforRouter'Copy the code

Let’s go on to improve the class capacity of the login page:

#### view/login/login.vue <template> <div class="login"> <div class="forms"> <div class="title" Width ="80px"> <el-form-item label=" "Class ="is-required" >< el-input V-model ="user" size="small" placeholder=" @keyup.enter="goIndex" ></el-input> </el-form-item> <el-form-item label=" n&nbsp; &nbsp; &nbsp; &nbsp; Code: "Class ="is-required" > <el-input V-model =" PWD" size="small" placeholder=" please input password "show-password@keyup. enter="goIndex" ></ el-form-item> </el-form-item label=" "Class ="is-required" > <el-input V-model ="verCode" size="small" placeholder=" @keyup.enter="goIndex" style="width:50%" ></el-input> <div class="code"> <verificationCode :identify-code="code" /> </div> </el-form-item> </el-form> <div class="btn"> <el-button style="width:100%;" Size ="small" type="primary" @click="goIndex" > </el-button> </div> </div> </template> <script lang="ts"> // Reactive: the realization method of the responsive data / / toRefs: the object of multiple attributes into responsive data / / getCurrentInstance: access to the current instance / / onMounted: {reactive, toRefs, getCurrentInstance, onMounted} from "vue"; import { useRouter } from "vue-router"; import { useStore } from "vuex"; import { ElMessage } from "element-plus"; import "./interface/Login"; / / the interface defined before the introduction of the import verificationCode from "@ / components/verificationCode. Vue"; Export default {name: "Login", components: {verificationCode,}, setup() {const _this: any = getCurrentInstance(); Const store = useStore<any>(); // use vuex const menus = store.state.menu. Menus; Const data: LoginData = reactive({user: "admin", // PWD: "123456", // password verCode: Router: useRouter(), // goIndex: () => {if (! Data.user) {ElMessage({message: "Please enter user name ~", type: "warning", duration: 2000,}); return false; } if (! Data.pwd) {ElMessage({message: "Please enter password ~", type: "warning", duration: 2000,}); return false; } if (! Data.vercode) {ElMessage({message: "Please enter verification code ~", type: "warning", duration: 2000,}); return false; } if (data.verCode ! = data.code) {ElMessage({message: "verification code error ~", type: "warning", duration: 2000,}); return false; } the if (data. User = = = "admin" & & data. PWD = = = "123456") {/ / simulation login const menuList: string | null = JSON. The stringify (menus); localStorage.setItem("menuList", menuList); localStorage.setItem("token", "456456456456456"); localStorage.setItem("userName", "admin"); data.router.push({ path: "/business" }); } else {ElMessage({message: "user name or password error ~", type: "warning", duration: 2000,}); return false; Rand (min: number, Max: number) {return math.floor (math.random () * (max-min)) + min; // Rand (min: number, Max: number) {return math.floor (math.random () * (max-min)) + min; }, // Update the captcode updateCode() {data.code = String(data.rand(1000, 9999)); //4 bit verification code},}); onMounted(() => { data.updateCode(); }); const refData = toRefs(data); return { ... refData, }; }}; </script>Copy the code

I won’t talk about the style here, but go straight to the picture above:

After entering the verification code to log in, you can see, combined with the previous things, you can see a general outline:

axios

NPM install axios install axios, create a few new files under SRC, again using the idea of importing multiple modules from the file system:

  • API /modules/admin.ts // stores interface functions
  • API/apilist.ts // imports modules files as modules
  • API /axios.ts // Simple AXIos encapsulation
  • API /url.ts // The interface address of the runtime environment –> baseURL

The logic in apilist.ts is basically the same as when using vuex.

#### API/apilist. ts const req = import.meta. GlobEager ("./modules/*.ts") // Define an API object interface ApiObj {[key: string]: any; } const api: ApiObj = {} for (const key in req) { const name: String = key. Replace (/ ^ \. / / modules / / (. *) \ \ w + $/, '$1') / / filename const value: Any = req[key] // Fetch the content of the file API [name] = value.default // Assignment} const API = API export default API #### API /modules/admin.ts import { AxiosPromise } from "axios"; import http from ".. /axios"; // encapsulate from API /axios.ts const admin ={userLogin(params: any): AxiosPromise<any> {return HTTP ({url: "/auth-service/common/login", // method: "POST", data:params,}); } } export default admin;Copy the code

Then mount the API globally:

# # # # main. Ts import API from ". / API/apiList "/ / mount app. Config. GlobalProperties. = $API APICopy the code

To use in view/login/login.vue:

#### view/login/login.vue import { getCurrentInstance } from "vue"; export default { setup() { const _this: any = getCurrentInstance(); Const API: any = _this.ctx.$API; Api.admin.userlogin (obj). Then ((res: any) => {..... }); }}Copy the code

The end of the

Now the company’s PC side project is based on this template to change, you can modify according to their business needs oh ~~ demo address: gitee.com/Srimr/vite-… References:

  • Vue3 Chinese document
  • Vite Chinese document
  • Element Plus
  • TypeScript