vue2.0 一起在懵逼的海洋里越陷越深(五)

2,064 阅读8分钟
原文链接: leenty.com

前言

本文章系列:vue2.0一起在懵逼的海洋里越陷越深 (http://leenty.com/tags/vuejs/)
之前的几篇文章的说了vue-router以及vuex的简单使用,这次就开始组合这两者进行实际应用。
场地呢就在我的vue2.0Demo,这是源码地址,觉得靠谱的话欢迎加星跟随,有问题欢迎评论和指正😃
OK交代完毕,说下这回要完成的内容。
这回要做的是一个带缩放功能的滑动菜单(就是一个侧拉栏)和文章列表,以及文章的展示路由
使用vuex做状态管理控制css完成动画过度效果以及使用vue-router的嵌套路由功能。

滴滴滴!上车请刷卡!

正文

首先,我们先把核心功能完成,也就是vue-router的嵌套路由功能

嵌套路由功能

有些时候我们会遇到一个模板重复使用的情况,注意我说的并不是一个子模板在其父模板上的重复,而是多个页面之间的使用到相同的父模板。
就好比有这么几个路径

  • vue2.leenty.com/article/demo1
  • vue2.leenty.com/article/demo2
  • vue2.leenty.com/article/demo3
    可以发现其中共有的部分vue2.leenty.com/article
    /article/demo1                 /article/demo2               /article/demo3
    +------------------+           +-----------------+          +-----------------+
    | article          |           | article         |          | article         |
    | +--------------+ |           | +-------------+ |          | +-------------+ |
    | | demo1        | |  +----->  | | demo2       | | +----->  | | demo3       | |
    | |              | |           | |             | |          | |             | |
    | +--------------+ |           | +-------------+ |          | +-------------+ |
    +------------------+           +-----------------+          +-----------------+
    

没错,这个路径指向的就是父模板,他在多个子路由里被重复的渲染,如果我们没有对其做嵌套路由的处理,结果将是不仅我们写的累,vuejs渲染的也多余,因为这个模板被反复的使用却每次都被重新渲染。
so,我们开始做嵌套路由吧!
打开路由列表文件(routes.js)
tips:不要把routes.js和项目里的router.js搞混咯,一个是路由列表文件routes.js,一个是路由导出文件router.js
在里面我们假定有一个基础的路由(这个文件在本系列第二章里有讲到)

const routes = [
  {
    name: 'Article',
    path: '/article',
    component: require('./components/Article.vue')
    // 这里因为书写以及以后做异步组件的方便,将原先的import导入的方式改成了require的方式
    // 这么做不会实质上没和之前没有变化的,只是单纯的写法不同。
  }
]
export default routes

好,接下来我们加入子路由,
目前本系列已经有五篇文章,那么现在一一加入进去。
当前的项目路径

src
├── main.js               # vuejs应用入口
├── router.js             # 路由导出文件
├── routes.js             # 路由列表文件
├── App.vue               # vuejs应用根模板
├── components
│   ├── Home.vue
│   ├── Article.vue
│   ├── Demo.vue
│   ├── ...               # 存放各个路由入口文件
│   └── templates         # 存放模板
│       ├── AppArticleList.vue    # 文章列表 
│       └── ...
└── store
│   ├── index.js          # 组装模块并导出 store 的地方
│   ├── actions.js        # 根级别的 action
│   ├── mutations.js      # 根级别的 mutation
│   ├── types.js          # mutation命名空间
│   └── modules
│       ├── demo.js       # demo模块
│       └── status.js     # 全局应用状态模块
└── md                    # 存放md文件
    └── articles          # 文章路径 
        ├── vue2-1.vue
        ├── vue2-2.vue
        ├── vue2-3.vue
        ├── vue2-4.vue
        └── vue2-5.vue
        (这里为了讲解方便,会将.md文件替换为.vue文件,)
        (效果是一样的只是怕读者有些乱,.vue文件你们尝试的时候可以写些东西)

嵌套路由时会在原有路由对象的基础上添加一个children的节点
代码如下:

const routes = [
  {
    name: 'Article',
    path: '/article',
    // 父路由上尽量写绝对路径,不然可能会引起一些麻烦,
    // 有捣(xia)鼓(gao)精神的同学可以试试
    component: require('./components/Article.vue'),
    children: [
    // children节点:传入一个子路由数组,格式与父路由是一样的
      {
        name: 'vue2_1',
        path: 'vue2_1',
        // path: 导入的路径是相对路径,你不需要写全,如下的path将会被vuejs理解为:
        // '/article/vue2_1'
        // *** 注意: ***
          // 如果你写的是这样的相对路径,就千万别在前面加'/',不然就意味着这是一个绝对路径
        component: require('./md/articles/vue2-1.vue')
      },
      {
        name: 'vue2_2',
        path: '/article/vue2_2',
        // 演示一个绝对路径,这样子的路径会被vuejs理解为其本意'/article/vue2_2'
        // 如果这里只写了'/vue2_2'的话,vuejs就会把路由理解为'/vue2_2',
        // 不过不用担心他显示上的问题,只是url会有些有趣的区别
        // 你会发现虽然url变短了,但是父模板依然正常的显示着。
        component: require('./md/articles/vue2-2.vue')
      },
      {
        name: 'vue2_3',
        path: 'vue2_3',
        component: require('./md/articles/vue2-3.vue')
      },
      {
        name: 'vue2_4',
        path: 'vue2_4',
        component: require('./md/articles/vue2-4.vue')
      },
      {
        name: 'vue2_5',
        path: 'vue2_5',
        component: require('./md/articles/vue2-5.vue')
      }
    ]
  }
]
export default routes

嗯,好了,这样嵌套路由就建立好了

对侧拉栏做状态管理

打开src/store/modules/status.js
代码如下

import * as types from '../types'
// 引入命名空间,放置在types里
import getScrollData from '../../utils/scroll'
// 这是获得滚动数据的js文件,具体怎样写的可以去我github开源项目里看
// 导出的是一个方法,这个方法返回一个对象
// {
//    scrollTop: 0,
//    scrollHeight: 0,
//    windowHeight: 0,
//    scrollBottom: 0
// }
const state = {
  articleList: false,
  // 布尔值,表示侧拉文章列表的开关
  scroll: {
  // 滚动相关的数据
    scrollTop: 0,
    scrollHeight: 0,
    windowHeight: 0,
    scrollBottom: 0
  }
}
const getters = {
  // articleList: ({status}) => status.articleList
  // tips: 上面这种方法是错误的。这里的getters传入进来的不是state的根对象,
  // 而是当前的state对象,在这里也就相当于是state = state.status
  // 所以可以放心的用state
  articleList: state => state.articleList
  // 设置Getters,在.vue文件里可以使用mapGetters方法获得
}
const mutations = {
  [types.ARTICLE_LIST] (state) {
    state.articleList = !state.articleList
  },
  // 设置mutations,只有这个方法可以改变state
  [types.SCROLLDATA] (state, scrollObj) {
    state.scroll = scrollObj
  }
}
const actions = {
  articleListSwitch ({ commit }) {
    commit(types.ARTICLE_LIST)
  },
  // 设置actions,可以在这里做一些异步的工作,然后使用commit来调用mutations修改state
  pushScrollData ({ commit }) {
    commit(types.SCROLLDATA, getScrollData(), { silent: true })
    // 因为页面滚动触发频繁,会影响到我们平时的vuex的审查,所以这里选择静默提交
  }
}
export default {
  state,
  getters,
  actions,
  mutations
}
// 而后的.vue文件就可以调用辅助方法达到获取状态或者控制状态的目的了

调试vuex最好使用vuejs的谷歌插件Devtools
或者去github下载源码自己编译
翻墙要梯子(vpn),想翻墙没vpn的我这里安利一个vpn,没什么其他,因为我正用的就是这个。
贴一个云梯推荐码 referyt.com/?r=f688f08a…,通过推荐码注册可以优惠10元,笔者也可以得到10元优惠,在得到优惠的同时也是对我的鼓舞吧😂

渲染链接列表

接下来要做的就是做链接跳转。
切到AppArticleList.vue文件,也就是文章列表页。
大家可以在我的Demo里点击左上角的菜单按钮看到这个列表
!(AppArticleList.vue)[/img/vue/AppArticleList.jpg]

里面的内容是这样子的
(因为内容有些复杂,为了看的清晰点这是我提取出来的核心部分)
(源文件可以看github.com/leenty/vue2…)





  // css就不多说了
  @import '../../assets/stylus/preinstall'
  .articleList
    background-color c-master
  .articleList__content
    width s-articleList
    margin-top 8vh
    max-height 84vh
    color #fff
  .articleList__li
    transform translateX(-(s-articleList))
    transition transform .3s cb-duang .2s
  .articleList__link
    width 100%
    line-height 1.3em
    padding-left 10px
    min-height 50px
    background-color rgba(255,255,255,.1)
    &:hover
      background-color rgba(255,255,255,.3)
    svg
      transform-origin bottom center
      transform scale(.7)
  .articleList__link--Active
    background-color rgba(255,255,255,.4)
  .articleList--Active .articleList__li
    transform translateX(0)
  .articleList__title
    display block
    width 100%
    font-size 12px
    &:first-line
      font-size 14px

在写的过程中碰到了一个浏览器bug,这里还是说下
bug: 如果父元素进行了transform变换,那么子元素的position fixed将会失去作用,退化成position absolute
解决方案: 之前试过想要使用css的方式去绕过这个问题,但是发现不行,无奈使用了js去计算子元素退化成absolute后的差值,对其进行位移达到视觉的效果。
有兴趣的可以打开vue2.leenty.com/article/vue…然后审查元素,查看我的导航条也就是.header__content,这个时候你打开侧边栏然后上下滚动就会看到.header__content上js所不全的差值了

装载嵌套路由

打开article.vue文件,文件很简单,内容如下:




关于触发滚动之后的一系列事件

关于触发滚动,考虑到之后可能会有多个页面需要使滚动方面的数据,所以就放在了vuex里作为状态的一部分。
所以滚动的监听就只需要监听一次就好了,多个地方的监听会浪费资源
最终,我把监听放在了App.vue里面,在里面监听’scroll’事件,然后放在vuex上,供有需要的组件去使用




  @import './assets/stylus/main'
  .app__menu
    background-color c-master
  .app__content
    overflow auto
    transition transform .5s
    box-shadow 0 0 100px 5px rgba(0,0,0,0.3)
    background-color c-bgc
    transform-origin s-articleList center
  .app__content--Active
    transform scale(.9) translateX(s-articleList)
  .app__bodyer
    max-width max-width
    background-color c-bgc
  @media screen and (max-width: max-width)
    .app__bodyer
      padding 0 10px

ok,这么个流程走下来,算是把vuejs,vue-routervuex用在了一起

其他

演示地址(http://vue2.leenty.com)
源码地址(https://github.com/leenty/vue2)
github主页,觉得靠谱的话欢迎加星跟随