From list to detail, it’s not as easy as you think
preface
This article assumes that we use vue+vuex+ vuE-router to start the discussion. The React bucket should be similar.
In daily front-end research and development, we often encounter such scenarios: for example, from the list of goods to enter the details of goods, from the list of orders to enter the details of orders. Let’s look at a demo~
Seems to be still smooth smooth, with the client effect is closer to ~
The text start
Now, a lot of you might say, well, that’s easy. Just use vue-Router + Transition.
<template>
<transition name="custom-classes-transition"
:enter-active-class="`animated ${transitionEnter}`"
:leave-active-class="`animated ${transitionLeave}`">
<router-view/>
</transition>
</template>
<script>
export default {
data: () => ({
transitionEnter: '',
transitionLeave: ''
}),
watch: {
'$route' (to, from) {
const toDepth = to.path.split('/').length
const fromDepth = from.path.split('/').length
if (toDepth < fromDepth) {
this.transitionEnter = 'slideInLeft'
this.transitionLeave = 'slideOutRight'
} else {
this.transitionEnter = 'slideInRight'
this.transitionLeave = 'slideOutLeft'
}
}
}
}
</script>
Copy the code
As shown above, the slide animation using animated. The CSS (https://daneden.github.io/animate.css/)
<style lang='scss'>
$use-slideInLeft: true;
$use-slideInRight: true;
$use-slideOutLeft: true;
$use-slideOutRight: true;
import "node_modules/animate-sass/animate";
.animated {
top: 0;
width: 100%;
height: 100%;
animation-duration: calc(300ms);
}
.slideOutRight, .slideOutLeft {
position: fixed;
}
</style>
Copy the code
Then define the path rules of the router and name it in a restful way.
export default new Router({
Routes: [{// Product list
path: '/',
name: 'auctionroom',
component: () => import('app/auction-room/room/app.vue')
}, {// Commodity details
path: ':activityId',
name: 'auctionroom-item',
component: () => import('app/auction-room/item/app.vue')
}]
})
Copy the code
Is it really that easy to fulfill requirements?
Tombstone elements and route guards
In fact, we didn’t get the details until we went to the details page! An Created hook in the lifecycle of a VUE component instance is typically selected to retrieve the corresponding back-end data interface.
This process is parallel to the transition animation, where the right side of the screen is clicked before the data is retrieved. As you might expect, we try to make the data source behave like it would in the real world, with network latency and so on.
When this happens, you actually need to place a tombstone entry in the corresponding position, and when the data is retrieved the tombstone entry will be replaced by the actual content. The reason for this design was that we wanted the tombstone element to have a nice transition before being replaced by actual data, rather than a stiff or disorienting effect.
First of all, the ugly tombstone, the actual situation of tombstone elements should be designed, in many news clients today’s headlines see ~
A more common approach than this is to get the data before the navigation is complete, using the Router’s beforeRouteEnter hook. While this approach is great, there are also potential problems:
-
While retrieving data, the user will stay in the current interface, so it is recommended that some progress bar or other indication be displayed during retrieving data. It is also necessary to show some global error alerts if data retrieval fails.
-
No! Can!!!! Gets component instance this because the component instance has not been created before the guard executes
Vuex + keep-alive and return to refresh
In fact, when rendering details, we already have a Collection of items in the current list, usually an array. Why not populate the details with existing data? The details page renders the data immediately, and then gets the rest of the data through the interface, and then backfills the page after the complete data is retrieved
With this scenario, we had to introduce VuEX to pass data between multiple page components (<10 milliseconds) without waiting for a network response (> 50 milliseconds for Ajax). In addition, the dependent back-end interface must be consistent in the processing of lists and details. That is, the fields of the details interface can only be greater than or equal to the fields of the list interface.
This is what THE author is currently using, and the code is roughly as follows:
goDetail () {
const {activityId} = this
this.$store.commit('AUCTION_DETAIL', this.$props)
this.$router.push({
name: 'auctionroom-item',
params: { activityId }})
}
Copy the code
OK, the incoming logic takes care of the smooth animation and the asynchronous fetching of data, then the new problem arises! We need to consider another case: if the user goes to the list page many times, then goes to the details page and returns, the location remains the same.
Paging VS infinite scrolling
As for paging, the two most common modes are page number paging or using scroll bars, which are also often discussed in the product design world. I found two articles about everyone being a product manager, and you can read them further if you are interested.
-
The infinite scroll: thorough understanding of it (http://www.woshipm.com/pd/132888.html)
-
Infinite drop-down scroll VS paging, which one to use (http://www.woshipm.com/pd/350745.html)
Relatively simple conclusions can be summarized as, page Numbers are applicable to those users looking for specific information list of search results page and the user’s browsing history of the more important occasions, which is suitable for the consumption of Twitter, etc. The user is unlimited information flow is not often search for specific information application, or more than the former in PC, The latter is more common in H5.
If it is page number mode, then return is not an issue, because the page turn information is usually carried in the page URL, and when we return we just need to refresh the current page information. Problem this time the project is the latter, product students can not accept the details of the back to the user back to the top ~
Introduced the keep alive
To solve this problem, you need to use a feature of the vue keep alive – (https://cn.vuejs.org/v2/api/#keep-alive), the principle of use:
-
Component instances are cached rather than destroyed when dynamic components are wrapped
-
The activated and deactivated hooks are invoked during the intra-keep-alive route switchover
-
If the router is outside the router-view, the affected range is the router-view.
Matters needing attention:
-
Created may not be invoked, and some logic needs to be moved to Activated
-
$destroy () can be called from deactivated if state preservation is not required
The problem of not refreshing was solved, but the product students brought new problems, such as if the user in the details page operation! For example, after entering the details from the order list and changing the order status, the list page needs to refresh this data.
Vuex can also be used to solve this problem. The deactivated hook of the details page updates the corresponding data in the list, and also relies on the backend to use the same data format for the details and list interface description orders. The code is roughly as follows:
deactivated () {
this.$store.commit('AUCTION_LIST_INDEX', this.index, this.$data)
}
Copy the code
The final effect is as follows:
For such orders, only the user’s own operation of the data, in this way can meet the needs. However, this scheme is not perfect for commodities and competitive auction products, where there are a lot of data updates during user access time
We might want to cache the page number of the current viewable area in the list page, using vue-scroller, and then refresh the current viewable area on return. But is that the end? You may still be naive!
The complexity of endless scrolling
Students who have done Android, ios and React-native development probably know the famous ListView, ScrollView, RecyclerView
You probably don’t have similar requirements on the Web, but you should know that the more DOM nodes you have, the higher your memory footprint. We may need to reuse list nodes in the viewable area and recycle unseen nodes, but we also need to merge them to keep the scrollbars from changing due to content reclamation collapses.
I won’t break it down too much, but the nuggets have a translation from Google and a corresponding extension:
-
[translation] the complexity of endless rolling – apart from Google a great god (https://juejin.cn/post/6844903463629881351)
-
Design the infinite scroll drop-down load, the practice essence of high-performance page (https://juejin.cn/post/6844903465357934599)
According to the article observation, the use of this technology in the real product line is relatively few. Probably because the implementation complexity and benefit ratio are not very high. However, Taobao mobile terminal search page to achieve a similar idea. The following figure,
conclusion
Borrowing: When you’re trying to provide a high performance user experience feature, a technically simple problem can become a complex one. This article is a case in point. As Progressive Web Apps become first-class citizens on mobile devices (will they?) The good experience of high performance will become more and more important. Developers must also continue to explore patterns to deal with performance constraints. Of course, these designs are based on mature technology.
My view: in fact this kind of optimization why not browser to do! ?
Finally do a small advertisement, turn around excellent product mobile phone to help sell, let you sell its old mobile phone at a high price ~ if it is helpful to you, please forward to circle of friends ~