不識廬山真面目,只緣身在此山中。html
大概一個月前,開源了Vue重構豆瓣移動端的項目,效果還能夠,收到了不少小夥伴的反饋,話說是要寫一些文章的,但遲遲沒有動筆,估計小夥伴們等的花都謝了,拖延症是病,須要治療...vue
接下來開始填坑,這一系列的文章會把在開發中遇到的問題總結下來。這篇文章是第一篇,是一些準備工做,包括從idea到具體項目實現...java
萬事開頭難,當有idea從你腦海中閃過的時候,你第一個想到的應該是:腳手架工具,快速生成基本的項目結構,即刻上手。Vue官方就提供了方便易用的Vue-cli命令行工具,快速,高效,爽! webpack
這個項目自己是基於Vue-cli的webpack模板,簡單的輸入一條命令vue init webpack my-project
,便能生成一個使用webpack做爲打包工具,具有熱重載,代碼檢查,css預處理等一系列功能的初始項目。ios
這一系列文章不會講webpack如何使用?有可能會涉及一些簡單的配置項。固然,學習webpack能很好的理解和解決開發中遇到的問題,有須要可自行谷歌。
不過,也沒必要擔憂,正如上面所說,即便你不瞭解webpack,你仍然能夠用Vue-cli快速開發出高逼格Vue應用。git
來看看咱們的目錄結構:github
. ├── build // Webpack打包相關配置 ├── config // 基本環境配置 ├── index.html // 通用HTML模板 ├── package.json // 相關依賴 ├── README.md // README ├── src // 源碼目錄 │ ├── App.vue // 入口頁面 │ ├── assets // 靜態資源目錄 │ ├── components // 全局公用組件目錄 │ │ ├── Banner.vue // 廣告橫幅組件 │ │ ├── Card.vue // 卡片組件 │ │ ├── DownloadApp.vue // 底部app下載組件 │ │ ├── Group.vue // 小組組件 │ │ ├── HeaderBar.vue // 頂部導航組件 │ │ ├── List.vue // 列表組件 │ │ ├── Rating.vue // 星級評分組件 │ │ ├── Scroller.vue // 橫向滾動組件 │ │ ├── Marking.vue // 標記組件 │ │ ├── SubNav.vue // 二級導航組件 │ │ ├── Tags.vue // 標籤組件 │ │ ├── Types.vue // 項目類型組件 │ │ └── UserBar.vue // 用戶欄組件 │ ├── main.js // 應用初始化入口文件 │ ├── router // 路由目錄 │ │ └── index.js // 路由配置 │ ├── store // Vuex全局狀態目錄 │ │ ├── index.js // Store根文件 │ │ └── modules // 模塊目錄 │ │ ├── activities.js // 活動相關狀態 │ │ ├── book.js // 書籍相關狀態 │ │ ├── group.js // 小組相關狀態 │ │ ├── movie.js // 電影相關狀態 │ │ ├── search.js // 搜索相關狀態 │ │ ├── subject.js // 主題相關狀態 │ │ └── user.js // 用戶相關狀態 │ └── views // 視圖目錄 │ ├── BookView.vue // 書籍視圖 │ ├── DetailView.vue // 首頁活動詳情視圖 │ ├── GroupView.vue // 小組視圖 │ ├── HomeView.vue // 主頁視圖 │ ├── LoginView.vue // 登陸視圖 │ ├── MovieView.vue // 電影視圖 │ ├── PagesView.vue // 綜合視圖 │ ├── RegisterView.vue // 註冊視圖 │ ├── SearchView.vue // 搜索視圖 │ ├── StatusView.vue // 廣播視圖 │ ├── SubjectView.vue // 主題視圖 │ └── TalionView.vue // 覆蓋層視圖 └── static // 靜態文件目錄
能開始了嗎?。客官,莫急!web
首先,咱們要對寫的項目有一個總體的印象,哪些東西是公用的?能夠抽離爲組件的?哪些是一次性組件?這些組件之間是否擁有某種關係?經過怎樣的邏輯把他們關聯起來?哪些頁面是可重用的?又有哪些頁面須要同時顯示在視圖裏?路由要怎麼劃分?項目是否足夠的大?要不要統一狀態管理......vue-router
從上面結構中能夠看出,咱們把一些可重用的或者是一次性組件寫在了src/components
中。
把徹底不一樣或者是關聯性不大的頁面獨立爲不一樣的視圖放在src/views
裏,這些包含了一個個子組件的視圖一樣可視爲組件。
上面結構中對各個目錄和文件作了簡單的描述,可能有些不太精確,建議結合代碼來看。
關於視圖方面,主要想說一下PagesView
視圖和TalionView
視圖。TalionView
在這裏是做爲彈出層,覆蓋在其餘頁面之上,擁有較高的在z-index,其內容包括了搜索框和一些快速導航。PagesView
視圖,又對各個頁面作了一次組合,包括了<header-bar>
頭部導航組件,路由出口<router-view>
,還有一個TalionView
視圖。
爲何要這麼作呢?
綜合項目全部視圖來看,除了登陸註冊頁面外,其餘頁面的佈局大體相同:頂部導航+中間內容視圖+覆蓋層。這在無形中經過視圖將此項目分紅了兩大模塊:登陸註冊類無通用樣式模塊,和具有通用公共樣式的普通模塊。
固然這樣劃分的另外一個基礎是對路由的配置。接下來,咱們來看看路由,進行進一步解釋。
先瞄一眼咱們的路由配置:
routes: [ { // [1] path: '/', redirect: '/pages/' }, { // [2] path: '/pages', component: PagesView, children: [ { path: '', redirect: '/pages/home' }, { path: 'home', name: 'HomeView', component: HomeView }, { path: 'movie', name: 'MovieView', component: MovieView }, ...... { path: 'detail/:id', name: 'DetailView', component: DetailView } ] }, { // [3] path: '/pages/:classify/subject/:id', name: 'SubjectView', components: { default: PagesView, subject: SubjectView } }, { // [4] path: '/search', name: 'SearchView', components: { default: PagesView, search: SearchView } }, { // [5] path: '/login', name: 'LoginView', component: LoginView }, { // [6] path: '/register', name: 'RegisterView', component: RegisterView }, { // [7] path: '*', redirect: '/pages/' } ]
路由的匹配規則是自上而下的,第一條[1]規則對路由進行了重定向。接着,第二條[2],對應了組件PagesView
,其中又包含了若干條子路由。這至關於上面描述的第一類模塊,擁有統一的視圖,子路由的路由出口爲本組件PagesView
中定義的<router-view>
。而這一個聚合的擁有子路由和子視圖的模塊對應的路由出口爲入口文件App.vue
中定義的無名路由出口<router-view class="view"></router-view>
。
能夠看到在App.vue
中還有兩個具名的路由出口:name="subject"
和name="search"
。subject
出口對應的路由爲[3],是電影,圖書等的詳情頁面,是否是以爲能夠把它劃分到[2]中的子路由中?徹底能夠,但這裏沒有這麼作,爲了將視圖和路由對應起來,擁有一個好看直觀的路徑,因此就抽了出來,單獨配置了,是否是有點蛇精病...回正題,爲了同時(同級)展現多個視圖,而不是嵌套展現,咱們配置了components
,將PagesView
和SubjectView
同時展現在視圖中。search
路由也作了一樣的處理。
5爲登陸註冊路由,只在視圖中展現了各自對應的單個組件,再也不受約束。自由發揮...
最後一條路由[7],至關於404頁面,在以上全部路由都不匹配的狀況下,重定向到404頁面,這裏又把它重定向到了主頁,是否是很機智...
數據驅動應用,當咱們的應用愈來愈大時,對數據的操控將會愈來愈複雜。那麼,咱們到底須要不須要集中式的狀態管理(Vuex)?
Flux 架構就像眼鏡:您自會知道何時須要它。 --Dan Abramov
對於組件來講,若是,數據自己高度隸屬於本組件,那麼,直接封裝在組件裏將是一個好的選擇。當父子組件之間共享數據,咱們也能經過props
和自定義事件解決。即便組件愈來愈多,視圖愈來愈多,若是彼此之間並沒有太大聯繫,咱們也沒有必要使用Vuex
。
稍微吐槽一下本項目:除了用戶模塊和搜索模塊的狀態以外,其餘的狀態是沒有必要必定使用Vuex的。電影數據,圖書數據,小組數據等是一次性數據,何時訪問就何時呈現,頂多會經過路由傳遞一些必要的參數。便是說,其餘視圖不依賴這些數據,它自己也不須要來自其餘視圖的狀態,而且這些狀態並不影響全局狀態。這個時候你沒必要使用Vuex。但你這裏使用了,做何解釋呢?的確,Vuex很酷,我想試試。沒別的理由。我能清楚明瞭的查看每個組件的狀態,掌控全局,這的確很酷。
吐槽完了!回正題。如今假設咱們的項目足夠大了(接着更新說不定就大了哦-_-!)。組件,視圖多的數不過來,而且他們之間的關係錯綜複雜。整個應用也須要記錄和維護更多的複雜的全局狀態。如今咱們有了Vuex,咱們把共享狀態抽取出來,以一個全局單例模式管理。咱們的應用構成一張巨大的蜘蛛網,而不論網的哪個節點都能訪問狀態。描述爲星型拓撲結構更容易理解一些吧。
爲了防止單一的狀態集中到一個文件中而變得冗餘,難以維護,咱們進一步的將狀態分割成了模塊,這些模塊和視圖一一對應,這樣代碼就變得更結構化,且很是容易維護了。
│ ├── store // Vuex全局狀態目錄 │ │ ├── index.js // Store根文件 │ │ └── modules // 模塊目錄 │ │ ├── activities.js // 活動相關狀態 │ │ ├── book.js // 書籍相關狀態 │ │ ├── group.js // 小組相關狀態 │ │ ├── movie.js // 電影相關狀態 │ │ ├── search.js // 搜索相關狀態 │ │ ├── subject.js // 主題相關狀態 │ │ └── user.js // 用戶相關狀態
不要爲了用vuex而用vuex
若是應用確實不大,只是有一些多層嵌套組件,兄弟組件之間傳遞狀態的需求,使用事件總線global event bus就ok啦!若是須要構建一箇中大型應用,爲了更好地管理狀態,上Vuex。至於,不要爲了用vuex而用vuex,只要你以爲用着爽,拿來用又何妨!
Ajax庫的選擇是比較自由的。起初,項目使用的是vue-resource
,其提供的jsonp方法用着比較爽,因爲項目的不少數據來自豆瓣的api,直接上jsonp簡單方便,跨域什麼的不考慮。你很機智嘛!vue-resource不支持服務端渲染,官方也再也不推薦vue-resource。但這個不影響它的使用,若是你喜歡,接着用也沒有問題。這裏我將vue-resource的版本released出來:The last version of vue-resource
花了一點時間,遷移到了Superagent
,準備作一些有趣的事情。和axios
基本相同,很明顯axios更火,axios的文章也更多一點,有的選未必很差。Superagent是在寫express時接觸的,先後端通用,做者殺馬特TJ,用了一段時間,還不錯。如今拿來和vue一塊用,更親切。
Superagent的api簡單易用,能知足大多數應用需求,輕量級,支持ssr,可擴展性強。Superagent和axios的核心都不支持jsonp,這裏採用了Superagent的插件superagent-jsonp
。
咱們能夠這麼使用:
import request from 'superagent' import jsonp from 'superagent-jsonp' request .get('https://api.douban.com/v2/event/list?loc=108288&start=' + state.skip + '&count=3') .use(jsonp) .end((err, res) => { if (!err) { commit({ type: 'loadMore', res: res.body.events }) } })
有關於Superagent的更多問題能夠閱讀官方文檔或參考本項目源碼。
登陸註冊部分只簡單的在先後端作了基本檢驗,更嚴格的表單驗證,沒有作。社區裏表單驗證的插件也不少,vee-validate比較好用,就很少說了,若是有須要能夠仔細閱讀文檔。這裏先挖個坑,我想再造個輪子,試一試...
我暫時總結了一些關於表單驗證的關鍵詞,算是佔個坑吧!
冗餘,遠程,時機,分離,集中式管理,重用,可配置,順序,自定義,字段消毒,隨機補充規則,優雅
我去!要求不少嘛...
數據來源,分兩個部分,一個是豆瓣的api:Douban Api V2,另外一個是mock的一些數據:Douban Backend。採用express手寫完成。跨域問題,上面已經介紹,在不能操控的豆瓣數據上,使用的是jsonp。部署在heroku上的mock數據服務,徹底可控,採用cors,藉助cors模塊完成。固然,方法不少,你的地盤,你作主。
在構建成功以後,咱們將dist/
中的文件發佈到咱們已經準備好的服務器上。
在發佈中會遇到兩個常見的問題:
第一:npm run build
後,項目部署到服務器,訪問頁面空白?
因爲項目是用vue-cli構建,咱們並無對項目作任何配置,儘管默認配置下它工做的很好。看控制檯,報錯,一連串的404,文件找不到。js沒加載上,vue沒有初始化,頁面天然空白。
解決方法:把congif/
目錄下index.js
中build
的assetsPublicPath
改成 ./
,而後從新npm run build。
第二:assetsPublicPath
配置正確,頁面依舊空白?
查看路由配置信息:mode: 'history'
啓用了History模式。使用 history 模式時,URL 就像正常的 url,不過這種模式要玩好,還須要後臺配置支持,vue-router文檔給出了不一樣服務器的簡單配置:HTML5 History 模式
發佈到github pages上:
github pages用來展現項目再好不過了。不過,咱們沒辦法作服務器配置,HTML5 History 模式要捨棄了,頁面的滾動行爲的體驗差點也不要緊,關於這兩點有後續文章。npm run build
後經過下面git命令發佈:
git add -f dist git commit -am 'Update live demo' git subtree push --prefix dist origin gh-pages
這是第一篇,比較雜亂一些,寫了這麼長,但願對你有所幫助。若是你在查看這個項目,或閱讀本文章時有什麼問題能夠直接聯繫我或到項目地址提交英文issue,歡迎各位小夥伴前來斧正,不勝感激......項目,系列文章將會持續更新,拖延症也在治療中...
本文首發於簡書
做者:jeneser
Github:https://github.com/jeneser
版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證)