Source link: Github

Public account: wechat search front end tool person; Take more dry goods

A, the opening

  • Vue3.0 betaVersion officially launched, as a new technology lover, new projects will be officially usedvue3.0Development; Next, the conclusion (on the solid grasp of their own technology) introduction (share ape friends in need)
  • That was introduced in my last blog postvue3.0Common syntax and development skills; Please click on it if you need itVue3.0 advanced, environment construction, the use of relevant API
  • I thought it would be useful for yougithubPoint astar
  • projectgithubAddress:https://github.com/laijinxian/vue3-typescript-template

Ii. Project Introduction (Mobile Terminal)

  • 1) Technology Stack:Vue3 + vuex + typescript + webpack + vant-UI + AXIos + less + PostCSS - PxtoREM (REM adaptation)
  • 2) No official build toolsviteThe reason:vitePit is really a lot, sometimes normal writingwebpackNo problem, inviteOn the error; The kind of guy who looks like he’s confused,vitegithubMention Issues are useless, maintenance personnel casually answered the next on myIssuesTurn it off. I’m drunk, too;
  • 3) I’m still looking forward to itviteWait for him to mature before formal use;
  • 4) Involvement: Only a few functions of the initial stage of the project are posted at present
    • webpack requireAutomatic registration of routes and asynchronous group pricing
    • axiosRequest encapsulation (request interception, response interception, request cancellation, unified processing)
    • vuexService modularization and takeover requests are processed in a unified manner

Iii. Project construction

Please refer to the previous article on Vue3.0 progression, environment building and related API usage

  1. Vue - cli, vueDownload the latest version
  2. Execute the commandvue create my_app_name
  3. After executing the above command, choose manual configuration (the third one). Do not choose the default configuration, there are many we do not need, my choice is as follows:

    Iii. Main Functions of the project

    1. webpack requireAutomatic registration of routes and asynchronous group pricing

    // This file is in global.ts under utilsVue files define isComponents fields; Distinguishes whether an isRouter field is automatically registered for a route// Use methods in main.ts asyncComponent() and index.ts vueRouters() on router
    import { defineAsyncComponent } from 'vue'
    import { app } from '.. /main' import { IRouter } from './interface'  // Get all vue filesfunction getComponent() {  return require.context('.. /views'.true, /\.vue$/); }  // Capitalize the first letterfunction letterToUpperCase(str: string): string {  return str.charAt(0).toUpperCase() + str.slice(1); }  // Convert the first letter to lowercasefunction letterToLowerCase(str: string): string {  return str.charAt(0).toLowerCase() + str.slice(1); }  export const asyncComponent = (): void => {  // Get the 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) {  // Register components asynchronously let componentRoot = defineAsyncComponent(  () => import(`@/views/${fileNameSrc}`)  )   app.component(letterToUpperCase(file.name), componentRoot)  }  }); };  // Get the routing fileexport const vueRouters = (): IRouter[] => {   const routerList: IRouter[] = [];   const requireRouters = getComponent();   requireRouters.keys().forEach((fileSrc: string) => {  // Get the file name under components const viewSrc = requireRouters(fileSrc);   const file = viewSrc.default;  // Uppercase const routerName = letterToUpperCase(file.name);  // Change the first letter to lowercase const routerPath = letterToLowerCase(file.name);   const fileNameSrc = fileSrc.replace(/^\.\//, ' ');   if (file.isRouter) {  routerList.push({  path: `/${routerPath}`,  name: `${routerName}`,  component: () => import(`@/views/${fileNameSrc}`)  });  }  });  return routerList; }; Copy the code

    2. axiosRequest encapsulation (request interception, response interception, request cancellation, 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 environmentAxios.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. config.cancelToken = new axios.CancelToken(function executor(cancel: Canceler): void {  sourceAjaxList.push(cancel)  })  // sessionId exists add sessionIDS 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 an 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) { // Failed login or login failed to cancel the request sourceAjaxList.length && sourceAjaxList.length > 0 && sourceAjaxList.forEach((ajaxCancel, index) => { AjaxCancel () // Cancel the request delete sourceAjaxList[index]  })  Toast({  message: data.message,  duration: 2000  })  return router.push('/login')  } else {  return data  }  } else {  return data  }  }, error => {  const { response } = error // Here to handle error HTTP code or server or background error 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 abnormal, please try again later! '. duration: 2000  })  }  }  }  return Promise.reject(error.message)  }) } Copy the code

    3. vuexService modularization and takeover requests are processed in a unified manner

    // See the project store directory for detailsimport { Module } from 'vuex'
    import { IGlobalState, IAxiosResponseData } from '.. /.. /index'
    import * as Types from './types'
    import { IHomeState, ICity, IAccessControl, ICommonlyUsedDoor, AGetCtiy } from './interface'
    import qs from 'qs'; import * as API from './api'  const state: IHomeState = {  cityList: [],  communityId: 13,  commonlyUsedDoor: {  doorControlId: ' '. doorControlName: ' '  },  accessControlList: [] }  const home: Module<IHomeState, IGlobalState> = {  namespaced: true. state,  actions: { // Get the cell list async [Types.GET_CITY_LIST]({ commit }) {  const result = await API.getCityList<IAxiosResponseData>()  if(result.code ! = = 0)return  commit(Types.GET_CITY_LIST, result.data)  }, // Get the access list of the community async [Types.GET_ACCESS_CONTROL_LIST]({ commit }) {  const result = await API.getCityAccessControlList<IAxiosResponseData>({  communityId: state.communityId  })  if(result.code ! = = 0)return  commit(Types.GET_ACCESS_CONTROL_LIST, result.data.userDoorDTOS)  commit(Types.SET_COMMONLY_USERDOOR, result.data.commonlyUsedDoor)  },  },  mutations: { // Set the cell list [Types.GET_CITY_LIST](state, cityList: ICity[]) {  if(cityList.length ! == 0) state.cityList = cityList }, // Set the access control list of the community [Types.GET_ACCESS_CONTROL_LIST](state, accessControlList: IAccessControl[]) {  if(accessControlList.length ! = = 0)return state.accessControlList = accessControlList  }, // Set the current cell [Types.SET_COMMONLY_USERDOOR](state, commonlyUsedDoor: ICommonlyUsedDoor) {  state.commonlyUsedDoor = commonlyUsedDoor  }  } } export default home Copy the code

    4. homeFile 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"; import qs from 'qs';  / * ** Purpose of hook: Personal understanding:* 1. Global public methods; Consider using utility class functions* 2. CityList and accessControlList are only displayed data without subsequent modification; Consider extracting it to be managed by the parent component* 3, if the method internal logic is more, other pages need to use, so the extraction is more appropriate* 4, of course, it is no problem to choose freely and implement it inside steUP method, but it is not conducive to obtaining references from other pages* 5. Vuex Actions, mutations function logic should be as little as possible for easy maintenance; The 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}`, {  communityId: 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> Copy the code

    5. loginFile code

    <template>
      <div class="login-container">
    <p> Mobile login </p>    <van-cell-group>
          <van-field
     v-model="phone"  required  clearable  maxlength="11"  label="Mobile phone Number"  placeholder="Please enter your mobile phone number." />  <van-field  v-model="sms"  center  required  clearable  maxlength="6"  label="SMS verification code"  placeholder="Please enter SMS verification code.">  <template #button>  <van-button  size="small"  plain  @click="getSmsCode">{{isSend ? `${second} s` : 'Send captcha'}}</van-button>  </template>  </van-field>  </van-cell-group>  <div class="login-button">  <van-button  :loading="isLoading"  size="large"  @click="onLogin"  loading-text="Logging in..."  type="primary"> login < / van - button > </div>  </div> </template>  <script lang="ts">  import { defineComponent, reactive, toRefs } from 'vue'  import { useStore } from "vuex";  import { IGlobalState } from "@/store";  import * as Types from "@/store/modules/Login/types";  import { Toast } from 'vant'  import router from '@/router'  export default defineComponent({  name: 'login'. isRouter: true. setup(props, ctx) {  let store = useStore <IGlobalState> ()  const state = reactive({  sms: ' '. phone: ' '. second: 60,  isSend: false. isLoading: false  }) Const phoneRegEx = / ^ [1] [3,4,5,6,7,8,9] [0-9] {9} $/// Get the verification code const getSmsCode = async () => {  localStorage.removeItem('h5_sessionId')  store.commit(`login/${Types.SAVE_PHONE}`, state.phone)  if(! phoneRegEx.test(state.phone))return Toast({  message: 'Phone number input error! '. duration: 2000  })  store.dispatch(`login/${Types.GET_SMS_CODE}`, state.phone).then(res => {  if(res.code ! = = 0)return  Toast({  message: 'Verification code has been sent to your mobile phone, please check.'. duration: 2000  })  state.isSend = true  const timer = setInterval(() => {  state.second--;  if (state.second <= 0) {  state.isSend = false  clearInterval(timer);  }  }, 1000);  })  } / / login const onLogin = () => {  state.isLoading = true  store.commit(`login/${Types.SAVE_SMS_CODE}`, state.sms)  store.dispatch(`login/${Types.ON_LOGIN}`).then(res => {  state.isLoading = false  if(res.code ! = = 0)return  localStorage.setItem('h5_sessionId', res.data.sessionId)  store.commit(`login/${Types.SAVE_USER_INFO}`, res.data)  router.push('/index')  })  }  return { . toRefs(state), onLogin,  getSmsCode  }  }  }) </script>  <style lang="less" scoped>  .login-container {  padding: 0 20px;  >p {  padding: 50px 20px 40px;  font-size: 40px;  }  .login-button {  margin-top: 50px;  }  } </style> Copy the code

    Iv. Project UI

    Five, the conclusion

    The above is the summary of personal actual project development, welcome to comment on the wrong place