Vue2.5构建去哪儿网

268 阅读5分钟

技术栈

  • Vue: Vue、Vue-router、Vuex、Vue-cli
  • 插件:axios、vue-swesome-swiper、better-scroll
  • css样式预设置:stylus
  • api:后台接口数据

生成文件的部分说明

 build文件 -- 项目webpack打包配置内容

 config文件 -- 项目配置内容

 node_modules文件 -- 第三方依赖包

 src文件 -- 存放整个项目的源代码

   src/router文件 -- 项目的所有路由

   src/assets文件 -- 会被webpack打包成依赖模块

   src/App.vue -- 项目的根组件

   src/main.js -- 项目的入口文件

 static文件 -- 里面的文件不会被webpack打包处理,而是被直接复制到最终目录(dist/static)下

 index.html -- 默认页面

项目特点

  • 组件化开发
  • 易于维护

项目分为几部分?

  • 首页部分
  • 详情页部分
  • 城市选择部分

项目怎样拆分?

  • 按照页面拆分,src/pages目录下每个夹代表一个页面
  • 页面文件夹(父组件)下管理组成页面的子组件文件,父子组件间利用props传值。组件化使每部分的代码更清晰,易于维护
  • 在router/index.js中管理路由

首页部分

  1. iconfont图标引入与使用
  2. 使用vue-swesome-swiper轮播插件
  3. 公用样式封装
  4. axios获取接口数据
  5. 父子组件间传值

使用vue-awesome-swiper轮播组件(2.6.7版本)

安装这个插件

npm install vue-awesome-swiper --save

用import在入口文件(main.js)中导入

import VueAwesomeSwiper from 'vue-awesome-swiper'

为了防止因为网速过慢而引起的页面抖动,我们将css样式设置成

overflow hidden
width 100%
height 0
padding-bottom 31.25%

使包裹插件的div的高度由宽度的27%撑开。

这里要注意的是,vue-awesome-swiper插件拥有自己的样式,要让它使用我们定义的样式,需要用到>>>和ref

构建多页切换

利用计算属性根据图标数量判断当前图标在哪个页面,构建多页切换功能

  computed: {
    pages: function () {
        const res = []
        for (let i in this.iconList) {
            const k = Math.floor(i / 8)
            if (!res[k]) {
                res[k] = []
            }
            res[k].push(this.iconList[i])
        }
        return res
    }
  }

样式封装

将公用样式封装在varibles.styl和mixins.styl文件中,有以下几点好处:

  1.可以方便得被组件使用,避免重复编写样式

  2.便于后期维护

使用axios进行ajax请求

安装axios插件

将静态文件放在static文件夹下,这些静态文件能被浏览器直接读取

开发环境转发代理,设置配置文件(config/index.js)下devproxyTable内容,webpack-dev-serve工具会自动将/api转换成static/mock

 proxyTable: {
  '/api': {
    target: 'http://localhost:8081/',
    pathRewrite: {
      '^/api':'/static/mock'
    }
  }
}

用import在父组件导入axios,发送get请求

 axios.get('/api/index.json')

城市选择部分

  1. router-link内部组件的使用
  2. 使用better-scroll插件

实现页面跳转

使用<router-link>内部组件通过路由实现跳转页面的功能,to后边加需要跳转的页面的路由,(to = "/"表示跳转到根路径下的页面)

<router-link to="/">
  <div class="header-left">
    <div class="iconfont back-icon">&#xe606;</div>
  </div>
</router-link>

使用better-scroll插件

首先通过修改样式使页面固定,后续搭配better-scroll插件实现原声APP的页面上下滑动的效果

将 HTML DOM 结构调整成文档中规定的结构,在外层取wrapper,引用插件之后,在 mounted () 生命周期钩子里面新建一个这个 DOM 引用的实例。

import Bscroll from 'better-scroll'
export default {
  name: 'CityList',
  //生命周期函数 挂载之后执行
  mounted () {
    //引用 wrapper DOM
    this.scroll = new Bscroll(this.$refs.wrapper)
  }
}

alphabet

是一个显示在右的 a-z 字母缩略指引

city-components

兄弟组件间联动,这里没有采用 bus。 而是采用 Alphabet.vue(子组件) 传递给 City.vue(父组件) ,然后再通过 City.vue(父组件) 传递给 List.vue(子组件)。

Alphabet.vue 的 template 的循环展示中绑定 @click ,并在 methods 中使用 $emit 向外( City.vue 父组件 )发送 change 事件。

<template>
  <ul class="list">
    <li class="item"
        v-for="(item, key) of cities"
        :key="key"
        @click="handleLetterClick"
    >
      {{key}}
    </li>
  </ul>
</template>


methods: {
  handleLetterClick (e) {
    this.$emit('change', e.target.innerText)
  }
}

City.vuetemplate 中设置 @change="handleLetterClick" 监听 change 事件。并在 methods 中定义事件 handleLetterClick,传递 letter 参数。

data 中定义数据 letter,传递给 List.vue,在 List.vue 子组件 用props 接收 letter,通过侦听器 watch,侦听 letter 的变化

使用 better-scroll 中的 scrollToElement 方法进行点击跳转效果的实现

watch: {
  letter () {
    if (this.letter) {
      const element = this.$refs[this.letter][0]
      this.scroll.scrollToElement(element)
    }
  }
}

使用 Vuex 实现数据共享

需要实现 city 页面的数据传递给 index 首页。由于 City.vue 和 Home.vue 没有公用父级组件,这样就无法通过一个公用的父级组件进行数据的中转。这里我们使用 Vuex 数据层框架来实现。

安装Vuex,在main.js中注入store,并在src下创建名为'store'的文件夹,state 里放置全局公用数据 city

List.vueSearch.vue组件中包含城市循环输出项的元素标签上定义 @click="handleCityClick(item.name)"

并在相应的methods 中执行 Vuexcommit 方法( 数据共享 ) 和 Vue-routerpush 方法( 页面跳转 )

localStorage

使用 localStorage 实现城市保存的功能,在 store 的 index.js 文件中配置 localStorage

有可能当用户使用隐身模式或禁用localStorage,会导致浏览器报错。所以建议使用 try catch进行优化

let defalutCity = '北京'
try {
  if (localStorage.city) {
    defaultCity = localStorage.city
  }
} catch (e) {}

export default new Vuex.Store({
  state: {
    city: defaultCity
  },
  mutations: {
    changeCity (state, city) {
      state.city = city
      try {
        localStorage.city = city
      } catch (e) {}
    }
  }
})

keep-alive 优化

当查看 network 时候,可以看到从首页到城市选择页切换过程中每次切换都会发送 ajax 请求。所以我们对此进行优化。

App.vue 中给 <router-view/> 外部添加一个 <keep-alive> 标签。其含义是路由的内容被加载过一次之后,就把路由的内容放置到内存中,下一次再使用路由的时候,无需重新加载组件、执行钩子函数。只需要从内存中拿出以前的内容显示就可以了。

activated 生命周期钩子

结合 keep-alive 新增的 activated 生命周期钩子,实现每次点击曾经选中过的城市,不发送ajax,城市选择变化的时候再进行 ajax 请求的优化。

详情页

:to 实现动态路由

使用 tag 将 router-link 标签替换成 li,从而不用修改样式就可以达到之前样式的效果。

然后按照下图所示进行动态路由的实现。即点击相应的列表选择选择动态跳转页面。