项目地址 https://github.com/hongchh/timeline-x

一、成品展示

1

2

3

4

二、项目需求

  • 添加每一天的时间记录,修改某天的时间记录(因为可能记错或者忘了记某项活动)
  • 每天的记录可以有多项活动,每项活动有对应的时间
  • 每项活动划分到特定的类型
2016-01-20,星期五
1. 学习Vue, 5h,[学习]
2. 跑步,0.5h,[运动]
3. 看霹雳布袋戏,2h,[休闲]

2、数据分析

  • 按照月份统计每天的总时间,按照年份统计每月的总时间,按照分类统计各项内容的总时间
  • 以图表形式展示月份时间支出和年份时间支出的变化情况
  • 以图表形式展示各种类型的活动的时间支出情况
  • 计算总时间和平均时间

3、时光展示

  • 时光轴形式进行活动记录展示,便于回顾总结
  • 轮播图形式进行活动记录展示,便于回顾总结

4、数据模型

{
  "items": [{
    "content": "string",
    "time": "number",
    "type": "string"
  }],
  "year": "number",
  "month": "number",
  "date": "number",
  "day": "number"
}

数据示例

{
  "items": [{
    "content": "学习Vue",
    "time": "5",
    "type": "学习"
  }, {
    "content": "跑步",
    "time": "0.5",
    "type": "运动"
  }, {
    "content": "看霹雳布袋戏",
    "time": "2",
    "type": "休闲"
  }],
  "year": "2016",
  "month": "01",
  "date": "20",
  "day": "5"
}

三、开发思路

1、界面构成

  • 整个应用分成2个主要界面:【主界面】,【权限界面】
  • 【权限界面】用于用户登录,也是应用的启动界面
  • 【主界面】包含3个子界面:【管理】,【时光轴】,【时光展】
  • 【时光轴】和【时光展】用于时光展示
  • 【管理】用于展示数据分析结果以及编辑时光记录(添加/修改)

2、跳转关系

  • 【权限界面】验证成功之后跳转到【主界面】
  • 【主界面】默认展示【时光轴】界面
  • 【主界面】顶栏可以选择跳转到【管理】、【时光轴】或【时光展】界面
  • 【主界面】顶栏选择“锁屏”之后回到【权限界面】

3、组件划分

└─App:挂载整个应用
   ├─Auth:【权限界面】
   │  └─StarFlow:【权限界面】底部的动画
   └─Main:【主界面】的基本结构
      ├─Management:【管理】
      │     ├─TimeAnalysisPerMonth:月份时间分析组件
      │     ├─TimeAnalysisPerYear:年份时间分析组件
      │     ├─TimeAnalysisByType:分类时间分析组件
      │     └─EditTimeRecord:时间记录编辑组件
      ├─Timeline:【时光轴】
      └─TimeSlide:【时光展】

4、文件结构

└─build:构建用到的相关文件
├─config:构建的配置文件
├─server:应用的服务器源码
│   ├─controller:服务端业务逻辑
│   ├─model:数据存储逻辑
│   ├─static:静态文件
│   ├─views:应用的视图文件
│   ├─app.js:express服务器配置文件
│   └─server.js:服务器启动文件
├─src:前端开发源码
│   ├─assets:图片等静态资源
│   ├─components:前端组件
│   ├─router:前端路由
│   ├─store:vuex的store
│   ├─App.vue:应用的外层结构
│   └─entry.js:应用的入口文件
└─static:前端开发过程中用到的静态文件
    └─data:存放伪数据以及伪数据生成器

四、开发历程

1、基础配置

使用vue-cli生成一个webpack项目模板

vue init webpack timeline-x

生成之后为了支持jade+sass开发,还需要安装相关的依赖

npm install node-sass --save-dev
npm install sass-loader --save-dev
npm install jade --save-dev

配置完成之后我们就可以在项目中使用jade和sass来进行开发了,.vue文件的模板如下,注意在template标签和style标签里面使用lang属性说明jade和sass。

<template lang="jade">
div#auth
  h1 Auth Page
</template>

<script>
export default {
  name: 'auth'
}
</script>

<style lang="sass">
#auth
  border: 1px solid red
</style> 

2、准备组件

按照之前划分好的组件,在src/components文件夹里面准备好相关文件。暂时不需要写入各组件的内容,就按照上面的模板一样写个标题说明这是哪个组件即可。

c

3、配置路由

组件都准备好之后安装路由

npm install vue-router --save

安装完成之后需要在使用路由的时候将其导入,我这里选择在router/index.js文件里面导入。

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

按照前面确定好的页面跳转关系配置路由信息,然后测试界面跳转是否正常。

const router = new Router({
  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' }
  ]
})

4、组件设计

UI方面使用了一些element-ui的组件,因此还需要先安装element-ui。同样地安装之后需要导入,导入方法类似之前的vue-router。注意这里还需要导入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个时间分析图表使用的是echarts,需要先安装echarts。安装之后import需要用到的图表就行了,这样经过webpack构建之后的产品代码就只有用到的图表的那部分代码了,可以较少产品代码体积。

npm install echarts --save

由于我只用到了柱状图和圆饼图,然后图表上面还使用了标题和提示等组件,所以只需要在entry.js里面导入这些组件即可。

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】准备好的文件里面开始编写组件。在template标签中编写组件的HTML结构,然后在style标签中调节样式,业务逻辑则是放在script标签中。下面我用Auth.vue来作为例子,其他组件请参考github仓库里面的代码。

权限界面比较简单(参考上面的成品展示图),HTML结构如下,使用element-ui的栅格布局,同时用了另外一个动态背景组件star-flow。

div#auth
  star-flow
  div#auth-input
    el-row(:gutter="20")
      el-col(:span="8", :offset="8")
        el-tooltip(:disabled="disabled", :content="errorTip", placement="bottom-start", effect="light")
          el-input(placeholder="请输入密码", v-model="password", type="password")
            template(slot="append")
              el-button(@click="signin") Go

样式如下,设置一下背景图、宽高度之类的。

#auth
  width: 100%
  height: 100%
  background: url(../../assets/auth-bg.jpg) no-repeat
  background-size: 100% 100%
  background-attachment: fixed
  #auth-input
    position: absolute
    width: 100%
    height: 10%
    top: 45%

下面是js部分了,使用es6的写法,为了使用另一个组件,需要先将其import进来然后添加到components里面。export是将当前的组件导出,其他模块才能使用到。data里面写该组件用到的数据项,methods则是这个组件里面需要的方法函数了。(有点类似angular的controller)

import StarFlow from './StarFlow'

export default {
  name: 'auth',
  components: { StarFlow },
  data () {
    return {
      password: '',
      disabled: true,
      errorTip: ''
    }
  },
  methods: {
    setTip (tip) { // 消息提示,1.5秒后自动关闭
      this.errorTip = tip
      this.disabled = false
      setTimeout(() => {
        this.disabled = true
        this.errorTip = ''
      }, 1500)
    },

    signin () { // 验证密码解除锁屏
      if (!this.password) {
        this.setTip('密码不能为空')
      } else {
        this.$store.dispatch('unlockScreen', this.password)
        .then((err) => {
          if (err) this.setTip('密码错误')
          else this.$router.replace('/main')
        })
      }
    }
  }
}

5、改善UI

调整组件的样式,并且改进应用的样式,添加过渡动画。过渡动画直接在router-view外面套一个transition,然后编写相应的过渡样式即可,很简便。

6、数据状态管理

该项目由6个组件需要用到同一份数据,1个记录编辑组件、2个时光展示组件和3个数据分析组件。为了方便数据管理,同时也好制造机会学习Vuex,因此我这里引入vuex来进行应用的状态管理。安装vuex,然后在store/index.js里面导入vuex。

npm install vuex --save
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

定义1个store存放应用的全局状态:锁屏变量和时间记录。默认开启锁屏,所以lockScreen设置为true,而timeRecords则是一个时间记录数据,里面包含多条记录。这些数据在应用启动接触锁屏之后向服务器获取,在还没有开发服务器的时候,为了完成前端开发可以先在这里写一些伪数据进去。

const store = new Vuex.Store({
  state: {
    lockScreen: true,
    timeRecords: []
  },
  mutations,
  actions
})

在store/actions.js和store/mutations.js里面定义这些全级状态可能发生的变化。如果涉及到异步操作,则将这些涉及异步的变化放到actions.js里面,例如向服务器获取数据这个操作就是一个异步的,应该将其代码放在action里面。根据Vuex文档的介绍,mutation的代码必须要是同步的。

由于涉及跟服务器的交互,所以我们还需要一个提供http服务模块。上网查了查,有vue-resource这个东西可以用,不过好像更推荐使用axios,因此我这里也选择使用axios。下面进行安装和导入。

npm install axios --save
import axios from 'axios'

准备好了之后可以开始编写了,下面是actions.js的代码,其他代码请参考github仓库。实现了后台交互功能,然后通过commit相应的mutation来更新store里面的状态。注释部分的代码是在前端开发还没有服务器的时候使用的开发代码。

export default {
  unlockScreen ({commit}, password) { // 验证密码,接触锁屏
    // 使用"npm run dev"启动时候请解除下面代码的注释,注释后面的POST代码
    // return new Promise((resolve, reject) => {
    //   commit('UNLOCK')
    //   resolve(false)
    // })
    return axios.post('/api/check', {
      password: password
    }).then((res) => {
      if (!res || res.status !== 200 || res.data.err) {
        return true
      } else {
        commit('UNLOCK')
        return false
      }
    })
  },

  addRecord ({commit}, record) { // 添加记录
    // 使用"npm run dev"启动时候请解除下面代码的注释,注释后面的POST代码
    // return new Promise((resolve, reject) => {
    //   commit('UPDATE_RECORD', record)
    //   resolve(false)
    // })
    return axios.post('/api/add', record).then((res) => {
      if (!res || res.status !== 200 || res.data.err) {
        return true
      } else {
        commit('UPDATE_RECORD', record)
        return false
      }
    })
  },

  fatchData ({commit}) { // 获取数据
    axios.get('/static/data/data.json').then((res) => {
      if (res.status === 200) {
        commit('FATCH_DATA', res.data)
      }
    })
  }
}

7、准备伪数据

为了让应用有更多数据可以呈现,需要自行编造一些伪数据,我写了一个伪数据生成器,即static/data/data-generator.js。运行之后产生100多条时间记录并存放到json文件里面。具体请参考github仓库。

8、完善锁屏

实现锁屏功能其实不难,只要在权限界面检验之后更新store里面的锁屏状态为false,在主界面点击顶栏的锁屏之后更新store里面的锁屏状态为true即可。但为了更完善,还需要在路由里面设置一个全局钩子,在进入相应界面之前检查一下store的锁屏状态,例如,在访问主界面的时候需要检查store里面的锁屏状态是否为true,如果是的话强行给它重定向到权限界面,因为这可能是用户通过手动修改URL来访问的。

这里有一个坑,在router的全局钩子里面访问不到store里面的状态。在stack-overflow里面找到了这个解决方案,把store也给import到router里面去,这样就可以访问到了。不知道有没有其他更优秀的方案,欢迎交流。

import store from '../store'

router.beforeEach((to, from, next) => { // 对特定路径进行验证,增强锁屏功能
  if (to.path === '/') {
    next('/auth')
  } else if (to.path === '/auth' && !store.state.lockScreen) {
    next('/main')
  } else if (to.path !== '/auth' && store.state.lockScreen) {
    next('/auth')
  } else {
    next()
  }
})

9、后台开发

前端开发基本完成之后就可以开始后台开发了,我后端使用的是express框架,按照MVC模式进行开发。由于本项目关注的是前端开发,所以后端就写得比较简单,也没有用上数据库,没有什么好讲的。主要有一点需要注意,为了方便,我更改了build的目标路径。用vue-cli生成的webpack项目build之后是在主目录下面生成一个dist文件夹来存放产品文件,我将其改成build之后静态文件放到server里面的static文件夹,而index.html则放到server里面的views文件夹,这样就不用手动去搬dist里面的文件给服务器用了。改动很简单,只需要该config/index.js里面的7-8行即可。

index: path.resolve(__dirname, '../server/views/index.html'),
assetsRoot: path.resolve(__dirname, '../server'),

10、前后对接

对接前端和后台的接口,调整代码,修正bug。如果一开始将接口想清楚、设计好的话这里基本没有什么难。本项目只有2个post数据和1个get数据的接口,没有难度。

11、改进,修正小问题

五、结束

大概用了5天写这个项目,基本入门了Vue,还是一次蛮不错的体验。为了多点练习强行加入了vuex,虽然官方推荐不要在小项目里面使用vuex,但我觉得引入vuex之后还是可以解决很多问题,思路也清晰了很多。在用vuex之前的想法是在一个外层的组件里面获取数据然后传递给子组件。后来发现如果我在编辑记录组件里面更新或者添加了一条记录,父组件和其他兄弟组件的数据不会收到更新。如果通过$emit来让父亲组件更新数据然后再使得兄弟组件更新,整个过程又太过繁琐。而Vuex的思路是弄一个全局状态来对数据进行管理,组件树上的组件都可以更新状态,状态变化之后会反馈到相应的其他组件上。这个思路很清晰,代码写起来也很顺利,也体验了vuex的强大,确实可以省事很多。

部分内容可能无法讲得很清楚,有兴趣了解的话请参考github仓库的代码和commit记录。下面说说几点收获:

  • es6写起来感觉超棒
  • webpack比gulp优雅
  • vue值得尝试
Logo

一站式虚拟内容创作平台,激发创意,赋能创作,进入R空间,遇见同道,让优质作品闪耀发光。​

更多推荐