你真的了解keep-alive吗?

了解之前你先从动态组件说起~

component

有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里:
在这里插入图片描述
上述内容可以通过 Vue 的 <component> 元素加一个特殊的 is attribute 来实现:

<template>
  <div class="hello">
    <button @click="handleAbout">About</button>
    <button @click="handleHome">Home</button>
    <keep-alive>
      <component :is="currentTab"></component>
    </keep-alive>
  </div>
</template>

<script>
import About from "./about";
import Home from "./home";
export default {
  name: "HelloWorld",
  components: {
    About,
    Home
  },
  props: {
    msg: String
  },
  data() {
    return {
      currentTab: 'About'
    };
  },
  methods: {
    handleAbout () {
      this.currentTab = 'About'
    },
    handleHome () {
      this.currentTab = 'Home'
    }
  }
};
</script>

component默认每次都会销毁和重建,那么为了性能优化,我们可以使用keep-alive缓存,缓存还有一些其他的作用,比如切换时保留滚动位置,切换时保留页面输入的内容,等等等

keep-alive

将keep-alive包裹你的component

<keep-alive>
  <component :is="currentTab"></component>
</keep-alive>

这样就可以保留tab之间用户的输入的信息了,但是并不能保留滚动的位置,不信你看下面代码,一个tab里面不需要滚动,而另外一个tab需要滚动。

about.vue

<template>
  <div>
    about
  </div>
</template>

<script>
export default {
  
}
</script>

<style lang="">
  
</style>

home.vue

<template>
  <div class="wrapper">
    <ul>
      <li v-for="(item, index) in 50" :key="index">
        {{item}}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  
}
</script>

<style>
  .wrapper {
    height: 200px;
    overflow: auto;
  }
</style>

写法上没啥问题,但就是每次切换的时候不能保留滚动位置,怎么办???

记录滚动位置

解决办法

不使用component和keep-alive组件,使用v-show代替

<home v-show="currentTab==='Home'"></home>
<about v-show="currentTab==='About'"></about>

这里有个需要注意的地方就是,需要把滚动设置到组件里面去,而不是他们共同的父元素,因为他们不能共用滚动,共用滚动的话滚动位置又乱了,所以不要为了偷懒而设置在在父元素中,比如下面代码:

<div class="container">
  <home v-show="currentTab==='Home'"></home>
  <about v-show="currentTab==='About'"></about>
</div>
    
.container {
  height: 200px;
  overflow: auto;
}

其实很多人认为keep-alive能保留滚动位置,也许是你在配合vue-router的时候这样使用过,看下面代码

  <keep-alive>
    <router-view></router-view>
  </keep-alive>

其实keep-alive只能通过点击浏览器自带的返回按钮才能记录位置,如果你需要在A切换到B再切换到A,通过JS的路由跳转是不能记录位置的。来个图片吧,这样直观一点:
在这里插入图片描述

通常我们有这样的需求,商品列表跳转的商品详情页,然后返回到商品列表,这个时候是要保留滚动位置的,既然Keep-alive做不到,我们可以使用其他方法。

通过在页面中记录滚动位置,当组件再次被激活时,重新设置一下页面的滚动,代码如下:

export default {
  // 1.绑定滚动事件
  mounted () {
    window.addEventListener('scroll', this.handleScroll)
  },
  
  // 3.当再次进入(前进或者后退)时,只触发activated(注:只有在keep-alive加载时调用)
  activated () {
    if (this.scroll > 0) {
      this.$nextTick(() => {
        document.documentElement.scrollTop = this.scroll
        window.addEventListener('scroll', this.handleScroll)
      })
    }
  },
  
  // 4.deactivated 页面退出时关闭事件 防止其他页面出现问题
  deactivated () {
    window.removeEventListener('scroll', this.handleScroll)
  },
  
  methods: {
  	// 2.滚动时候保留位置
    handleScroll () {
      this.scroll = document.documentElement.scrollTop
    }
  }
};
</script>

有时候我们的页面需要keep-alive保留状态,有些时候我们的页面不需要keep-alive保留状态,这个时候可以使用属性include和exclude属性处理。

include 和 exclude 属性允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示:

<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>

更多内容请参考官方文档:链接

总结

  1. keep-alive可以保留页面的状态,比如表单输入
  2. keep-alive可以保留触发返回键的滚动位置
  3. keep-alive不能保留动态组件的滚动位置,需要使用v-show代替
  4. keep-alive不能保留通过路由切换页面时候的滚动位置,需要在页面组件中单独处理
  5. keep-alive可以通过exclude排除不需要保留状态的页面
  6. 使用了keep-alive才会触发的生命周期是activated 和 deactivated
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章