<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          vue項目實戰(zhàn)精粹匯總

          共 17470字,需瀏覽 35分鐘

           ·

          2022-02-14 23:25

          前言

          vue作為前端主流的3大框架之一,目前在國內(nèi)有著非常廣泛的應(yīng)用,由于其輕量和自底向上的漸進(jìn)式設(shè)計思想,使其不僅僅被應(yīng)用于PC系統(tǒng),對于移動端,桌面軟件(electronjs)等也有廣泛的應(yīng)用,與此誕生的優(yōu)秀的開源框架比如elementUI,iView, ant-design-vue等也極大的降低了開發(fā)者的開發(fā)成本,并極大的提高了開發(fā)效率。筆者最初接觸vue時也是使用的iview框架,親自體會之后確實非常易用且強(qiáng)大。

          筆者曾經(jīng)有兩年的vue項目經(jīng)驗,基于vue做過移動端項目和PC端的ERP系統(tǒng),雖然平時工作中采用的是react技術(shù)棧,但平時還是會積累很多vue相關(guān)的最佳實踐和做一些基于vue的開源項目,所以說總結(jié)vue的項目經(jīng)驗我覺得是最好的成長,也希望給今年想接觸vue框架或者想從事vue工作的朋友帶來一些經(jīng)驗和思考。

          你將收獲

          • vue框架使用注意事項和最佳經(jīng)驗

          • vue項目配置經(jīng)驗總結(jié)

          • vue組件設(shè)計經(jīng)驗總結(jié)

          • vue項目架構(gòu)與服務(wù)化探索

          正文

          本文不僅僅是總結(jié)一些vue使用踩過的一些坑和項目經(jīng)驗,更多的是使用框架(vue/react)過程中的方法論和組件的設(shè)計思路,最后還會有一些個人對工程化的一些總結(jié),希望有更多經(jīng)驗的朋友們可以一起交流,探索vue的奧妙。

          在開始文章之前,筆者建議大家對javascript, css, html基礎(chǔ)有一定的了解,因為會用框架不一定能很好的實現(xiàn)業(yè)務(wù)需求和功能,要想實現(xiàn)不同場景下不同復(fù)雜度的需求,一定要對web基礎(chǔ)有充足的了解,所以希望大家熟悉如下基礎(chǔ)知識,如果不太熟悉可以花時間研究了解一下。

          javascript:

          • 數(shù)組常用方法的使用,比如遍歷有forEach,map,filter,every, some,reduce,操作方法有splice,slice, join,push,shift, pop,sort等

          • 基本數(shù)據(jù)結(jié)構(gòu),引用類型(對象,數(shù)組)

          • 基本邏輯運(yùn)算if else, switch,三目運(yùn)算:?,for/while循環(huán)等

          • 字符串常見api(如replace,slice, substr,indexOf)

          • 基本正則使用

          • 變量作用域,作用域鏈,變量提升,函數(shù)聲明提升

          • 對象基本用法,面向?qū)ο缶幊?/p>

          css:

          • 基本盒模型(border/content/padding等)

          • 4種常用定位(static/absolute/relative/fixed)

          • 常用布局方式(浮動布局/彈性布局flex/自適應(yīng)布局/網(wǎng)格布局grid)

          • css3基本樣式與動畫(transition,animation)

          html:

          • 新標(biāo)簽基本用法和使用

          • head標(biāo)簽作用與用法(主要是meta屬性的用法)

          所以希望大家掌握好以上基礎(chǔ)知識,也是前端開發(fā)的基礎(chǔ),接下來我們直接進(jìn)入正文。

          1. vue框架使用注意事項和最佳經(jīng)驗

          ?

          vue學(xué)習(xí)最快的方式就是實踐,根據(jù)官網(wǎng)多寫幾個例子是掌握vue最快的方式。 接下來筆者就來總結(jié)一下在開發(fā)vue項目中的一些實踐經(jīng)驗。

          ?

          1.1 vue生命周期以及不同生命周期下的應(yīng)用

          以上是vue官網(wǎng)上的生命周期的方法,大致劃分一下分為創(chuàng)建前/后,掛載前/后,更新前/后,銷毀前/后這四個階段。各個階段的狀態(tài)總結(jié)如下:

          • beforeCreate:在beforeCreate生命周期執(zhí)行時,data和methods中的數(shù)據(jù)還未初始化,所以此時不能使用data中的數(shù)據(jù)和methods中的方法

          • create:data 和 methods初始化完畢,此時可以使用methods 中的方法和data 中的數(shù)據(jù)

          • beforeMount:template模版已經(jīng)編譯好,但還未掛載到頁面,此時頁面還是上一個狀態(tài)

          • mounted:此時Vue實例初始化完成了,DOM掛載完畢,可以直接操作dom或者使用第三方dom庫

          • beforeUpdate: 此時data已更新,但還未同步頁面

          • updated:data和頁面都已經(jīng)更新完成

          • beforeDestory:Vue實例進(jìn)入銷毀階段,但所有的 data 和 methods , 指令, 過濾器等都處于可用狀態(tài)

          • destroyed: 此時組件已經(jīng)被銷毀,data,methods等都不可用

          根據(jù)以上介紹,頁面第一次加載時會執(zhí)行 beforeCreate, created, beforeMount, mounted這四個生命周期,所以我們一般在created階段處理http請求獲取數(shù)據(jù)或者對data做一定的處理, 我們會在mounted階段操作dom,比如使用jquery,或者其他第三方dom庫。其次,根據(jù)以上不同周期下數(shù)據(jù)和頁面狀態(tài)的不同,我們還可以做其他更多操作,所以說每個生命周期的發(fā)展?fàn)顟B(tài)非常重要,一定要理解,這樣才能對vue有更多的控制權(quán)。

          1.2 vue常用的指令以及動態(tài)指令的使用

          指令 (Directives) 是帶有 v- 前綴的特殊屬性,vue常用的指令有:

          • v-bind 用于響應(yīng)式地更新 HTML屬性

          • v-if 根據(jù)表達(dá)式的值的真假來決定是否插入/移除元素

          • v-on 用于監(jiān)聽 DOM 事件

          • v-show 用于決定是否展示該元素,底層通過display:none實現(xiàn)

          • v-html 在dom內(nèi)插入html內(nèi)容

          • v-for 循環(huán)

          • v-text 渲染指定dom的內(nèi)容文本

          • v-cloak 和CSS規(guī)則如 [v-cloak] { display: none } 一起用,可以隱藏未編譯的 Mustache 標(biāo)簽直到實例準(zhǔn)備完畢

          以上是比較常用的指令,具體用法就不一一舉例了,其中v-cloak主要是用來避免頁面加載時出現(xiàn)閃爍的問題,可以結(jié)合css的[v-cloak] { display: none }方式解決這一問題。關(guān)于指令的動態(tài)參數(shù),使用也很簡單,雖然是2.6.0 新增的,但是方法很靈活,具體使用如下:

           ...   
          復(fù)制代碼

          我們可以根據(jù)具體情況動態(tài)切換事件名,從而綁定同一個函數(shù)。

          1.3 vue常用修飾符及作用

          1. 事件修飾符
          • .stop 阻止事件冒泡

          • .prevent 阻止事件默認(rèn)行為

          • .self 事件綁定的元素本身觸發(fā)時才觸發(fā)回調(diào)

          • .once 事件只能觸發(fā)一次,第二次就不會觸發(fā)了

          • .native 將一個vue組件變成一個普通的html,使其可以監(jiān)聽click等原生事件 具體使用如下:

          ok  
          復(fù)制代碼
          1. 表單修飾符
          • .lazy 在輸入框輸入完內(nèi)容,光標(biāo)離開時才更新視圖

          • .trim 過濾首尾空格

          • .number 如果先輸入數(shù)字,那它就會限制你輸入的只能是數(shù)字;如果先輸入字符串,那就相當(dāng)于沒有加.number

          用法如下:

            
          復(fù)制代碼

          還有很多修飾符比如鍵盤,鼠標(biāo)等修飾符,感興趣的大家可以自行學(xué)習(xí)研究。

          1.4 組件之間,父子組件之間的通信方案

          組件之間的通信方案:

          • 通過事件總線(bus),即通過發(fā)布訂閱的方式

          • vuex

          父子組件:

          • 父組件通過prop向自組件傳遞數(shù)據(jù)

          • 子組件綁定自定義事件,通過this.$emit(event,params) 來調(diào)用自定義事件

          • 使用vue提供的 children & $refs方法來通信

          1.5 vue實現(xiàn)按需加載組件

          組件的按需加載是項目性能優(yōu)化的一個環(huán)節(jié),也可以降低首屏渲染時間,筆者在項目中用到的組件按需加載的方式如下:

          1. 使用() => import(), 具體代碼如下:
            

          復(fù)制代碼
          1. 使用resolve => require(['./ComponentA'], resolve),使用方法如下:
            

          復(fù)制代碼

          「1.6 vuex的幾種屬性和作用,以及使用vuex的基本模式」

          ?

          Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。

          ?

          vuex的基本工作模式如下圖所示:

          state的改變完全由mutations控制, 我們也沒必要任何項目都使用vuex,對于中大型復(fù)雜項目而言,需要共享的狀態(tài)很多時,使用vuex才是最佳的選擇。接下來我將詳細(xì)介紹各api的概念和作用。

          • state 單一狀態(tài)樹,用一個對象就包含了全部的應(yīng)用層級狀態(tài),并且作為一個唯一數(shù)據(jù)源而存在

          • getters 就像計算屬性一樣,getter 的返回值會根據(jù)它的依賴被緩存起來,且只有當(dāng)它的依賴值發(fā)生了改變才會被重新計算 比如如下案例:

          const store = new Vuex.Store({  
          state: {
          todos: [
          { id: 1, text: '...', done: true },
          { id: 2, text: '...', done: false }
          ]
          },
          getters: {
          doneTodos: state => {
          return state.todos.filter(todo => todo.done)
          }
          }
          })
          // 訪問getters里的屬性
          this.$store.getters.doneTodos
          復(fù)制代碼
          • Mutation 更改 Vuex 的 store 中的狀態(tài)的唯一方法,使用案例如下:
          const store = new Vuex.Store({  
          state: {
          num: 1
          },
          mutations: {
          add (state) {
          // 變更狀態(tài)
          state.num++
          }
          }
          })

          // 在項目中使用mutation
          store.commit('add')
          // 添加額外參數(shù)
          store.commit('add', 10)
          復(fù)制代碼
          • Action Action提交的是mutation,而不是直接變更狀態(tài),可以包含任意異步操作,具體用法如下:
          const?store?=?new?Vuex.Store({??
          ??state:?{??
          ????num:?0??
          ??},??
          ??mutations:?{??
          ????add?(state)?{??
          ??????state.num++??
          ????}??
          ??},??
          ??actions:?{??
          ????add?(context)?{??
          ??????context.commit('add')??
          ????},??
          ????asyncAdd?({?commit?})?{??
          ????setTimeout(()?=>?{??
          ??????commit('add')??
          ????}??
          ??}??
          })??
          //?分發(fā)action??
          store.dispatch('add')??
          //?異步action??
          store.dispatch('asyncAdd')??
          //?異步傳參??
          store.dispatch('asyncAdd',?{?num:?10?})??
          復(fù)制代碼
          • Module 將store分割成模塊(module)。每個模塊擁有自己的 state、mutation、action、getter、甚至是嵌套子模塊

          筆者更具實際經(jīng)驗總結(jié)了一套標(biāo)準(zhǔn)使用模式,就拿筆者之前的開源XPXMS舉例,如下:

          store目錄是用來組織vuex代碼用的,我將action,mutation,state分文件管理,這樣項目大了之后也很容易管理和查詢。接下來看看是如何組織的:

          // type.ts  
          // 用來定義state等的類型文件
          export interface State {
          name: string;
          isLogin: boolean;
          config: Config;
          [propName: string]: any; // 用來定義可選的額外屬性
          }

          export interface Config {
          header: HeaderType,
          banner: Banner,
          bannerSider: BannerSider,
          supportPay: SupportPay
          }

          export interface Response {
          [propName: string]: any;
          }

          // state.ts
          // 定義全局狀態(tài)
          import { State } from './type'
          export const state: State = {
          name: '',
          isLogin: false,
          curScreen: '0', // 0為pc, 1為移動
          config: {
          header: {
          columns: ['首頁', '產(chǎn)品', '技術(shù)', '運(yùn)營', '商業(yè)'],
          height: '50',
          backgroundColor: '#000000',
          logo: ''
          }
          },
          // ...
          articleDetail: null
          };

          // mutation.ts
          import {
          State,
          Config,
          HeaderType,
          Banner,
          BannerSider,
          SupportPay
          } from './type'

          export default {
          // 預(yù)覽模式
          setScreen(state: State, payload: string) {
          state.curScreen = payload;
          },

          // 刪除banner圖
          delBanner(state: State, payload: number) {
          state.config.banner.bannerList.splice(payload, 1);
          },

          // 添加banner圖
          addBanner(state: State, payload: object) {
          state.config.banner.bannerList.push(payload);
          },

          // ...
          };

          // action.ts
          import {
          HeaderType,
          Response
          } from './type'
          import http from '../utils/http'
          import { uuid, formatTime } from '../utils/common'
          import { message } from 'ant-design-vue'

          export default {
          /**配置 */
          setConfig(context: any, paylod: HeaderType) {
          http.get('/config/all').then((res:Response) => {
          context.commit('setConfig', res.data)
          }).catch((err:any) => {
          message.error(err.data)
          })
          },
          /**header */
          saveHeader(context: any, paylod: HeaderType) {
          http.post('/config/setHeader', paylod).then((res:Response) => {
          message.success(res.data)
          context.commit('saveHeader', paylod)
          }).catch((err:any) => {
          message.error(err.data)
          })
          },
          // ...
          };

          // index.ts
          import Vue from 'vue';
          import Vuex from 'vuex';
          import { state } from './state';
          import mutations from './mutation';
          import actions from './action';

          Vue.use(Vuex);

          export default new Vuex.Store({
          state,
          mutations,
          actions
          });

          // main.ts
          // 最后掛載到入口文件的vue實例上
          import Vue from 'vue';
          import App from './App.vue';
          import router from './router';
          import store from './store/';
          import './component-class-hooks';
          import './registerServiceWorker';

          Vue.config.productionTip = false;

          new Vue({
          router,
          store,
          render: (h) => h(App),
          }).$mount('#app');
          復(fù)制代碼

          我們在實際項目中都可以使用這種方式組織管理vuex相關(guān)的代碼。

          「1.7 vue-router基本使用模式和導(dǎo)航鉤子的用法及作用」

          vue-router使用大家想必不是很陌生,這里直接寫一個案例:

          // router.ts  
          import Vue from 'vue';
          import Router from 'vue-router';
          import Home from './views/admin/Home.vue';

          Vue.use(Router);

          const router = new Router({
          mode: 'history',
          base: process.env.BASE_URL,
          routes: [
          {
          path: '/',
          component: Home,
          beforeEnter: (to, from, next) => {
          next();
          },
          children: [
          {
          // 當(dāng) /user/:id/profile 匹配成功,
          // UserProfile 會被渲染在 User 的
          path: '',
          name: 'header',
          component: () => import(/* webpackChunkName: "header" */ './views/admin/subpage/Header.vue'),
          },

          {
          path: '/banner',
          name: 'banner',
          component: () => import(/* webpackChunkName: "banner" */ './views/admin/subpage/Banner.vue'),
          },
          {
          path: '/admin',
          name: 'admin',
          component: () => import(/* webpackChunkName: "admin" */ './views/admin/Admin.vue'),
          },
          ],
          },
          {
          path: '/login',
          name: 'login',
          component: () => import(/* webpackChunkName: "login" */ './views/Login.vue'),
          meta:{
          keepAlive:false //不需要被緩存的組件
          }
          },
          {
          path: '*',
          name: '404',
          component: () => import(/* webpackChunkName: "404" */ './views/404.vue'),
          },
          ],
          });

          // 路由導(dǎo)航鉤子的用法
          router.beforeEach((to, from, next) => {
          if(from.path.indexOf('/preview') < 0) {
          sessionStorage.setItem('prevToPreviewPath', from.path);
          }
          next();
          })

          export default router
          復(fù)制代碼

          以上案例是很典型的靜態(tài)路由配置和導(dǎo)航鉤子的用法(如何加載路由組件,動態(tài)加載路由組件,404頁面路由配置,路由導(dǎo)航鉤子使用)。如果在做后臺系統(tǒng),往往會涉及到權(quán)限系統(tǒng),所以一般會采用動態(tài)配置路由,通過前后端約定的路由方式,路由配置文件更具不同用戶的權(quán)限由后端處理后返。由于設(shè)計細(xì)節(jié)比較繁瑣,涉及到前后端協(xié)定,所以這里只講思路就好了。

          1.8 vue中檢測變化的注意事項

          受現(xiàn)代 JavaScript 的限制,Vue 無法檢測到對象屬性的添加或刪除。由于 Vue 會在初始化實例時對屬性執(zhí)行 getter/setter 轉(zhuǎn)化,所以屬性必須在 data 對象上存在才能讓 Vue 將它轉(zhuǎn)換為響應(yīng)式的。還有一種情況是,vue無法檢測到data屬性值為數(shù)組或?qū)ο蟮男薷模晕覀冃枰迷瓕ο笈c要混合進(jìn)去的對象的屬性一起創(chuàng)建一個新的對象。可以使用this.$set或者對象的深拷貝,如果是數(shù)組則可以使用splice,擴(kuò)展運(yùn)算符等方法來更新。

          1.9 對指定頁面使用keep-alive路由緩存

          keep-alive是Vue的內(nèi)置組件,能在組件切換過程中將狀態(tài)保留在內(nèi)存中,防止重復(fù)渲染DOM。我們可以使用以下方式設(shè)置某些頁面是否被緩存:

          1. 通過路由配置文件和router-view設(shè)置:
          // routes 配置  
          export default [
          {
          path: '/A',
          name: 'A',
          component: A,
          meta: {
          keepAlive: true // 需要被緩存
          }
          }, {
          path: '/B',
          name: 'B',
          component: B,
          meta: {
          keepAlive: false // 不需要被緩存
          }
          }
          ]
          復(fù)制代碼

          路由視圖配置:

          // 路由設(shè)置  










          復(fù)制代碼





          1. 通過router-view的key屬性 具體方式如下:
            


          復(fù)制代碼

          1.10 vue常用工具函數(shù)總結(jié)

          總結(jié)一下筆者在vue項目中的常用的工具函數(shù)。

          • 識別ie瀏覽器
          /**  
          * 識別ie--淺識別
          */
          export const isIe = () => {
          let explorer = window.navigator.userAgent;
          //判斷是否為IE瀏覽器
          if (explorer.indexOf("MSIE") >= 0) {
          return true;
          }else {
          return false
          }
          }
          復(fù)制代碼
          • 顏色16進(jìn)制轉(zhuǎn)rgba
          /**  
          * 顏色轉(zhuǎn)換16進(jìn)制轉(zhuǎn)rgba
          * @param {String} hex
          * @param {Number} opacity
          */
          export function hex2Rgba(hex, opacity) {
          if(!hex) hex = "#2c4dae";
          return "rgba(" + parseInt("0x" + hex.slice(1, 3)) + "," + parseInt("0x" + hex.slice(3, 5)) + "," + parseInt("0x" + hex.slice(5, 7)) + "," + (opacity || "1") + ")";
          }
          復(fù)制代碼
          • 去除html標(biāo)簽
          // 去除html標(biāo)簽  
          export const htmlSafeStr = (str) => {
          return str.replace(/<[^>]+>/g, "")
          }
          復(fù)制代碼
          • 獲取url參數(shù)對象
          /* 獲取url參數(shù) */  
          export const getQueryString = () => {
          let qs = location.href.split('?')[1] || '',
          args = {},
          items = qs.length ? qs.split("&") : [];
          items.forEach((item,i) => {
          let arr = item.split('='),
          name = decodeURIComponent(arr[0]),
          value = decodeURIComponent(arr[1]);
          name.length && (args[name] = value)
          })
          return args;
          }
          復(fù)制代碼
          • 解析url參數(shù)
          /* 解析url參數(shù) */  
          export const paramsToStringify = (params) => {
          if(params){
          let query = [];
          for(let key in params){
          query.push(`${key}=${params[key]}`)
          }
          return `${query.join('&')}`
          }else{
          return ''
          }
          }
          復(fù)制代碼
          • 將數(shù)據(jù)轉(zhuǎn)化為數(shù)組
          export const toArray = (data) => {  
          return Array.isArray(data) ? data : [data]
          }
          復(fù)制代碼
          • 帶參數(shù)跳轉(zhuǎn)url(hash模式)
          /**  
          * 帶參數(shù)跳轉(zhuǎn)url(hash模式)
          * @param {String} url
          * @param {Object} params
          */
          export const toPage = (url, params) => {
          if(params){
          let query = [];
          for(let key in params){
          query.push(`${key}=${params[key]}`)
          }
          window.location.href = `./index.html#/${url}?${query.join('&')}`;
          }else{
          window.location.href = `./index.html#/${url}`;
          }
          }
          復(fù)制代碼
          • 控制字符串顯示,超出指定字?jǐn)?shù)則顯示省略號
          /**  
          * 指定字符串 溢出顯示省略號
          * @param {String} str
          * @param {Number} num
          */
          export const getSubStringSum = (str = "", num = 1) => {
          let newStr;
          if(str){
          str = str + '';
          if (str.trim().length > num ) {
          newStr = str.trim().substring(0, num) + "...";
          } else {
          newStr = str.trim();
          }
          }else{
          newStr = ''
          }
          return newStr;
          }
          復(fù)制代碼
          • 生成uuid
          /**  
          * 生成uuid
          * @param {number} len 生成指定長度的uuid
          * @param {number} radix uuid進(jìn)制數(shù)
          */
          export function uuid(len, radix) {
          let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
          let uuid = [], i;
          radix = radix || chars.length;

          if (len) {
          for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix];
          } else {
          let r;

          uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
          uuid[14] = '4';

          for (i = 0; i < 36; i++) {
          if (!uuid[i]) {
          r = 0 | Math.random()*16;
          uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
          }
          }
          }

          return uuid.join('');
          }
          復(fù)制代碼
          • 生成指定格式的時間字符串
          /**  
          * 生成指定格式的時間
          * @param {*} timeStemp 時間戳
          * @param {*} flag 格式符號
          */
          export function formatTime(timeStemp, flag) {
          let time = new Date(timeStemp);
          let timeArr = [time.getFullYear(), time.getMonth() + 1, time.getDate()];
          return timeArr.join(flag || '/')
          }
          復(fù)制代碼

          1.11 如何基于axios二次封裝一個具有請求/響應(yīng)攔截的http請求

          這個主要是對axios的理解,大家可以學(xué)習(xí)axios官方文檔,這里給出一個二次封裝的模版:

          import axios from 'axios'  
          import qs from 'qs'

          // 請求攔截
          axios.interceptors.request.use(config => {
          // 此處可以封裝一些加載狀態(tài)
          return config
          }, error => {
          return Promise.reject(error)
          })

          // 響應(yīng)攔截
          axios.interceptors.response.use(response => {
          return response
          }, error => {
          return Promise.resolve(error.response)
          })

          function checkStatus (response) {
          // 此處可以封裝一些加載狀態(tài)
          // 如果http狀態(tài)碼正常,則直接返回數(shù)據(jù)
          if(response) {
          if (response.status === 200 || response.status === 304) {
          return response.data
          // 如果不需要除了data之外的數(shù)據(jù),可以直接 return response.data
          } else if (response.status === 401) {
          location.;
          } else {
          throw response.data
          }
          } else {
          throw {data:'網(wǎng)絡(luò)錯誤'}
          }

          }

          // axios默認(rèn)參數(shù)配置
          axios.defaults.baseURL = '/api/v0';
          axios.defaults.timeout = 10000;

          // restful API封裝
          export default {
          post (url, data) {
          return axios({
          method: 'post',
          url,
          data: qs.stringify(data),
          headers: {
          'X-Requested-With': 'XMLHttpRequest',
          'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          }
          }).then(
          (res) => {
          return checkStatus(res)
          }
          )
          },
          get (url, params) {
          return axios({
          method: 'get',
          url,
          params, // get 請求時帶的參數(shù)
          headers: {
          'X-Requested-With': 'XMLHttpRequest'
          }
          }).then(
          (res) => {
          return checkStatus(res)
          }
          )
          },
          del (url, params) {
          return axios({
          method: 'delete',
          url,
          params, // get 請求時帶的參數(shù)
          headers: {
          'X-Requested-With': 'XMLHttpRequest'
          }
          }).then(
          (res) => {
          return checkStatus(res)
          }
          )
          }
          }
          復(fù)制代碼

          該模版只是一個大致框架,大家可以細(xì)化成業(yè)務(wù)需求的樣子,該案例提供了restful接口方法,比如get/post/delete/put等。

          1.12 vue常用社區(qū)組件,插件

          筆者在做vue項目時為了提高開發(fā)效率也會直接用第三方插件,下面整理一下常用的vue社區(qū)組件和庫。

          1. UI框架
          • elementUI

          • iview

          • Mint UI 基于 Vue.js 的移動端組件庫

          • Vant 有贊團(tuán)隊的移動端組件庫

          1. 社區(qū)組件
          • Vuetable-2 基于vue的強(qiáng)大的表格組件

          • vue-fa 基于vue的圖標(biāo)組件庫

          • vue-notification vue優(yōu)美的信息通知組件

          • vue-progress-path vue個性的路徑進(jìn)度條組件

          • Vue樹組件,可讓您以美觀和邏輯的方式呈現(xiàn)層次結(jié)構(gòu)的數(shù)據(jù)

          • vue-social-sharing vue社區(qū)分享組件

          • vue-qrcode-reader 一組用于檢測和解碼二維碼的Vue.js組件

          • vue-clipboard2 基于vue的剪切板組件

          • cool-emoji-picker vue表情包組件

          • Vue-tabs-component 強(qiáng)大而美觀的tab組件

          更多組件可以在vue插件社區(qū)查看。

          2. vue項目配置經(jīng)驗總結(jié)

          在講完vue項目經(jīng)驗之后,為了讓大家能獨立負(fù)責(zé)一個項目,我們還需要知道從0開始搭建項目的步驟,以及通過項目實際情況,自己配置一個符合的項目框架,比如有些公司會采用vue+element+vue+less搭建,有些公司采用vue+iview+vue+sass,或者其他更多的技術(shù)棧,所以我們要有把控能力,我們需要熟悉webpack或者vue-cli3腳手架的配置,筆者之前有些過詳細(xì)的webpack和vue-cli3搭建自定義項目的文章,這里由于篇幅有限就不一一舉例了。感興趣的朋友可以參考以下兩篇文章:

          3. vue組件設(shè)計經(jīng)驗總結(jié)

          ?

          組件系統(tǒng)是 Vue 的另一個重要概念,因為它是一種抽象,允許我們使用小型、獨立和通常可復(fù)用的組件構(gòu)建大型應(yīng)用。幾乎任意類型的應(yīng)用界面都可以抽象為一個組件樹。在一個大型應(yīng)用中,有必要將整個應(yīng)用程序劃分為組件,以使開發(fā)更易管理。

          ?

          對于一個基礎(chǔ)組件來說,我們該如何下手去設(shè)計呢?首先筆者覺得應(yīng)該先從需求和功能入手,先劃分好組件的功能邊界,組件能做什么,理清這些之后再開始寫組件。

          如上圖組件的一個抽象,我們無論如何記住的第一步就是先理清需求在去著手開發(fā),這樣可以避免大量效率的丟失。在上圖中我們要注意組件的解耦合,每個組件都負(fù)責(zé)特定的功能或者展現(xiàn),這樣對組件后期維護(hù)性和擴(kuò)展性有非常大的幫助。筆者總結(jié)了一下組件設(shè)計的注意事項:

          • 確定組件設(shè)計的邊界和功能定位

          • 組件盡量遵循單一職責(zé)原理,用組合代替功能的雜糅

          • 組件屬性暴露要適度,不可過渡暴露屬性

          • 組件封裝要考慮可重用,可組合,可配置

          • 做好組件類型設(shè)計的劃分(展示型組件,錄入型組件,基礎(chǔ)組件, 布局組件,反饋型組件,業(yè)務(wù)組件等)

          筆者拿之前在開源社區(qū)發(fā)布的一個文件上傳組件為例子來說明舉例,代碼如下:

            


          復(fù)制代碼

          以上文件上傳預(yù)覽采用的是ts來實現(xiàn),但設(shè)計思路都是一致的,大家可以參考交流一下。 關(guān)于如何設(shè)計一個健壯的組件,筆者也寫過相關(guān)文章,大致思想都好似一樣的,可以參考一下:

          • 《精通react/vue組件設(shè)計》之快速實現(xiàn)一個可定制的進(jìn)度條組件

          • 《精通react/vue組件設(shè)計》之用純css打造類materialUI的按鈕點擊動畫并封裝成react組件

          • 3分鐘教你用原生js實現(xiàn)具有進(jìn)度監(jiān)聽的文件上傳預(yù)覽組件

          組件的設(shè)計思想和方法與具體框架無關(guān),所以組件設(shè)計的核心是方法論,我們只有在項目中不斷總結(jié)和抽象,才能對組件設(shè)計有更深刻的理解。

          4. vue項目架構(gòu)與服務(wù)化探索

          這里是筆者總結(jié)的一套思維導(dǎo)圖:

          有點微前端架構(gòu)的感覺,但是還有很多細(xì)節(jié)需要考慮。此架構(gòu)適用于不同子系統(tǒng)獨立部署和開發(fā)的環(huán)境, 也不需要考慮具體的技術(shù)棧選擇,相同的框架采用同一套自建組件庫來達(dá)到組件的復(fù)用,這里提倡項目開始設(shè)計時就考慮組件化和模塊化,做出功能的最大的拆分和去耦合。筆者后面會單獨花時間總結(jié)微前端架構(gòu)具體的一些設(shè)計思路和落地方案,感興趣的可以一起探討交流。

          2021技術(shù)復(fù)盤匯總


          好啦, 今天的分享就到這啦, 如果文章對你有幫助, 歡迎?「點贊」?+?「在看」, 鼓勵作者創(chuàng)造更優(yōu)質(zhì)的內(nèi)容~


          點個在看你最好看

          瀏覽 48
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  激情丁香五月 | 黄色三级在线观看 | 九九九九在线视频播放 | 欧美熟妇精品黑人巨大一二三区 | 9无码|