This article is a vue.js tutorial that aims to help readers better understand some of the design ideas in vue.js with a common business scenario- Paging/unlimited loading . A more comprehensive presentation of the thought process of using vue.js to complete a requirement compared to many of the Todo list tutorials, and more focused on piecemeal details to help readers quickly grasp and use them, compared to some of the higher-order tutorials that build large applications.
Demand analysis
When the amount of information on a page is too large (for example, there are 200 pieces of news in a news list), problems arise, such as:
"Data volume is too large, affecting loading speed
"User experience is poor, it is difficult to locate a previously read an article
"Poor scalability, if 200 becomes 2000 or more
So the common solution is to load data at the end of the page or to display the paging. The implementation of an infinite load is similar to the following:
1.ajax class method to get Data
2. Storing data in a local array
3. Each piece of data in the array is inserted into an HTML template fragment
4. Append the HTML fragment into the node
The implementation of the front page paging is similar to the following:
1.ajax class method to get Data
2. Data substitution Local Array
3. Each piece of data in the array is inserted into an HTML template fragment
4. Append the HTML fragment to the node after emptying the node
Often when you modify or maintain code, we find it annoying to render HTML and insert parts. Because we need to put the HTML into a string, in the corresponding position to insert data, is often a very long string, and then want to add a class is laborious. The ES6 template string makes this situation better, but it still has flaws (for example, when you actually write without the HTML code highlighting). At the same time we need to write a few for or foreach to loop the array, and then command the append, if this snippet has some complex interaction, may also need to bind a bunch of methods through the event agent.
If you have encountered the above problems when completing this kind of business, you will find that Vue is really coooooool, let ' s vue!
Create a new Vue.js project
It is highly recommended to use VUE-CLI to create a new project.
At first you might think that installing a bunch of libraries with node.js and NPM, generating directories and profiles that you don't know much about, and a code that jumps out a bunch of eslint hints. But it's definitely worth it, because a template like this can help you better understand the Vue.js organization document, and when you get used to it, you'll find that these rules greatly accelerate your development efficiency.
In this tutorial, we created a new project called Loadmore, and the new project process can refer to the installation section of the official website tutorial.
Layout page Structure
In order to cooperate with the tutorial step-by-step, I start with the completion of loading more features. In order to be consistent with the pagination that follows, my page preparation consists of two parts, one is the information list, the other is the bottom one that loads more buttons, and I put them all in the root component of App.vue.
<template>
<div id= "app" >
<list></list>
<a class= "button" @click = "Next" >go next</a>
</div>
</template>
<script>
import List from./components /list '
export default {
components: {
List
},
data () {return
{
...
}
}},
methods: {
next () {
...
}
}} </script>
<style scoped>
. button {
display:block;
width:100%;
Background: #212121;
Color: #fff;
Font-weight:bold;
Text-align:center;
Padding:1em;
Cursor:pointer;
Text-decoration:none
}
. Button span {
margin-left:2em;
Font-size:. 5rem;
Color: #d6d6d6;
}
</style>
In this process, we have the following ideas according to the Vue design idea:
1. In the list of information, we will complete the steps mentioned above, which are only related to the information list itself, and the only connection to the Next button is the list of triggers that need to be triggered by next click, which can be passed through props. So we put the list and its own business logic and style in the List.vue component.
2. We define some basic styles for the button, But the CSS selector we use is a. Button class name that might conflict with the. Button style in other components, so we added a scoped property so that the style style in App.vue only works inside the component.
Note: scoped does not affect the precedence of CSS, and using scoped does not mean that it will not be overwritten by an external style sheet.
3. We want to introduce some basic styles, such as reset.css. If you use a language such as sass in your project, then you can put the corresponding external sass file in the Assets folder and import it by importing it. Ordinary CSS can be written directly in a component without scoped attributes, but if you are sure that the stylesheet will not be changed frequently, it can also be introduced into the index.html as a third-party static resource. For example, in this example, I joined the index.html:
<link rel= "stylesheet" href= "/static/reset.css" >
Effect:
Complete List.vue
At present our main business logic revolves around the information list, which is the List.vue we created. First, we need to get the target data, and I use the Cnodejs.org community API as an example to write. If you also want to use a encapsulated AJAX library, you should do this:
Introduction of the third party JS Library
Place the target JS library file in a static folder, for example, I choose Reqwest.js, and then introduce it first in index.html.
<script src= "./static/reqwest.min.js" ></script>
Then, in the build configuration folder, modify the Webpack.base.conf.js,export Externals property:
Externals: {
' reqwest ': ' Reqwest '
}
So we can load the third party library at any time in our project.
Import reqwest from ' Reqwest '
Write an API interface
In this example, we only need to call the article list this interface, but in the actual project, you may need to call a number of interfaces, and these interfaces will be used in multiple components. Then the logic of calling the interface to scatter in the various components is certainly bad, imagine the other side of the URL has changed, you have to be in countless components to check whether to modify.
So I created a new API folder in the SRC folder to store all kinds of API interfaces. In the current example, to get a list of news, create a new News.js file:
Import reqwest from ' reqwest '
const domain = ' https://cnodejs.org/api/v1/topics '
export default {
getlist ( Data, callback) {
reqwest ({
url:domain,
data:data
})
. Then (Val => callback (NULL, Val)) C15/>.catch (e => callback (e))
}
}
So we have a api:getlist to get the news list.
Writing components
We use a <ol> as a news list, each <li> inside is a piece of news, including title, time and author 3 information.
In data, we use an array named list to store the data for the news list, which is, of course, empty at first. We then set a value named limit in data to control how many data each page loads, passing it as a parameter to the GetList API.
So our template part is like this (added some style landscaping style):
<template>
<ol>
<li v-for= "News of List" >
<p class= "title" >{{News.title}}</ p>
<p class= "date" >{{news.create_at}}</p> <p class=
"Author": {{ News.author.loginname}}</p>
</li>
</ol>
</template>
<style scoped >
ol {
margin-left:2rem;
List-style:outside decimal;
}
Li {
line-height:1.5;
Padding:1rem;
border-bottom:1px solid #b6b6b6;
Title {
Font-weight:bold;
Font-size:1.3rem
}
. Date {
font-size:. 8rem;
Color: #d6d6d6;
}
</style>
Then we obviously need to use getlist to get the data, but first think about where we're going to use it? First, we need to automatically fetch the list once the component starts rendering, and populate the underlying content. Second, we need to get a new list each time we click the Next button in App.vue.
So we define a get method in the methods, after successfully fetching the data, we put the acquired array into the current list array, so that we can load more.
Along the way, think about the parameters that the Get method requires, one that contains the page and limit two attributes, and the other is the callback function. callback function We have said that we just need to stitch the array so that the last page parameter is not set.
At initialization time, the page value should be 1, and the default is the first page content. The page value is then changed only by the Next button, so we let page get the page value from the App.vue by props.
Finally, a condition that supplements the trigger of the Get method. One is to call This.get () to get the initial content in the lifecycle function created of the component, the other is to get it when the page value changes, so we watch the page property and call This.get () when it changes.
The last List.vue of the script is this:
<script>
Import News from '. /api/news '
export default {
data () {return
{
list: [],
limit:10
}
},
props: {
Page: {
type:number,
default:1
}
},
created () {
this.get ()
},
watch: {
Page (val) {
this.get ()
}
},
methods: {Get
() {
news.getlist ({
page:this.page,
Limit:this.limit
}, (err, list) => {
if (err) {
console.log (err)
} else {
List.data.forEach ((data) => {
const d = new Date (data.create_at)
data.create_at = ' ${d.getfullyear ()}-${ D.getmonth () + 1}-${d.getdate ()} '
})
this.list = This.list.concat (List.data)}}
)
}
}
}
</script>
At the same time, we will modify the <list> in App.vue to:
<list:p age= "page" ></list>
Add an initial value to the page in App.vue and the corresponding method next:
Data () {return
{
page:1
}
},
methods: {
next () {
this.page++
}
}}
So we've finished loading more features.
Overwrite as paging
Because before our idea is very clear, the code structure is also very clear, so rewrite it will be very simple, just want to list.vue the stitching array into an assignment array can be:
General Loadmore
//this.list = This.list.concat (list.data)/
paging
this.list = List.data
This simple line completes the change in functionality, which is the power of the core data-driven view of the vue.js. Of course, we have to do a little more cooooool.
Add Features
Because paging replaces the original array, just one Next button is not enough, and we need a previous button to return to the previous page. Similarly, the previous button is also bound to a previous method, in addition to using this.page--to change the value of the page, you also need to This.page = = 1 boundary conditions to make a judgment.
At the same time in order to easily know our current number of pages, in the button, add {{page}} to display the number of pages.
<a class= "button" @click = "Next" >go next<span>current:{{page}}</span></a>
Transition animation
the process of writing and perfecting functions, has fully embodied the vue.js clear and convenient side, and then continue to see other useful features, the first is transition animation.
To show the power of transition, first I found an object to imitate: Lavalamp.js (demo address).
In the demo can see the page in a very elegant animation transition to complete the process of switching content, which itself is done with jquery+css animation, I am ready to rewrite with Vue.js.
First learned the original author of the idea, found that a div as a loader,position set to fixed. When paging, depending on the button clicked, the loader extends from the top or bottom to 100%. After loading the data, fold the height and finally hide.
So the initial idea is as follows:
1. Add a loader, the minimum height is consistent with the button, the background is black, make the transition appear more natural.
The 2.loader height needs to reach a screen height, so the height of HTML and body is set to 100%.
3. Need to have a value, as loader whether the basis for display, I set to finish, its default value is true, by adding v-show= "!finish" to loader to control its display.
4. Add This.finish = False to the next and previous methods to trigger the display of loader.
5. In App.vue and List.vue, establish a two-way props property binding to finish, and when the Get method in List.vue is finished, props is hidden by setting the finish in App.vue to true.
6. Add a transition to loader. Because the animation is divided into top expansion and bottom expansion, use dynamic transition to assign it the correct transition name.
7. Add a value up to determine which direction the animation starts, and its default value is False. In the previous method, execution This.up = True, and vice versa in the next method, executes This.up = False.
According to the idea, write the loader should be such (style and other styles set in the final unified display):
<div id= "loader" v-show= "!finish": transition= "up?" ' Up-start ': ' Down-start ' >
<span>Loading</span>
</div>
You can see that I have set the Up-start and Down-start two kinds of transition, the corresponding CSS animation code is as follows:
. down-start-transition {
bottom:0;
height:100%
}
. Down-start-enter {
Animation:expand 5s 1 cubic-bezier (0, 1, 0, 1) both;
Down-start-leave {
animation:collapse 5s 1 cubic-bezier (0, 1, 0, 1) both;
top:0;
Bottom:auto
}
. up-start-transition {
top:0;
height:100%
}
. Up-start-enter {
Animation:expand 5s 1 cubic-bezier (0, 1, 0, 1) both;
Up-start-leave {
animation:collapse 5s 1 cubic-bezier (0, 1, 0, 1) both;
Top:auto;
bottom:0;
}
@keyframes Expand {
0% {
height:3em;
Transform:translate3d (0, 0, 0);
}
100% {
height:100%;
Transform:translate3d (0, 0, 0);
}
}
@keyframes Collapse {
0% {
height:100%;
Transform:translate3d (0, 0, 0);
}
100% {
height:3em;
Transform:translate3d (0, 0, 0);
}
}
Set the expand and collapse two animation, and then in the transition of each life cycle hook to do the corresponding binding, to achieve and lavalamp.js close to the effect.
To ensure that the animation is complete, after the List.vue get method is executed, a settimeout timer is used to make the finish delay of 0.5 seconds become true.
Optimization Experience
After the animation effect is completed, the actual use found that lavalamp.js also has a clever design, that is, click Previous, the page to the bottom, and then click Next then go to the top.
Implementing the latter is not complicated, and adding the following line of code to the next method can be adjusted:
Document.body.scrollTop = 0
Previous to the bottom is slightly more complicated, because the page height will change after getting the data, if the implementation of scrolltop changes in the previous, there may be a new content after the height of the fill, the page is not the end of the situation. So I watch the value of finish, and go to the bottom only when the Click button is previous and the finish changes to False to true, the code is as follows:
Watch: {
finish (val, oldval) {
if (!oldval && val && this.up) {
Document.body.scrollTop = doc Ument.body.scrollHeight}}}
Front-End routing
after completing the above, find that no matter how many pages, once refreshed, will return to the first page. Vue-router was born to solve such problems.
First we introduce Vuerouter, the way can refer to the "introduction of the third party JS Library" above. Then there are some configurations of the routing rules in Main.js.
Our ideas include:
1. We need to reflect the current number of pages on the URL.
The number of pages in 2.url should be consistent with the page values in all components.
3. Click Next and the previous button to jump to the corresponding URL.
4. We have no router-view in this example.
So the main.js configuration is as follows:
Import Vue from ' Vue ' to ' import App from '
./app '
import vuerouter from ' Vuerouter ' Vue.use
(vuerouter)
Const ROUTER = new Vuerouter ()
router.map ({
'/page/:p agenum ': {
Name: ' Page ',
component: {}
}
})
router.redirect ({
'/': '/PAGE/1 '
})
Router.beforeeach ((transition) => {
if ( Transition.to.path!== '/page/0 ') {
transition.next ()
} else {
transition.abort ()}}
)
Router.start (app, ' app ')
First, a named path named page is defined. All the target paths are then '/', that is, the initial page request, redirected to '/PAGE/1 ' to ensure consistency. Finally, make a judgment before each route execution, and if the illegal path such as '/page/0 ' is done, the Transition.next () is not executed.
According to the previous idea, in App.vue, get the parameter value of the routing object and assign the value to page. Add the corresponding V-link to two buttons at the same time.
This article has been organized into the "Vue.js front-end component Learning course", welcome to learn to read.
The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.