Vue—去哪儿笔记

项目代码

一.项目环境准备

Vue项目运行在NodeJ环境中,npm为NodeJs的包管理工具,命令行 node -v ,npm -v 中查看系统是否已经安装Node环境。如果还没安装环境,就前往 Node官网下载吧。
接着安装 vue-cli 脚手架工具,vue-cli能够帮助我们快速构建Vue项目。安装脚手架:npm install --global vue-cli,创建vue项目: vue init webpack my-project,npm install 运行项目:   npm run dev。

二.项目代码结构介绍

下面来介绍下vue项目目录

README.md  项目说明文件

package.json  项目开发需要的第三方依赖包

LICENSE 开源协议的说明

index.html  项目默认首页文件

.prostcssrc.js 

.gitignore 

.eslintrc.js  配置代码规范

.eslintignore  文件不受代码规范限制

.editorconfig  编辑器语法

.bablelrc 通过bable语法解析,编译能够执行的代码

 static  静态资源  存放静态图片 mock模拟数据

 src 整个项目的源代码

       main.js项目入口文件

       App.vue项目原始根组件

       router/index.js 整个项目的路由配置

       components项目需要的组件

       assets 项目需要的图片

node_modules 项目依赖的第三方node包

config 项目配置文件

       index.js基础配置信息

       dev.env.js 开发环境配置信息

       prod.env.js 线上生产环境配置信息

build  项目打包webpack配置内容

三. 单文件组件与Vue中的路由

单文件组件.vue 是由组件模板<template></template>,组件逻辑结构<script></script>,组件样式<style></style> 三部分构成。                                                

路由就是根据网址的不同,返回不同的内容给用户。路由配置一般都在router目录下的index.js下啦。说到路由,不妨提下Vue中的页面路由:原生中可以通过<a>标签和 js的href属性进行页面的跳转,Vue 同样也有两种方法进行路由,分别是:<router-link to=' ' > 和 this.$router.push('/') 。

路由后拖动,多个界面之间会互相影响。在路由配置页index.js添加以下代码即可:

scrollBehavior (to, from, savedPosition) {
      return { x: 0, y: 0 }
    }复制代码

四.多页面应用和单页面应用的区别

Vue是单页面应用,那单页面应用和多页面运用又有什么区别呢?

单页面应用(SinglePage Web Application,SPA)

页面跳转 ——> JS渲染

优点:页面切换快 (js会感知url的变化,通过js感知到url的变化,js 动态地把当前页面的内容清楚掉,再把下一个页面的内容挂载到页面上。这时候,路由不是后端来做,而是前端来做。)

缺点:首屏时间稍慢 (首屏展示出来需要请求一次html和发送一个JS的请求,两个请求都回来了,首屏才会被展示出来),SEO差。

vue中还提供了服务器端等技术,通过这些技术,可以完美地解决单页面应用的这些问题。

多页面应用(MultiPage Application,MPA)

 指的是页面跳转—— >返回HTML

 优点:首屏时间快,SEO效果好(搜素引擎优化效果好,搜索引擎在做网页排名的时候需要知道网页的内容,根据网页内容给予权重从而进行排名。搜索引擎可以识别html中的内容的)。

 缺点:页面切换慢 (每次跳转页面的时候都需要发送http请求,网络比较慢的时候,在页面来回跳转的时候,会出现明显的卡顿情况)。

五.项目代码初始化

在正式编写代码之前,我们先进行一些代码的初始化。

 a.在默认首页文件index.html 完善<meta>标签的viewport配置

<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
复制代码

这样的话,要求用户对于移动设备的放大缩小都是无效的,并且页面的比例始终是1:1。

b. 在项目入口文件main.js中引入重置页面样式表reset.css

import './assets/styles/reset.css'
复制代码

c.引入一像素边框文件  

  (1像素边框问题)有的手机屏幕分辨率比较高,为2倍屏或者3倍屏。如果在页面上写     border:1px solid  black;这时候写的是1px,指的是css像素。但是在2倍屏上1px css像素对应的不是1个物理高度的像素,而是两个物理高度的像素。

d. 安装第三方依赖库fastclick

    (移动端有300毫秒点击延迟的问题) 移动端开发中,在某些机型上,某些浏览器上,当使用click 点击事件的时候,click 事件会延迟300 毫秒后才执行。

 安装fastclick 库  (--save表示无论在开发环境或者生产环境中都使用 fastclick)

npm install fastclick --save复制代码

引入

import fastClick from 'fastclick'
复制代码

使用

fastClick.attach(document.body)
复制代码

e. iconfont管理

去iconfont官网注册登录创建自己的项目,选择你要的图标加到购物车,都选择完后,将购物车的图标都加到项目中,然后下载到本地,选择字体文件和iconfont.css添加到Vue项目中,并在main.js文件中import。然后就可以使用啦,类名为“iconfont" ,&#xe632;为图标对应的进制代码,官网里可以查看。(不要忘记修改iconfont.css里的字体文件的路径)

<span class="iconfont">&#xe632;</span>
复制代码

e.项目中使用stylus

安装依赖包  npm install stylus --save

                   npm install stylus-loader --save

<style lang="stylus" scoped>

使用stylus ,scoped 局部化样式 表示样式只对当前组件起作用,不影响其他组件。

项目中我们使用rem做自适应布局,rem是根据html的font-size大小来变化,html font-size  = 50px =1rem (为方便计算,html font-size可以根据自己设置)

f.代码优化,定义样式变量

新建一个varible.styl 文件,定义样式变量

$bgColor = #00bcd4
复制代码

在组件样式中引入文件(<style>样式中引入import前要加@)

@import '../../../../assets/styles/varibles.styl'复制代码

此时文件路径很长,容易搞错,@代表src目录 ,所以我们可以将路径修改成:(记得在@前加~)

@import '~@/assets/styles/varibles.styl'
复制代码

在stylus中使用

background: $bgColor复制代码

另外,有的目录我们经常使用到,比如stylus目录,那有什么办法给目录起个别名呢?让我们更方便地访问。(就好像src目录的别名是@ 一样)

解决办法:打开build目录下的 webpack.base.conf.js 文件,找到 alias 别名项

'@': resolve('src'),
复制代码

根据src 的配置,可以配置你想要的路径的别名,如

'styles': resolve('src/assets/styles'),
复制代码

那么我们就可以更改上面复杂的路径了

  @import '~styles/varibles.styl'
复制代码

(提示:当我更改了webpack配置项的时候,记得重启服务器,ctr c    npm run start)

六.码云的运用

我的项目放在码云上面啦,当然更推荐大家使用github~

首先在码云上创建项目,具体的这里就不多说啦。然后 git clone adress 下载码云仓库代码到本地(SSH代码协议进行克隆)。

创建git分支。在真正的企业级别的开发中,我们每开发一个新的功能,都要创建一个git的分支,在分支上进行代码的开发。当代码开发完成之后,把分支的代码合并到master主分支上。


然后在git bansh终端运行 git pull ,就会将我们创建的 index-swiper 分支 拉到本地来。

在运行 git checkout index-swiper  ,这时候本地所在的分支就切换到 index-swiper 分支了。

将代码保存到本地仓库,并提交到线上仓库。

git add .     git commit -m ' '   git push

这个时候本地的index-swiper分支就提交到线上index-swiper分支了。

然后再将index-swiper分支上的内容合并到master分支上。

git checkout master //先切换到master分支上

git merge origin/index-swiper //然后把线上的index-swiper分支上新增的内容合并到本地

的 master分支上。

git push //将本地的master分支提交到线上。

master分支放的上整个项目所有功能的最新代码。index-swiper放的是开发的具体功能的开发完成时的代码。所以在实际企业级新项目开发中,我们会自己开发一个分支,测试没有问题后,再把这个分支的代码合并到主分支上。

七.AJAX获取数据

 axios第三方模块,可以实现跨平台的数据请求。axios十分强大,在服务器端axios可以帮助你发送xhr的请求;在node服务器上,可以帮助你发送http请求。

安装axios

npm install axios --save复制代码

引入

import axios from 'axios'
复制代码

使用mock模拟数据

 axios.get('/static/mock/index.json')

我们现在用的都是本地模拟接口的地址,加入代码要上线,在上线之前,需要把这块地址重新替换成  axios.get('/api/index.json') 这种格式,上线之前去改代码,是有风险的。不建议大家这么做。那怎么才能解决这个问题呢?我们想,在开发环境中,我们依然这么写我们的路径 axios.get('/api/index.json'),如果有一个转发机制,可任意帮助我们把 对api下所有json文件的请求 转发到本地的mock文件夹下。vue提供了proxy的代理功能,就可以实现我们的构想啦。

打开config目录下,在index.js文件,在开发环境里,官方提供了 proxyTable 这个配置项,在这里做些配置,就可以我们刚才的想法。

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

当我们去请求api这个目录的时候,我们希望它把请求转发到当前这台服务器的端口号上,然后对路径进行替换。 如何替换? 一旦你请求的地址是以 api 开头的,就替换请求到本地的static路径下的mock这个文件夹下。当你去访问api下面的index.json的时候,在开发环境中,vue-cli脚手架工具会自动帮助你把api 替换成/static/mock。

(提示:当我更改了webpack配置项的时候,记得重启服务器,ctr c npm run start)

八.轮播借助第三方的轮播插件 vue-awesome-swiper

安装(npm)

npm install vue-awesome-swiper@2.6.7 --save复制代码

使用(全局引入)

import VueAwesomeSwiper from 'vue-awesome-swiper'复制代码
import 'swiper/dist/css/swiper.css'复制代码
Vue.use(VueAwesomeSwiper)复制代码

在template中使用可以查看官网文档。

<!-- The ref attr used to find the swiper instance -->
<template>
  <swiper :options="swiperOption" ref="mySwiper" @someSwiperEvent="callback">
    <!-- slides -->
    <swiper-slide>I'm Slide 1</swiper-slide>
    <swiper-slide>I'm Slide 2</swiper-slide>
    <swiper-slide>I'm Slide 3</swiper-slide>
    <swiper-slide>I'm Slide 4</swiper-slide>
    <swiper-slide>I'm Slide 5</swiper-slide>
    <swiper-slide>I'm Slide 6</swiper-slide>
    <swiper-slide>I'm Slide 7</swiper-slide>
    <!-- Optional controls -->
    <div class="swiper-pagination"  slot="pagination"></div>
    <div class="swiper-button-prev" slot="button-prev"></div>
    <div class="swiper-button-next" slot="button-next"></div>
    <div class="swiper-scrollbar"   slot="scrollbar"></div>
  </swiper>
</template>

<script>
  export default {
    name: 'carrousel',
    data() {
      return {
        swiperOption: {
          // some swiper options/callbacks
          // 所有的参数同 swiper 官方 api 参数
          // ...
        }
      }
    },
    computed: {
      swiper() {
        return this.$refs.mySwiper.swiper
      }
    },
    mounted() {
      // current swiper instance
      // 然后你就可以使用当前上下文内的swiper对象去做你想做的事了
      console.log('this is current swiper instance object', this.swiper)
      this.swiper.slideTo(3, 1000, false)
    }
  }
</script>复制代码


当轮播图ajax数据获取完成后,swiperList变成真正的数据项。再传给HomeSwiper组件的时候,组件才获取到数据,然后重新渲染出来。因为swiper的初始化创建是根据空数组创建的,所以默认显示的是所有轮播图的最后一项。

解决办法:swiper的初次创建让完整的数据来创建,而不是由空数组创建。只需 添加v-if="list.length" ,当传递过来的list是空数组的时候,v-if为false,所以swiper不会被创建。只有真正的数据过来的时候,swiper才会被创建。

其实这样写是不优雅,模板代码尽量不要写逻辑。所以可以添加一个计算属性

computed: {
    showSwiper () {
      return this.list.length
    }
  }
复制代码

//一些css需要注意的点

防止轮播图加载过程中下方内容的抖动,可以给<swiper>包裹一层div,并且设置样式

宽高占比

.wrapper
    overflow: hidden
    width: 100%
    height: 0
    padding-bottom: 31.25%
    background: #eee
复制代码

样式穿透,wrapper样式下的所有swiper-pagination-bullet-active样式 不受 scoped 限制。

.wrapper >>> .swiper-pagination-bullet-active
    background: red !important复制代码

当文字很多,空间又不足,显示省略号

ellipsis()
  overflow: hidden
  white-space: nowrap
  text-overflow: ellipsis复制代码

一像素边框颜色不明显

.border-topbottom
    &:before
      border-color: #ccc
    &:after
      border-color: #ccc
复制代码

.border-topbottom 这个类的 bofore 和 after 伪元素的border-color 都设置为 #ccc,而通过控制这个颜色,就可以控制页面上一像素边框的颜色。

渐变

background-image: linear-gradient(top, rgba(0,0,0,0), rgba(0,0,0,8))复制代码

九.Better-scroll的使用

better-scroll 安装

npm install better-scroll --save复制代码

想要使用 better-scroll 元素需要符合如下dom结构

<div class="wrapper">
  <ul class="content">
    <li>...</li>
    <li>...</li>
    ...
  </ul>
  <!-- you can put some other DOMs here, it won't affect the scrolling -->
</div>复制代码

使用

import BScroll from 'better-scroll'
const wrapper = document.querySelector('.wrapper')
const scroll = new BScroll(wrapper)复制代码

十.兄弟组件联动

兄弟组件是非父子组件,非父子组件传值可以使用 bus总线 形式进行传值。

但是我们这个兄弟组件比较简单,当我们处理兄弟组件的时候,可以让 Alphabet组件的数据传递给City组件,City组件再转发给List组件。


点击的联动(点击城市列表页的右侧字母表,左侧的列表会自动地滚动到页面的显示区域之中)点击触发事件右侧字母子组件,获取字母(e.target.innerText),并通过$emit方法触发change事件 将字符传给City父组件,父组件获取到字母后,又通过属性传值给城市列表子组件,城市列表子组件通过监听字母地变化,获取字母的dom节点,通过better-scroll的scrollToElement实现自动地滚动。

滚动的联动(滑动城市列表页的右侧字母表,左侧的列表会自动地滚动到页面的显示区域之中) 定义一个标识位,手指触摸的时候标识位位true,结束滑动的时候标识位为false。只有再标识位为true的情况下,才去做move事件的处理。我们得知道往下滑动的时候,你现在所在的位置是第几个字母。思路是这样的:首先获得首字母A距离顶部的高度,再获得滑动时当前手指距离顶部的高度,做差值就能算出当前手指位置与首字母A的距离,再除以每个字母的高度,就能知道当前滑动的是第几个字母了。然后去取对应的字母,触发change事件给外部,剩余同上。

十一.列表切换性能优化

当我们手指在字母表上滑动的时候,就会触发handleTouchMove()事件,但是这样写性能会比较差。

handleTouchMove (e) {
      if(this.touchStatus) {
         const startY = this.$refs['A'][0].offsetTop
         const touchY = e.touches[0].clientY - 79
         const index = Math.floor((touchY - startY) /20)
         if(index >= 0 && index < this.letters.length ) { 
         this.$emit('change', this.letters[index])
        }
     }
 }
复制代码

首先,A的offsetTop值是固定的,而我们需要每次执行这个方法的时候(滑动字母),都会去运算一次 A到顶部的高度。为了提高性能,我们可以用updated 生命周期钩子,当页面数据被更新的时候,同时页面完成了自己的渲染之后,updated这个钩子就会执行。

 updated () {
     this.startY = this.$refs['A'][0].offsetTop
  }
复制代码

当初次渲染字母组件的时候,是用空对象cities渲染的,当ajax获取到数据之后,cities的值才发生变化,字母组件才被渲染出来。当网字母组件传的数据发生变化的时候,字母组件就会重新渲染。当字母组件重新渲染之后,updated这个生命周期钩子就会被执行,这个时候字母组件就展示了字母的所有内容,这个时候去获取A到顶部的高度。

函数节流

当我们鼠标或者手指在字母表来回移动的时候,touchmove执行的频率是非常高的。我们可以通过节流限制函数执行的频率。

 handleTouchMove (e) {
      if(this.touchStatus) {
        if(this.timer) {
         clearTimeout(this.timer)
        }
       this.timer = setTimeout(() => {
         const touchY = e.touches[0].clientY - 79
         const index = Math.floor((touchY - this.startY) /20)
         if(index >= 0 && index < this.letters.length ) { 
         this.$emit('change', this.letters[index])
       }
      }, 16)
    }
  }
复制代码

如果你已经正在滑动,让其延迟16毫秒再去执行,假设在16毫秒之间,又做了手指的滚动,那么就会把上一次要做的操作清除掉,重新执行这次要执行的事情。

十二.使用Vuex实现数据共享(首页和城市选择页的数据共享)

Home.vue与City.vue 没有公用的父级组件,这样的话城市页面和首页进行数据传递就没办法通过一个父级的组件进行数据的中转。那该如何进行这两个页面的数据通信呢?这里我们可以使用BUS总线的方法,但是依然比较麻烦。Vue的官方提供了一种工具,叫做vuex。这是官方推荐的一个数据框架。在vue的大型项目开发之中,vue只能承担视图层的主要内容,当我们涉及到大量数据之间传递的·时候,往往需要数据框架进行辅助。

如何使用vuex 数据层框架


Vuex指的是整个项目虚线部分的内容。那Vuex是什么呢,当我们的项目中各个页面或者多个组件之间进行复杂的数据传值很困难的时候,如果能够把公用的数据放到一个公共的存储空间进行存储,然后某一个组件改变了公共的数据,其他组件就能感知到。Vuex的设计理念就是这样的。

上图中,Vuex虚线部分就是一个公用数据存储区域,可以理解为是一个仓库。仓库中有一个State区域,所有的公用数据都存放在State之中,那组件如果想用一个公用的数据,直接去调用State 就可以了。有的时候我们想改变State里的数据,(不能让组件直接去改变数据)流程是这样的:如果有异步操作,就把异步操作放在Actions里,或者一些比较复杂的批量的同步操作也可以放到Actions里。组件先去调用Actions,Actions紧接着去调用Mutations,Mutations里面放的是一个一个同步地对State的修改。当然这也不是绝对的,有的时候可以让组件直接去调用Mutations去修改State里面的数据。需要注意的是,当组件调用Actions的时候,调用的是一个Dispatch()方法来操作Actions,Actions或者组件调用Mutations的时候需要用到Commit()方法。

安装vuex

npm install vuex --save复制代码

直接在main.js中引入vuex使用vuex,这样做其实不太好,vuex要做的文件夹其实是比较复杂的。所以,单独在src目录下创建一个store文件夹,然后再store文件夹建立一个index.js的文件。

vuex是一个插件,vue里面使用插件都是通过Vue.use( )使用的。

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store ({
	state: {
		city: '北京'
	}
})复制代码

然后在入口文件main.js中引用

import store from './store'
复制代码

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})
复制代码

这样就可以在各个组件中使用啦

<div>
   {{this.$store.state.city}}
</div>复制代码


现在我们想通过点击“热门城市”来改变“当前城市”,就是公用城市也要跟着变化,那该怎么做呢?(改变state)

首先需要调用Actions然后再去调用Mutations。

在list组件中点击热门城市改变city的时候,通过dispatch()方法调用 actions,传递两个参数,分别是'changeCity' 这个actions和 要改变的city

handleCityClick(city) {
      this.$store.dispatch('changeCity',city)
    }
复制代码

在store中创建一个actions对象,接受到dispatch过来的一个‘changeCity’方法,接受两个参数分别是上写文ctx和传递过来的数据city。actions要通过commit来调用mutations,mutations来改变数据。

export default new Vuex.Store ({
	state: {
		city: '北京'
	},
	actions: {
		changeCity (ctx,city) {
			ctx.commit('changeCity',city)
		}
	},
	mutations: {
		changeCity (state,city) {
          state.city = city
		}

	}
})复制代码

以上步骤改变State的过程里并没有任何的异步操作,也不是批量操作,所以这个时候组件没必要去调用Actions ,组件可以直接去调用Mutations。

 handleCityClick(city) {
      this.$store.commit('changeCity',city)
    }
复制代码

export default new Vuex.Store ({
	state: {
		city: '北京'
	},
	mutations: {
		changeCity (state,city) {
          state.city = city
		}

	}
})复制代码

十三.Vuex的高级使用及localStorage

html5中引入了一个新的API localStorage ,可以帮助我们实现cookie的功能,做到本地存储。在这里我们用localStorage完成城市保存的功能。

需要注意的是:当你使用localStorage,建议就在外层包裹一个try catch。因为在某些浏览器,如果用户关闭了本地存储这样的功能,或者选择隐身模式,你使用localStorge有可能会导致浏览器直接抛出异常,导致代码无法运行。

 try{
       localStorage.city = city
    } catch (e) {}
复制代码

let defaultCity = '上海'
try {
     if(localStorage.city) { 
     defaultCity = localStorage.city
	}
} catch (e) {}
复制代码

这样写代码,就比较规范了。

此时store下的index.js变得复杂起来了。为了易读性和可维护性,我们可以对代码进行拆分。怎么拆分这里就不多说啦。



有的时候因为城市名的长度,首页header组件样式会被破坏。

.header-right
      width: 1.24rem
      float: right
      text-align: center
      color: #fff
      .arrow-icon
        margin-left: -.04rem
        font-size: .24rem复制代码

这里我们设置一个左右的padding,将width改为min-width就可以啦

.header-right
      min-width: 1.04rem
      padding: 0 .1rem
      float: right
      text-align: center
      color: #fff
      .arrow-icon
        margin-left: .04rem
        font-size: .24rem复制代码



Vuex的高级用法:(代码优化)

 {{this.$store.state.city}}
复制代码

这时候我们使用公用数据,需要通过 {{this.$store.state.city}} 这样一长串才能获取到我们要的city数据。

Vuex中提供了一个比较高级的API,

首先我们引入mapState

import { mapState } from 'vuex'复制代码

之后我们来一个计算属性

computed: {
    ...mapState(['city'])
  }
复制代码

...mapState(['city'])  把vuex里面的city共用数据映射到该组件的名叫city的computed计算属性里。做好映射后,就可以 用 {{this.city}} 来获取city数据了。

传递内容可以是个数组,也可以是个对象。

 computed: {
    ...mapState({
      currentCity: 'city'
    })
  }
复制代码

映射后的计算属性名字就叫 currentCity 啦。所以我们通过 {{this.currentCity}}来获取数据。

 handleCityClick(city) {
      this.$store.commit('changeCity',city)
      this.$router.push('/')
    }
复制代码

当我们点击城市按钮的时候,会通过commit方法 派发一个mutations,Vuex同样提供了一个简便的API mapMutations

同样使用引入mapMutations

methods: {
    handleCityClick(city) {
      this.changeCity(city)
      this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
  },
复制代码

有一个mutations叫做changeCity,然后把这个mutations映射到组件里的一个叫做changeCity方法里,我们调用mutations就可以直接调用cahngeCity()这个方法啦。


Vuex有几个核心的概念,state存放公用数据,actions用于写些异步方法或者同步批量操作,mutations用于写些同步地对数据地改变。Vuex中还提供了 getters API,他的作用有点类似于组件中的computed计算属性的作用,当我们需要根据 state 里面的数据算出一些新的数据就可以借助 getter 来提供新的数据,避免数据的冗余。

getters: {
     doubleCity (state) {
           return state.city + ' ' + state.city 
     }
}复制代码

computed: {
    ...mapGetters(['doubleCity'])
  }复制代码

当我们遇到一个非常复杂的业务场景,比如说我们在管理后台系统的时候,经常会有很多公用的数据在vuex里面进行存储,这样mutations文件会变得非常庞,难以维护。这个时候可以借助module对一个复杂的state,mutations,actions进行拆分。创建store的时候可以通过module来对store的创建。

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态复制代码

这样做,A模块只要存储和A模块相关的数据和数据的操作就可以了,然后在创建store时候再对各个模块的数据进行整合。

十四. 使用keep-alive优化网页性能


我们打开chrome 下的Network 切换到XHR,会发现我们切换一次页面就会请求一次数据,原因是每次路由切换到一个组件的时候,这个组件就会被重新渲染,它的mounted()钩子就会被执行,那么ajax数据就会重新获取。这样每次切路由都重新获取一次数据会大大的降低性能。

我们只要在App.vue这个项目根组件的路由 <router-view/> 外包裹<keep-alive>

<keep-alive>
    <router-view/>
 </keep-alive>
复制代码

这样,路由的内容被加载过一次后就把路由的内容放到内存中,下一次再进这个路由的时候,不需要重新渲染这个组件,只需要去取内存中内容显示就可以啦。

这个时候其实我们代码还存在一些问题,当我们选择城市后,再路由到首页后,首页的内容是不会变化的。

我们可以通过vuex,将ajax请求路径为相应城市

 axios.get('/static/mock/index.json?city=' + this.city)复制代码

但是,因为我App.vue路由中添加了keep-alive 后,就算选择了不同的城市,页面也不会被重新渲染了。

那我们如何去改变缓存里的数据呢?方法1:当我们使用keep-alive的时候,组件里会多出一个生命周期函数activated()(keep-alive 组件激活时调用activated),当页面重新被显示的时候执行activated,在activad()里判断选择的城市是否被改变,改变了就重新发送ajax请求。

方法2:加个exclude,这个组将就不会进行缓存了。

<keep-alive exclude="Detail">
      <router-view/>
</keep-alive>
复制代码

十五.动态路由

path: '/detail/:id'

vue中路径后加 :id 为动态路由

十六.对全局事件的解绑

在上一节中,我们对window做了事件的绑定

activated () {
    window.addEventListener('scroll', this.handleSroll)
  }
复制代码

如果,我们在某个组件的标签上绑定了某个事件,只作用于这个组件,不会对外部组件产生任何的影响。但是,在这个组件里写的是对window这个全局事件的绑定,在该页面关闭时就需要对其解绑。那如何解绑呢?当我i们对这个组件用了keep-alive的时候,组件会提供 activated 生命周期钩子,在每次页面展示的时候被执行。与之对应,还提供了一个叫 deactivated生命周期钩子,在页面即将被隐藏,或者即将被替换成其他页面的时候,deactivated就会被执行。

deactivated () {
    window.removeEventListener('scroll', this.handleSroll)
  }
复制代码

也就是,页面展示的时候绑定scroll事件,页面被隐藏的时候,对scroll事件解绑。

十七.使用递归组件实现详情页列表

每个组件的  name  的作用是什么?

1.当我们做递归组件的时候,会用到name

<template>
  <div>
     <detail-list></detail-list>
  </div>
</template>

export default{
	name: 'DetailList'
}复制代码

2.当我们在也页面上想对某个页面取消缓存的时候

<keep-alive exclude="Detail">
      <router-view/>
</keep-alive>复制代码

3.vue-devtool调试


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值