Vue是一套工程化、便於多人合做開發的基於視圖層的前端開發框架。咱們最初選用Vue,由於其簡便且易於學習上手,組件化的開發思路適合多人合做開發,並且也支持多種現代化的工具鏈,好比UI庫ivew、JavaScript實用庫lodash、和後端數據交互的axios等。
下文會略微說起Vue入門基礎知識,而後主要闡述Vue組件開發的實踐經歷。html
在一門Vue入門的慕課中,說起了Vue的三大特性:前端
下面簡要說明一下我對這三個概念的理解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等組件。下面會對這些組件進行簡要的介紹。
與後端的接口採用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
。
其中RoadmapLayout.vue
設定了總體頁面視圖架構(參考iview),在Layout的基礎上,加入ArticleTableView
、 RoadmapEditorView
、WelcomeCardView
等組件,造成幾個主要頁面的組織。好比下方,header、footer是layout中的元素,加入WelcomeCard組件後造成主頁顯示界面。
在主頁面的基礎上,添加各個頁面的模塊組件,好比邊欄、表單、圖表、畫布、編輯器、按鈕等組件,完成總體頁面的製做。
經過上面的幾張圖,想必你們已經瞭解了組件開發的大概思路,感覺到了Vue經過組件化開發,可以達到的效果。可是在代碼層面,怎麼把組件鏈接起來,仍是不夠清楚。
因此下面會從代碼層面介紹,經過一些什麼樣的方法,可以實現上述效果。
在上一節的例子,layout是WelcomeCard的父組件,而RoadmapView又是RoadmapEditor的component的父組件。下圖也可清晰的看到RoadmapEditor頁面中到側邊欄Item的父子組件調用樹狀關係。
下面寫一下父子組件構建的代碼
<!-- 父組件中 --> <div> <child></child> </div> <script> import child from './child'; export default { components: {child} } </script> <!-- 子組件中 --> <script> export default { name: 'child', } </script>
頁面中,除了父子組件的概念及其代碼架構,父子組件之間的交互和傳值對於頁面的響應和觸發也極爲重要。所以下面介紹父組件向子組件傳值的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的內容,以獲取更深刻的認識。