【技術博客】Vue組件開發總結

Vue是一套工程化、便於多人合做開發的基於視圖層的前端開發框架。咱們最初選用Vue,由於其簡便且易於學習上手,組件化的開發思路適合多人合做開發,並且也支持多種現代化的工具鏈,好比UI庫ivew、JavaScript實用庫lodash、和後端數據交互的axios等。
下文會略微說起Vue入門基礎知識,而後主要闡述Vue組件開發的實踐經歷。html

Vue特性

在一門Vue入門的慕課中,說起了Vue的三大特性:前端

  • 前端工程化
  • 雙向綁定 MVVM
  • 組件化開發

下面簡要說明一下我對這三個概念的理解vue

前端工程化

總所周知,以前的前端開發,是依靠HTML+CSS+JavaScript。這種開發模式,在某些狀況下是極其繁瑣的。好比事件綁定的狀況:webpack

document.getElementById('dom').addEventListener('click', function(e) {
  ...
});

上述代碼的綁定方式,對於多個對象的多事件綁定,會極其繁瑣,並且要寫大量的重複代碼。而Vue採用的方法是組件內的事件觸發和方法綁定,簡易了不少。ios

<div @click="clickMethod">
</div>

methods: {
  clickMethod() {
    ...
  }
}

類似的例子還有不少。並且Vue也提供了不少輔助工程化開發的工具,好比基本腳手架(vue-cli)、包管理工具(yarn)、代碼規範(eslint)等,都有助於前端工程化開發。git

雙向數據綁定

雙向數據綁定,或者說MVVM,說的是程序的數據(model)和視圖(view)之間的架構模式。前端使用的架構模式還有MVC、MVP等等,雙向數據綁定的識別模式也能夠參考這篇博客。相關理論不少,可是在實際編程中,理解視圖的值發生更改後,數據的值也會更改,數據的值發生更改,觸發視圖內容更改便可。web

<div v-if="viewStyle==='chart'">
   <!-- show chart -->
</div>
<div v-else-if="table">
  <!-- show table -->
</div>

data() {
  viewStyle: 'chart'
}

上面的代碼示例也是說明model到view的一個例子,數據中的viewStyle從’chart‘改變爲’table‘時,視圖也隨之改變。而從view到model的例子,好比Input文本框,就是一個典型的用戶view中輸入,改變model數據的例子。vuex

組件化開發

組件化、模塊化,相信各位必定都據說過相似的術語。說白了,也就是把上萬行的程序分紅幾個幾千或者幾百行的文件,再把這些文件拆分紅幾十行的函數或者方法。拆分不是個難事,可是怎麼拆分能讓多人合做的時候分工明確,怎麼拆分能讓數據接口儘量簡潔,怎麼拆分能避免程序單模塊和組織上的bug。這都是拆分時須要考慮的事項。vue-cli

因此咱們組件化開發,一是作了前端視圖上的拆分。舉個例子:
頁面視圖組件化編程

這是咱們文獻管理的界面,其中以視圖爲單位的組件有頁面layout組件,頁面索引組件、文獻建立表單組件、表格組件、表格擴展組件和問卷調查組件。從中咱們能夠看出一個Vue的頁面也就是多個組件的疊加。在組件劃分時,能夠從頁面總體規劃入手,或整爲零的去劃分。

除了視圖上的劃分,還有工程邏輯上的劃分。好比和後端數據接口axios、前端的頁面跳轉router,各類頁面的圖標,也都是重要的前端開發組件因此在此基礎上,也就引出了咱們項目的代碼架構。

架構

README.md	
config/		
src
├── App.vue
├── apis
│   ├── User.js
│   └── util.js
├── assets
│   ├── HomePageLogo.png
│   └── logo.png
├── components
│   └── ErrPush.js
├── main.js
├── router
│   └── index.js
├── views
│   ├── Layout.vue
│   ├── UserLoginView.vue
│   └── UserRegisterView.vue
└── vuex
    └── index.js
build/		
index.html	
package.json	
yarn.lock
.eslintrc.js
.gitignore

上述代碼結構中,有GitHub工程相關文件,有yarn包管理相關文件,有知道yarn編譯的build文件夾和config配置文件夾。其中,src是源碼組織和組件分文件撰寫的目錄,其中有上面提到的apis(axios)、assets、components、router、views等組件。下面會對這些組件進行簡要的介紹。

與後端的接口apis

與後端的接口採用Node.js的http庫axois,代碼中對axios進行實例的建立

// eslint-disable-next-line no-unused-vars
const instanceAuth = axios.create({
  headers: {
    'Access-Control-Allow-Origin': '*',
  },
});

並對錯誤狀態進行處理

instanceAuth.interceptors.response.use(
  response => response,
  (error) => {
    if (error.response) {
      // code: 錯誤狀態碼, response:錯誤響應信息,error:原始錯誤信息
      switch (error.response.status) {
        case 400:
          return Promise.reject({ code: 4000, response: error.response, error }); // 客戶端請求有語法錯誤
        case 401: // 請求未經受權
        {
          store.commit('pushAuthToken', '');
          router.push({ name: 'Login' });
          return Promise.reject({ code: 4010, response: error.response, error });
        }
        case 404:
          return Promise.reject({ code: 4040, response: error.response, error }); // 頁面未找到
        case 403:
          return Promise.reject({ code: 4030, response: error.response, error }); // Bad Gateway
        case 500:
          return Promise.reject({ code: 5000, response: error.response, error }); // Server Error
        default:
          return Promise.reject({ code: -1, response: error.response, error }); // 不常見錯誤
      }
    } else {
      return Promise.reject({ code: -1, response: {}, error });
    }
  },
);

隨後對數據獲取請求進行了封裝

export const reqSingle = (url, _method, params_or_data = {}) => {
  const method = _method.toUpperCase();
  let options;
  if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
    options = {
      method,
      url,
      data: params_or_data,
    };
  } else {
    options = {
      method,
      url,
      params: params_or_data,
    };
  }
  return instanceAuth(options);
};

而在實際組件的使用中,也能夠對數據的增刪改查api進行更組件化的封裝,來減小冗餘代碼,使代碼更加清晰簡明。

// eslint-disable-next-line import/prefer-default-export
export const createArticleTabledata = (title, author, url, note, journal, ref) => req(
  '/api/articles/', 'POST', {},
  { title, author, url, note, journal, article_references: ref });

export const deleteArticleTabledata = id => req(
  `api/articles/${id}/`, 'DELETE');

export const changeArticleTabledata = data => req(
  `api/articles/${data.id}/`, 'PATCH', {}, data);

前端顯示頁面結構

前端頁面顯示,主要分佈在src/views

viewsDir

其中RoadmapLayout.vue設定了總體頁面視圖架構(參考iview),在Layout的基礎上,加入ArticleTableViewRoadmapEditorViewWelcomeCardView等組件,造成幾個主要頁面的組織。好比下方,header、footer是layout中的元素,加入WelcomeCard組件後造成主頁顯示界面。

layout2view

在主頁面的基礎上,添加各個頁面的模塊組件,好比邊欄、表單、圖表、畫布、編輯器、按鈕等組件,完成總體頁面的製做。

component2view

組件的代碼結構

經過上面的幾張圖,想必你們已經瞭解了組件開發的大概思路,感覺到了Vue經過組件化開發,可以達到的效果。可是在代碼層面,怎麼把組件鏈接起來,仍是不夠清楚。

因此下面會從代碼層面介紹,經過一些什麼樣的方法,可以實現上述效果。

  1. 父子組件概念

在上一節的例子,layout是WelcomeCard的父組件,而RoadmapView又是RoadmapEditor的component的父組件。下圖也可清晰的看到RoadmapEditor頁面中到側邊欄Item的父子組件調用樹狀關係。

父子組件樹狀關係
  1. 父子組件構建

下面寫一下父子組件構建的代碼

<!-- 父組件中 -->
<div>
  <child></child>
</div>

<script>
import child from './child';

export default {
  components: {child}
}
</script>

<!-- 子組件中 -->
<script>
export default {
  name: 'child',
}
</script>
  1. 父子組件互相傳值

頁面中,除了父子組件的概念及其代碼架構,父子組件之間的交互和傳值對於頁面的響應和觸發也極爲重要。所以下面介紹父組件向子組件傳值的props代碼架構(props也可參考官網說明下面代碼略去和上述代碼的重複部分

<!-- 父組件中 -->
<div>
  <child :sucData="fatherData">
  </child>
</div>

<script>
export default {
  data() {
    return {
      fatherData : [],
    },
  },
};
</script>

<!-- 子組件中 -->
<script>
export default {
  props: {
    sucData: {
      type: Array,
      required: true,
    },
  },
};
</script>

除了子組件會接收父組件的數據以外,也會向父組件觸發事件,並傳遞參數,這裏須要用到emit方法,來完成觸發。舉例以下:

<!-- 父組件中 -->
<div>
  <child @childEvent="childEvent">
  </child>
</div>

<script>
export default {
  method: {
    childEvent(par) {
      // do something
    };
  },
};
</script>

<!-- 子組件中 -->
<Button @click="onClick"></Button>
<script>
export default {
  method: {
    onClick() {
      this.$emit('childEvent', par);
    }
  },
};
</script>

頁面路由

頁面的跳轉也是頁面中極其重要的一個功能,這部分的內容由組內的另外一位同窗負責完成技術博客

總結

經過此次軟件工程編程,初步認識了Vue這一現代化的前端開發框架,並且本身也完成了幾個主要頁面的編寫,收穫頗豐。以後會繼續深刻webpack的內容,以獲取更深刻的認識。

相關文章
相關標籤/搜索