Original text: My github article
Follow the official account: wechat search web stack advanced; Receive more dry goods
1, Opening
- vue3. The 0 beta version is officially launched. As a new technology lover, the new project will officially use vue3 0 development; Next, summarize (the firm mastery of their own technology) and introduce (share the ape friends in need)
- The last blog introduced vue3 0 common grammar and development skills; If necessary, please click Vue3.0 advanced, environment construction, use of related API s
- If you think it's useful for you, github will order a star
- Project GitHub address: https://github.com/laijinxian/vue3-typescript-template
2, Project introduction (mobile terminal)
- 1) Technology stack: vue3 + vuex + typescript + webpack + vant UI + Axios + less + postcss pxtorem (REM adaptation)
- 2) Why the official build tool vite is not used: there are really many vite pits. Sometimes the normal way of writing webpack is OK, and an error is reported on vite; It's useless for vite's github to mention Issues. The maintenance personnel answered casually and turned off my Issues. I'm also drunk;
- 3) However, I still look forward to vite. Wait for him to mature and use it formally;
- 4) Points involved: at present, only a few functions in the early stage of the project are posted
- webpack require automatic registration of routing and asynchronous group price
- axios request encapsulation (request interception, response interception, request cancellation, unified processing)
- vuex service modularization and unified processing of takeover requests
3, Project construction
Refer to the previous article Vue3.0 advanced, environment construction, use of related API s
- vue cli, vue download the latest version
- Execute the command vue create my_app_name
- After executing the above command, choose manual configuration (the third one) instead of default configuration. There are many things we can't use. My choice is shown in the figure below:
3, Main functions of the project
1. Webpack requires automatic registration of routing and asynchronous group pricing
// The file is in global. Under utils ts // Distinguish whether the file is automatically registered as a component, and the vue file defines the isComponents field; Distinguish whether to automatically register as a route definition isRouter field // The usage methods are in main The method asyncComponent() in TS and the index. In the routing file router TS method vueRouters() import { defineAsyncComponent } from 'vue' import { app } from '../main' // Get all vue files function getComponent() { return require.context('../views', true, /\.vue$/); } // Convert initial to uppercase function letterToUpperCase(str: string) { return str.charAt(0).toUpperCase() + str.slice(1); } // Convert first letter to lowercase function letterToLowerCase(str: string) { return str.charAt(0).toLowerCase() + str.slice(1); } export const asyncComponent = function () { // Get file global object const requireComponents = getComponent(); requireComponents.keys().forEach((fileSrc: string) => { const viewSrc = requireComponents(fileSrc); const fileNameSrc = fileSrc.replace(/^\.\//, '') const file = viewSrc.default; if (viewSrc.default.isComponents) { // Asynchronous registration component let componentRoot = defineAsyncComponent( () => import(`@/views/${fileNameSrc}`) ) app.component(letterToUpperCase(file.name), componentRoot) } }); }; // Get route file export const vueRouters = function () { const routerList: any = []; const requireRouters = getComponent(); requireRouters.keys().forEach((fileSrc: string) => { // Get the file name under the components file const viewSrc = requireRouters(fileSrc); const file = viewSrc.default; // Initial to capital const routerName = letterToUpperCase(file.name); // Initial to lowercase const routerPath = letterToLowerCase(file.name); // Set routing path const fileNameSrc = fileSrc.replace(/^\.\//, ''); if (file.isRouter) { routerList.push({ path: `/${routerPath}`, name: `${routerName}`, component: () => import(`@/views/${fileNameSrc}`) }); } }); return routerList; };
2. axios request encapsulation (request interception, response interception, cancellation request, unified processing)
import axios, { AxiosRequestConfig, AxiosResponse, Canceler } from 'axios' import router from '@/router' import { Toast } from 'vant' if (process.env.NODE_ENV === 'development') { // development environment axios.defaults.baseURL = `https://test-mobileapi.qinlinkeji.com/api/` } else { // Formal environment axios.defaults.baseURL = `Official environment address` } let sourceAjaxList: Canceler[] = [] export const axionInit = () => { axios.interceptors.request.use((config: AxiosRequestConfig) => { // Set the cancel token to cancel the request (when a 401 occurs on an interface, cancel the subsequent multiple requests to avoid several error prompts) config.cancelToken = new axios.CancelToken(function executor(cancel: Canceler): void { sourceAjaxList.push(cancel) }) // sessionId exists. Add sessionId to all requests if (localStorage.getItem(`h5_sessionId`) && config.url!.indexOf('/user/login') < 0) config.url += ('sessionId=' + localStorage.getItem(`h5_sessionId`)) if (!config.data) config.data = {} return config }, function (error) { // Throw error return Promise.reject(error) }) axios.interceptors.response.use((response: AxiosResponse) => { const { status, data } = response if (status === 200) { // If no error occurs, output data directly to the callback function if (data.code === 0) { return data } else if (data.code === 401) { // If there is no login or login failure, cancel the subsequent request sourceAjaxList.length && sourceAjaxList.length > 0 && sourceAjaxList.forEach((ajaxCancel, index) => { ajaxCancel() // Cancel request delete sourceAjaxList[index] }) Toast({ message: data.message, duration: 2000 }) return router.push('/login') } else { return data } } else { return response } }, error => { const { response } = error // Error handling http code or server or background error reporting if (!response || response.status === 404 || response.status === 500) { if (!response) { console.error(`404 error %o ${error}`) } else { if (response.data && response.data.message) { Toast.fail({ message: 'Request exception, please try again later!', duration: 2000 }) } } } return Promise.reject(error.message) }) }
3. vuex business modularization and unified processing of takeover requests
// See the project store directory for details import { Module } from 'vuex' import { IGlobalState } from '../../index' import * as Types from './types' import { IHomeState, ICity, IAccessControl, ICommonlyUsedDoor } from './interface' import axios from 'axios' const state: IHomeState = { cityList: [], commonlyUsedDoor: { doorControlId: '', doorControlName: '' }, accessControlList: [] } const home: Module<IHomeState, IGlobalState> = { namespaced: true, state, actions: { // Get cell list async [Types.GET_CITY_LIST]({ commit }) { const result = await axios.post(`auth/v2/getApplyListGroupByCommunityH5?`) commit(Types.GET_CITY_LIST, result.data) }, // Access control list of community async [Types.GET_ACCESS_CONTROL_LIST]({ commit }, data) { const result = await axios.post(`doorcontrol/v2/queryUserDoor?`, { ...data }) commit(Types.GET_ACCESS_CONTROL_LIST, result.data.userDoorDTOS) commit(Types.SET_COMMONLY_USERDOOR, result.data.commonlyUsedDoor) }, }, mutations: { // Set cell list [Types.GET_CITY_LIST](state, cityList: ICity[]) { if (cityList.length !== 0) state.cityList = cityList }, // Set community access control list [Types.GET_ACCESS_CONTROL_LIST](state, accessControlList: IAccessControl[]) { if (accessControlList.length !== 0) return state.accessControlList = accessControlList }, // Set current cell [Types.SET_COMMONLY_USERDOOR](state, commonlyUsedDoor: ICommonlyUsedDoor) { state.commonlyUsedDoor = commonlyUsedDoor } } } export default home
4. home file code
<template> <div class="home-container"> <header> <Suspense> <template #default> <HomeSwiper></HomeSwiper> </template> <template #fallback> <div>...loading</div> </template> </Suspense> </header> <section> <Suspense> <template #default> <HomeContent :cityList="cityList" :accessControlList="accessControlList" ></HomeContent> </template> <template #fallback> <div>...loading</div> </template> </Suspense> </section> </div> </template> <script lang="ts"> import { defineComponent, reactive, toRefs, computed, onMounted } from 'vue' import { Store, useStore } from 'vuex' import { IGlobalState } from "@/store"; import * as Types from "@/store/modules/Home/types"; /** * Purpose of the hook: personal understanding: * 1,Public method similar to global; You can consider mentioning it in tool class functions * 2,cityList, accessControlList They are all data for display only, without subsequent modification; Therefore, it can be considered to be extracted and managed by the parent component * 3,If the method has more internal logic and other pages need to be used, it is more appropriate to extract * 4,Of course, there is no problem to choose freely and implement it in the step method, but it is not conducive to the reference of other pages * 5,vuex actions,mutations Function logic should be as few as possible to facilitate maintenance; Logical processing should be inside the page */ function useContentData(store: Store<IGlobalState>) { let cityList = computed(() => store.state.home.cityList) let accessControlList = computed(() => store.state.home.accessControlList) onMounted(() => { if (cityList.value.length === 0) store.dispatch(`home/${Types.GET_CITY_LIST}`) if (accessControlList.value.length === 0) store.dispatch(`home/${Types.GET_ACCESS_CONTROL_LIST}`, 13) }) return { cityList, accessControlList } } export default defineComponent({ name: 'home', isComponents: true, setup() { let store = useStore<IGlobalState>() let { cityList, accessControlList } = useContentData(store) const state = reactive({ active: 0, }) return { ...toRefs(state), cityList, accessControlList } } }) </script> <style scoped lang="less"> .home-container { height: 100%; background: #f6f6f6; header { overflow: hidden; height: 500px; background-size: cover; background-position: center 0; background-image: url("~@/assets/images/home_page_bg.png"); } section { position: relative; top: -120px; padding: 0 20px; } } </style>
4, Project ui
5, Conclusion
The above is the summary of personal actual project development. If there is anything wrong, please leave a message and correct it