項(xiàng)目地址?https://github.com/hongchh/timeline-x
添加每一天的時(shí)間記錄堕汞,修改某天的時(shí)間記錄(因?yàn)榭赡苡涘e(cuò)或者忘了記某項(xiàng)活動(dòng))
每天的記錄可以有多項(xiàng)活動(dòng),每項(xiàng)活動(dòng)有對(duì)應(yīng)的時(shí)間
每項(xiàng)活動(dòng)劃分到特定的類型
2016-01-20税课,星期五1. 學(xué)習(xí)Vue, 5h俱萍,[學(xué)習(xí)]2. 跑步镀首,0.5h,[運(yùn)動(dòng)]3. 看霹靂布袋戲鼠次,2h更哄,[休閑]
按照月份統(tǒng)計(jì)每天的總時(shí)間,按照年份統(tǒng)計(jì)每月的總時(shí)間成翩,按照分類統(tǒng)計(jì)各項(xiàng)內(nèi)容的總時(shí)間
以圖表形式展示月份時(shí)間支出和年份時(shí)間支出的變化情況
以圖表形式展示各種類型的活動(dòng)的時(shí)間支出情況
計(jì)算總時(shí)間和平均時(shí)間
時(shí)光軸形式進(jìn)行活動(dòng)記錄展示,便于回顧總結(jié)
輪播圖形式進(jìn)行活動(dòng)記錄展示麻敌,便于回顧總結(jié)
{? "items":[{? ? "content":"string",? ? "time":"number",? ? "type":"string"}],? "year":"number",? "month":"number",? "date":"number",? "day":"number"}
數(shù)據(jù)示例
{? "items":[{? ? "content":"學(xué)習(xí)Vue",? ? "time":"5",? ? "type":"學(xué)習(xí)"}, {? ? "content":"跑步",? ? "time":"0.5",? ? "type":"運(yùn)動(dòng)"}, {? ? "content":"看霹靂布袋戲",? ? "time":"2",? ? "type":"休閑"}],? "year":"2016",? "month":"01",? "date":"20",? "day":"5"}
整個(gè)應(yīng)用分成2個(gè)主要界面:【主界面】赢赊,【權(quán)限界面】
【權(quán)限界面】用于用戶登錄,也是應(yīng)用的啟動(dòng)界面
【主界面】包含3個(gè)子界面:【管理】级历,【時(shí)光軸】释移,【時(shí)光展】
【時(shí)光軸】和【時(shí)光展】用于時(shí)光展示
【管理】用于展示數(shù)據(jù)分析結(jié)果以及編輯時(shí)光記錄(添加/修改)
【權(quán)限界面】驗(yàn)證成功之后跳轉(zhuǎn)到【主界面】
【主界面】默認(rèn)展示【時(shí)光軸】界面
【主界面】頂欄可以選擇跳轉(zhuǎn)到【管理】寥殖、【時(shí)光軸】或【時(shí)光展】界面
【主界面】頂欄選擇“鎖屏”之后回到【權(quán)限界面】
└─App:掛載整個(gè)應(yīng)用
? ├─Auth:【權(quán)限界面】
? │? └─StarFlow:【權(quán)限界面】底部的動(dòng)畫
? └─Main:【主界面】的基本結(jié)構(gòu)
? ? ? ├─Management:【管理】
? ? ? │? ? ├─TimeAnalysisPerMonth:月份時(shí)間分析組件
? ? ? │? ? ├─TimeAnalysisPerYear:年份時(shí)間分析組件
? ? ? │? ? ├─TimeAnalysisByType:分類時(shí)間分析組件
? ? ? │? ? └─EditTimeRecord:時(shí)間記錄編輯組件
? ? ? ├─Timeline:【時(shí)光軸】
? ? ? └─TimeSlide:【時(shí)光展】
└─build:構(gòu)建用到的相關(guān)文件├─config:構(gòu)建的配置文件├─server:應(yīng)用的服務(wù)器源碼│? ├─controller:服務(wù)端業(yè)務(wù)邏輯│? ├─model:數(shù)據(jù)存儲(chǔ)邏輯│? ├─static:靜態(tài)文件│? ├─views:應(yīng)用的視圖文件│? ├─app.js:express服務(wù)器配置文件│? └─server.js:服務(wù)器啟動(dòng)文件├─src:前端開發(fā)源碼│? ├─assets:圖片等靜態(tài)資源│? ├─components:前端組件│? ├─router:前端路由│? ├─store:vuex的store│? ├─App.vue:應(yīng)用的外層結(jié)構(gòu)│? └─entry.js:應(yīng)用的入口文件└─static:前端開發(fā)過程中用到的靜態(tài)文件? ? └─data:存放偽數(shù)據(jù)以及偽數(shù)據(jù)生成器
使用vue-cli生成一個(gè)webpack項(xiàng)目模板
vue init webpack timeline-x
生成之后為了支持jade+sass開發(fā),還需要安裝相關(guān)的依賴
npm install node-sass --save-dev
npm install sass-loader --save-dev
npm install jade --save-dev
配置完成之后我們就可以在項(xiàng)目中使用jade和sass來進(jìn)行開發(fā)了粤策,.vue文件的模板如下樟澜,注意在template標(biāo)簽和style標(biāo)簽里面使用lang屬性說明jade和sass。
div#auth? h1 Auth Pageexportdefault{? name:'auth'}#authborder: 1pxsolidred
按照之前劃分好的組件秩贰,在src/components文件夾里面準(zhǔn)備好相關(guān)文件。暫時(shí)不需要寫入各組件的內(nèi)容熊户,就按照上面的模板一樣寫個(gè)標(biāo)題說明這是哪個(gè)組件即可。
組件都準(zhǔn)備好之后安裝路由
npm install vue-router --save
安裝完成之后需要在使用路由的時(shí)候?qū)⑵鋵?dǎo)入嚷堡,我這里選擇在router/index.js文件里面導(dǎo)入。
import Vue from'vue'import Router from'vue-router'Vue.use(Router)
按照前面確定好的頁(yè)面跳轉(zhuǎn)關(guān)系配置路由信息艇棕,然后測(cè)試界面跳轉(zhuǎn)是否正常蝌戒。
constrouter =newRouter({? mode:'history',? routes: [? ? { path:'/auth', component: Auth },? ? {? ? ? path:'/main',? ? ? component: Main,? ? ? children: [? ? ? ? { path:'management', component: Management },? ? ? ? { path:'timeline', component: Timeline },? ? ? ? { path:'time-slide', component: TimeSlide },? ? ? ? { path:'', redirect:'timeline'}? ? ? ]? ? },? ? { path:'/', redirect:'/auth'}? ]})
UI方面使用了一些element-ui的組件沼琉,因此還需要先安裝element-ui北苟。同樣地安裝之后需要導(dǎo)入,導(dǎo)入方法類似之前的vue-router打瘪。注意這里還需要導(dǎo)入element-ui的樣式文件index.css友鼻。
npm install element-ui --save
import Vue from'vue'import ElementUI from'element-ui'import'element-ui/lib/theme-default/index.css'Vue.use(ElementUI)
3個(gè)時(shí)間分析圖表使用的是echarts傻昙,需要先安裝echarts。安裝之后import需要用到的圖表就行了挂滓,這樣經(jīng)過webpack構(gòu)建之后的產(chǎn)品代碼就只有用到的圖表的那部分代碼了猪瞬,可以較少產(chǎn)品代碼體積岩齿。
npm install echarts --save
由于我只用到了柱狀圖和圓餅圖,然后圖表上面還使用了標(biāo)題和提示等組件贾惦,所以只需要在entry.js里面導(dǎo)入這些組件即可。
import'echarts/lib/chart/pie'import'echarts/lib/chart/bar'import'echarts/lib/component/tooltip'import'echarts/lib/component/title'import'echarts/lib/component/legend'
到步驟【2】準(zhǔn)備好的文件里面開始編寫組件敦捧。在template標(biāo)簽中編寫組件的HTML結(jié)構(gòu)须板,然后在style標(biāo)簽中調(diào)節(jié)樣式,業(yè)務(wù)邏輯則是放在script標(biāo)簽中兢卵。下面我用Auth.vue來作為例子习瑰,其他組件請(qǐng)參考github倉(cāng)庫(kù)里面的代碼。
權(quán)限界面比較簡(jiǎn)單(參考上面的成品展示圖)济蝉,HTML結(jié)構(gòu)如下杰刽,使用element-ui的柵格布局,同時(shí)用了另外一個(gè)動(dòng)態(tài)背景組件star-flow王滤。
div#authstar-flowdiv#auth-inputel-row(:gutter="20")? ? ? el-col(:span="8", :offset="8")? ? ? ? el-tooltip(:disabled="disabled", :content="errorTip", placement="bottom-start", effect="light")? ? ? ? ? el-input(placeholder="請(qǐng)輸入密碼", v-model="password",type="password")? ? ? ? ? ? template(slot="append")? ? ? ? ? ? ? el-button(@click="signin") Go
樣式如下贺嫂,設(shè)置一下背景圖、寬高度之類的雁乡。
#authwidth:100%height:100%background: url(../../assets/auth-bg.jpg) no-repeatbackground-size:100%100%background-attachment: fixed#auth-inputposition: absolute? ? width:100%height:10%top:45%
下面是js部分了第喳,使用es6的寫法,為了使用另一個(gè)組件踱稍,需要先將其import進(jìn)來然后添加到components里面曲饱。export是將當(dāng)前的組件導(dǎo)出,其他模塊才能使用到珠月。data里面寫該組件用到的數(shù)據(jù)項(xiàng)扩淀,methods則是這個(gè)組件里面需要的方法函數(shù)了。(有點(diǎn)類似angular的controller)
import StarFlow from'./StarFlow'exportdefault{? name:'auth',? components: { StarFlow },? data () {return{? ? ? password:'',? ? ? disabled:true,? ? ? errorTip:''}? },? methods: {? ? setTip (tip) {// 消息提示啤挎,1.5秒后自動(dòng)關(guān)閉this.errorTip = tipthis.disabled =falsesetTimeout(() => {this.disabled =truethis.errorTip =''},1500)? ? },? ? signin () {// 驗(yàn)證密碼解除鎖屏if(!this.password) {this.setTip('密碼不能為空')? ? ? }else{this.$store.dispatch('unlockScreen',this.password)? ? ? ? .then((err) => {if(err)this.setTip('密碼錯(cuò)誤')elsethis.$router.replace('/main')? ? ? ? })? ? ? }? ? }? }}
調(diào)整組件的樣式,并且改進(jìn)應(yīng)用的樣式庆聘,添加過渡動(dòng)畫胜臊。過渡動(dòng)畫直接在router-view外面套一個(gè)transition,然后編寫相應(yīng)的過渡樣式即可伙判,很簡(jiǎn)便象对。
該項(xiàng)目由6個(gè)組件需要用到同一份數(shù)據(jù)宴抚,1個(gè)記錄編輯組件勒魔、2個(gè)時(shí)光展示組件和3個(gè)數(shù)據(jù)分析組件甫煞。為了方便數(shù)據(jù)管理,同時(shí)也好制造機(jī)會(huì)學(xué)習(xí)Vuex沥邻,因此我這里引入vuex來進(jìn)行應(yīng)用的狀態(tài)管理危虱。安裝vuex,然后在store/index.js里面導(dǎo)入vuex唐全。
npm install vuex --save
import Vue from'vue'import Vuex from'vuex'Vue.use(Vuex)
定義1個(gè)store存放應(yīng)用的全局狀態(tài):鎖屏變量和時(shí)間記錄埃跷。默認(rèn)開啟鎖屏,所以lockScreen設(shè)置為true邮利,而timeRecords則是一個(gè)時(shí)間記錄數(shù)據(jù)弥雹,里面包含多條記錄。這些數(shù)據(jù)在應(yīng)用啟動(dòng)接觸鎖屏之后向服務(wù)器獲取延届,在還沒有開發(fā)服務(wù)器的時(shí)候剪勿,為了完成前端開發(fā)可以先在這里寫一些偽數(shù)據(jù)進(jìn)去。
conststore =newVuex.Store({? state: {? ? lockScreen:true,? ? timeRecords: []? },? mutations,? actions})
在store/actions.js和store/mutations.js里面定義這些全級(jí)狀態(tài)可能發(fā)生的變化方庭。如果涉及到異步操作厕吉,則將這些涉及異步的變化放到actions.js里面,例如向服務(wù)器獲取數(shù)據(jù)這個(gè)操作就是一個(gè)異步的械念,應(yīng)該將其代碼放在action里面头朱。根據(jù)Vuex文檔的介紹,mutation的代碼必須要是同步的龄减。
由于涉及跟服務(wù)器的交互项钮,所以我們還需要一個(gè)提供http服務(wù)模塊。上網(wǎng)查了查希停,有vue-resource這個(gè)東西可以用烁巫,不過好像更推薦使用axios,因此我這里也選擇使用axios宠能。下面進(jìn)行安裝和導(dǎo)入亚隙。
npm install axios --save
import axios from'axios'
準(zhǔn)備好了之后可以開始編寫了,下面是actions.js的代碼违崇,其他代碼請(qǐng)參考github倉(cāng)庫(kù)阿弃。實(shí)現(xiàn)了后臺(tái)交互功能,然后通過commit相應(yīng)的mutation來更新store里面的狀態(tài)亦歉。注釋部分的代碼是在前端開發(fā)還沒有服務(wù)器的時(shí)候使用的開發(fā)代碼恤浪。
exportdefault{? unlockScreen ({commit}, password) {// 驗(yàn)證密碼畅哑,接觸鎖屏// 使用"npm run dev"啟動(dòng)時(shí)候請(qǐng)解除下面代碼的注釋肴楷,注釋后面的POST代碼// return new Promise((resolve, reject) => {//? commit('UNLOCK')//? resolve(false)// })returnaxios.post('/api/check', {? ? ? password: password? ? }).then((res) => {if(!res || res.status !==200|| res.data.err) {returntrue}else{? ? ? ? commit('UNLOCK')returnfalse}? ? })? },? addRecord ({commit}, record) {// 添加記錄// 使用"npm run dev"啟動(dòng)時(shí)候請(qǐng)解除下面代碼的注釋,注釋后面的POST代碼// return new Promise((resolve, reject) => {//? commit('UPDATE_RECORD', record)//? resolve(false)// })returnaxios.post('/api/add', record).then((res) => {if(!res || res.status !==200|| res.data.err) {returntrue}else{? ? ? ? commit('UPDATE_RECORD', record)returnfalse}? ? })? },? fatchData ({commit}) {// 獲取數(shù)據(jù)axios.get('/static/data/data.json').then((res) => {if(res.status ===200) {? ? ? ? commit('FATCH_DATA', res.data)? ? ? }? ? })? }}
為了讓應(yīng)用有更多數(shù)據(jù)可以呈現(xiàn)赛蔫,需要自行編造一些偽數(shù)據(jù)砂客,我寫了一個(gè)偽數(shù)據(jù)生成器,即static/data/data-generator.js呵恢。運(yùn)行之后產(chǎn)生100多條時(shí)間記錄并存放到j(luò)son文件里面鞠值。具體請(qǐng)參考github倉(cāng)庫(kù)。
實(shí)現(xiàn)鎖屏功能其實(shí)不難彤恶,只要在權(quán)限界面檢驗(yàn)之后更新store里面的鎖屏狀態(tài)為false,在主界面點(diǎn)擊頂欄的鎖屏之后更新store里面的鎖屏狀態(tài)為true即可鳄橘。但為了更完善声离,還需要在路由里面設(shè)置一個(gè)全局鉤子,在進(jìn)入相應(yīng)界面之前檢查一下store的鎖屏狀態(tài)瘫怜,例如术徊,在訪問主界面的時(shí)候需要檢查store里面的鎖屏狀態(tài)是否為true,如果是的話強(qiáng)行給它重定向到權(quán)限界面鲸湃,因?yàn)檫@可能是用戶通過手動(dòng)修改URL來訪問的赠涮。
這里有一個(gè)坑,在router的全局鉤子里面訪問不到store里面的狀態(tài)暗挑。在stack-overflow里面找到了這個(gè)解決方案笋除,把store也給import到router里面去,這樣就可以訪問到了窿祥。不知道有沒有其他更優(yōu)秀的方案株憾,歡迎交流。
import store from'../store'router.beforeEach((to, from, next) => {// 對(duì)特定路徑進(jìn)行驗(yàn)證晒衩,增強(qiáng)鎖屏功能if(to.path ==='/') {? ? next('/auth')? }elseif(to.path ==='/auth'&& !store.state.lockScreen) {? ? next('/main')? }elseif(to.path !=='/auth'&& store.state.lockScreen) {? ? next('/auth')? }else{? ? next()? }})
前端開發(fā)基本完成之后就可以開始后臺(tái)開發(fā)了,我后端使用的是express框架听系,按照MVC模式進(jìn)行開發(fā)贝奇。由于本項(xiàng)目關(guān)注的是前端開發(fā),所以后端就寫得比較簡(jiǎn)單靠胜,也沒有用上數(shù)據(jù)庫(kù)掉瞳,沒有什么好講的。主要有一點(diǎn)需要注意浪漠,為了方便陕习,我更改了build的目標(biāo)路徑。用vue-cli生成的webpack項(xiàng)目build之后是在主目錄下面生成一個(gè)dist文件夾來存放產(chǎn)品文件址愿,我將其改成build之后靜態(tài)文件放到server里面的static文件夾该镣,而index.html則放到server里面的views文件夾,這樣就不用手動(dòng)去搬dist里面的文件給服務(wù)器用了响谓。改動(dòng)很簡(jiǎn)單损合,只需要該config/index.js里面的7-8行即可省艳。
index: path.resolve(__dirname,'../server/views/index.html'),assetsRoot: path.resolve(__dirname,'../server'),
對(duì)接前端和后臺(tái)的接口嫁审,調(diào)整代碼跋炕,修正bug。如果一開始將接口想清楚律适、設(shè)計(jì)好的話這里基本沒有什么難辐烂。本項(xiàng)目只有2個(gè)post數(shù)據(jù)和1個(gè)get數(shù)據(jù)的接口,沒有難度捂贿。
大概用了5天寫這個(gè)項(xiàng)目分瘾,基本入門了Vue,還是一次蠻不錯(cuò)的體驗(yàn)吁系。為了多點(diǎn)練習(xí)強(qiáng)行加入了vuex德召,雖然官方推薦不要在小項(xiàng)目里面使用vuex,但我覺得引入vuex之后還是可以解決很多問題汽纤,思路也清晰了很多上岗。在用vuex之前的想法是在一個(gè)外層的組件里面獲取數(shù)據(jù)然后傳遞給子組件。后來發(fā)現(xiàn)如果我在編輯記錄組件里面更新或者添加了一條記錄蕴坪,父組件和其他兄弟組件的數(shù)據(jù)不會(huì)收到更新肴掷。如果通過$emit來讓父親組件更新數(shù)據(jù)然后再使得兄弟組件更新,整個(gè)過程又太過繁瑣背传。而Vuex的思路是弄一個(gè)全局狀態(tài)來對(duì)數(shù)據(jù)進(jìn)行管理呆瞻,組件樹上的組件都可以更新狀態(tài),狀態(tài)變化之后會(huì)反饋到相應(yīng)的其他組件上径玖。這個(gè)思路很清晰痴脾,代碼寫起來也很順利,也體驗(yàn)了vuex的強(qiáng)大梳星,確實(shí)可以省事很多赞赖。
部分內(nèi)容可能無法講得很清楚,有興趣了解的話請(qǐng)參考github倉(cāng)庫(kù)的代碼冤灾。下面說說幾點(diǎn)收獲:
es6寫起來感覺超棒
webpack比gulp優(yōu)雅
vue值得嘗試