Purpose: VuE-CLI built vUE single page application, some specific pages, to achieve forward refresh, backward not refresh, similar to app user experience. Note: The refresh here refers specifically to the triggering of an Ajax request to fetch data from the server when entering the page. No refresh specifically means that when entering this page, ajax requests are not triggered and previously cached data is used to reduce server requests and make the user experience smoother.

Project requirements:

The exploration of any technology comes from the needs of the project. A project I worked on before was a wechat terminal mall, which used the traditional MVC mode and JQ + JS, so I am familiar with the project requirements of the mall. At present, I am learning VUE and practicing a shopping mall. I meet the needs that I have often mentioned before but cannot solve well. Some pages need to be refreshed forward, but not backward. For example, from the mall [home] –> [Details page] –> [Order submission page], every time you open a new page, you need to get new data, but after pressing the back button, you don’t need to get new data, and the scroll bar remains in the previous position. The most common operation is from [home] –> [Details page], and then from [Details page] –> [home page], and so on.

An example is shown below:

Previous experience:

People plant trees so that people can enjoy the shade. Sharing in the tech world has been booming. Encounter problems, we can enjoy to search, to find the footprints of the big guy. In view of the above requirements, I saw a keep-alive sharing vue-Router, which is more suitable for my needs, but it is slightly unsuitable for my project. This share technical points, more suitable for two pages before the jump back. While my page is a jump between multiple routes (2+), return. Helpless, can only go to discover by oneself. However, this technical point gave me a good inspiration, hereby thank the author. @ RoamIn

Implementation idea:

Note: In the demo, the Index page contains three link navigations. Page1 –>page2–>page3. Advance in turn, each advance to a new page need to get data, and press the back button, from page3 back to page2, page2 no longer get new data, but use the previous cache of data. When you return from Page2 to PAGe1, page1 no longer retrieves new data, but uses the previous data. Therefore, page1 and page2 need to be cached, and page3 does not. Think of Page1 as the home page, page2 as the details page, and Page3 as the order submission page. That’s easy to understand.

  • Use keep-alive to cache pages that need to be cached

    • Rewrite router-view in app.vue

      <keep-alive> <router-view v-if="$route.meta.keepAlive"> <! </router-view> </keep-alive> <router-view v-if="! $route.meta.keepAlive"> <! Page3 --> </router-view>Copy the code
    • Add routing meta information to router/index.js and set the page to be cached

      Routes: [{path: '/', name: 'index', Component: index, meta: {keepAlive: false, // This component does not need to cache}}, {path: '/page1', name: 'page1', Component: page1, meta: {keepAlive: true, // This component needs to be cached}}, {path: '/page2', name: 'page2', Component: page2, meta: {keepAlive: true, // This component needs to be cached}}, {path: '/page3', name: 'page3', Component: Page3, meta: {keepAlive: false, // This component does not need to be cached}}]Copy the code
    • The order in which hook functions are executed

      • Do not use keep-alive beforeRouteEnter –> created –> Mounted –> Destroyed

      • Use keep-alive beforeRouteEnter > created > Mounted > activated > deactivated to access the cached page again. Only beforeRouteEnter > Activated > deactivated is triggered. Created and Mounted will no longer execute. We can use different hook functions to do different things. Check that the hook functions activated and deactivated are two important hook functions in VUE after keep-alive is used. Check that the value of activated and deactivated are activated.

  • How to write the page to be cached

    Note: Page1 and page2 in demo, these two pages need to be cached, the idea is the same, page1 as an example, page2 is not repeated. Example file: components/page1. Vue

    • Data initializes a STR string to hold data fetched from the background

    Data () {return {MSG: "I am the first page ", STR: "" // after loading the page, execute the method to get data, insert into this}; }Copy the code
    • Create a method in methods that simulates getting data from the background

    Methods: {getData() {// getData() {this. STR = "I am using a method to load data..." ; }}Copy the code
    • Modify the router/index.js configuration

      • Every time we enter a page, we need to know which page we came from to determine whether we need to fetch data. Take this page1 page as an example, when we know from page2, we can think that the user operated the return key, then the page1 page does not need to obtain new data, using the previous cache of data can be. If it’s coming from another page, we need to get the data.

      • The from argument in the beforeRouteEnter hook function can be used to determine which page is coming from. This argument is executed before the component instance is created, so variables cannot be defined in data. We can define a variable in the route to determine.

      • Add the isBack variable to the meta of router/index.js. Default is false

      { path: '/page1', name: 'page1', component: page1, meta: { keepAlive: IsBack :false,}}, {path: '/page2', name: 'page2', Component: page2, meta: {keepAlive: true, // This component needs to be cached isBack:false, // to determine which page was last}},Copy the code
    • BeforeRouteEnter determines which page it came from

      • If the route is from page2, it indicates that the current page does not need to refresh to obtain new data, and can directly use the previously cached data

      BeforeRouteEnter (to, from, next) {// Route navigation hook, cannot get component instance 'this', So cannot be defined in the data variables (except using the vm) / / https://router.vuejs.org/zh-cn/advanced/navigation-guards.html / / so, using the routing information for the meta field set variables, Easy to get at all locations. This is why defined in meta isBack / / reference https://router.vuejs.org/zh-cn/advanced/meta.html if (from the name = = 'page2') { to.meta.isBack=true; } next();} next();} next();} next(); },Copy the code
    • Check that the value of Activated executes the getData method to get the data

      • Because this page needs to be cached. The created and Mounted methods are executed only on first entry and not on second entry. Activated executes every time it enters, so it fetches data in this hook function.

        activated() { if(! This.$route.meta. IsBack){this.getData() {this.getData(); $route. Meta. IsBack =false} $route. Meta.Copy the code
    • Is that all?

      • And when that’s done, and you execute it, it looks like it’s ok. The first time I go to Page1, I get new data, and when I return from Page2, I don’t get new data anymore, I use the cached data. But there is also a problem. When the user enters page2 from Page1, for some reason, the page in Page2 is manually refreshed. When I return to page1, I find that the cached data is missing and has not been retrieved. So we need to add another criterion, when the user manually refresh the page, and then return to retrieve the data.

      • How do you add this condition to determine if the user has refreshed the page? As we know, when keep-alive is used, the created hook function is only triggered on the first entry and is not executed on the second entry. When the user refreshes the page, the hook function is executed again, so we can use this trick to do some writing.

      • The variable isFirstEnter is defined in data to determine whether the page was entered for the first time or whether the page was refreshed. The default is false

        Data () {return {MSG: "isFirstEnter ", STR: "", // isFirstEnter:false // isFirstEnter:false}; },Copy the code
      • Created sets isFirstEnter to true to indicate that the page has been entered or refreshed for the first time

        created() { this.isFirstEnter=true; // This hook function is executed only after the first entry or refresh of the page. // This hook function is not executed after keep-alive (2+ times).Copy the code
      • Add the judgment condition in activated

        activated() { if(! This $route. The meta. IsBack | | this. IsFirstEnter) {/ / if isBack is false, show that need to get new data, otherwise no longer request, directly use the data/cache/if isFirstEnter is true, This.str = "this.str (); this.getData(); } this.$route.meta. IsBack =false;} This. IsFirstEnter =false; },Copy the code
      • That should do it

  • There is no need to write cached pages

    Note: Page3 in demo, this page does not need to cache, how to write how to write, do not need to do special Settings.

Other Settings:

With keep-alive, there may be a slight problem: the second page may inherit the scrollbar height of the first page. (encountered in my project) for example: after scrolling down page1, enter page2, then page2 scroll bar may be the previous height, may not be at the top.

  • Each time you leave the record scroll bar height, re-enter according to the project needs to restore the previous height, or set the top.

  • Router /index.js: router/index.js: router/index.js

      mode: 'history',
      scrollBehavior(to, from, savedPosition) {
          if (savedPosition) {
              return savedPosition
          } else {
              return {
                  x: 0,
                  y: 0
              }
          }
      }Copy the code

Question:

In this demo exercise, I printed the sequence of hook functions and found a problem (I have a very simple understanding of hook functions) : When entering Page2 from Page1, the beforeRouteEnter and Created methods of Page2 are executed, and then the deactivated method of Page1 is executed. So I put these two initialization Settings in Activated instead of deactivated

    this.$route.meta.isBack=false;
    this.isFirstEnter=false;Copy the code

Conclusion:

In order to solve this forward refresh backward not refresh problem, let me a whole week of distress, think of a lot of methods, but also failed to solve. Finally, after many tests and comprehensive experience of various leaders, I came to the conclusion of this relatively ‘low’ method. At present, I am also vue white, also exploring forward, if this method can solve the problem you meet, I am very happy. If you think it’s really low, gently spray. Demo is on GitHub below, welcome star. Comments and suggestions are also welcome. Thank you

GitHub