“Actual combat” series is Blue with everyone to do things, programs that it’s not a difficult thing, just begin, more things to the knowledge of master, so in this series, I hope you did not ask a lot (there is a problem please leave a message), so as to grasp the knowledge of what they have learned, welcome thumb up, collection, review, forwarding
“Learning war in war.”
Vue is very popular and Vue3 is discussed a lot, so this time Blue will take you to Vue3 to make an “infinite drop-down load” application (I am not good at naming, anyone who has a good name welcome to contribute 😂), let’s have a look at the effect
In a nutshell, when we scroll down to the bottom of the page, we load more data so that the user can scroll down to the bottom of the page — an infinite drop-down effect. So, to do this, we need to consider a few things:
- Some basic: project construction, basic layout
- How to load data
- How to listen to the pull down, how to judge the end
- How are components divided and who is responsible for functions
Step 1: Create the project
Since we’re going to build something, we have to have a project and start building it
Create a project
If you don’t already have a CLI for Vue, you can install it first (you can upgrade if you do, the latest VERSION of cli only supports VUe3) :
npm install -g @vue/cli # If it is too slow, you can configure CNPM taobao source or YARN, which is much faster
Copy the code
We then do the rest of the creation directly with the vue command
vue create endless-scroll Endless Scroll is the name of the project, you can take whatever you like
Copy the code
Next it lets you choose the type of project, in this case vue3
The following “manual selection” has a lot of features available, we are not here for the time being, interested in you can have a look, a variety of testing what
Then there’s the long wait, which can take about 10 minutes to make a cup of tea or go for a spin
Tea’s done, it’s done, so we can try to start it
cd endless-scroll Follow your own project name
npm run serve There are three common startup methods. Serve is used for debugging during development
Copy the code
If all goes well, open http://localhost:8080 and you will see the following default content
So, our development journey has officially begun
The project structure
First, let’s take a look at the small things we’ve just created
Just to give you an idea
.git Git local library, version control use, we here is a test project can be deleted
node_modules # All dependency modules and future third party modules will also be placed here, extremely fragile, must be supplied
public Static public files (e.g. index.html, ICONS etc.)
src # The heart of the project, the code you wrote is right here
.gitignore Git filters will be read by your IDE
babel.config.js # Babel configuration, leave it
package.json Project configuration files - dependencies on modules, startup commands, project configuration, etc
README.md # file description, you can see, after reading can delete
yarn.lock # module version lock, whether to leave or not (deleted will be automatically created), lock the version used
Copy the code
Do a sweep
I’ve deleted it a little bit, and now it looks like this
First, delete the component. The HelloWorld attached to it is useless. Just delete it
Finally, clean up our app. vue root component as well, leaving a template is enough
Clean up before
Clean up after
So far, the preparation is complete. Let’s go. Let’s get started
Step 2: Figure out the layout
So where do we start? Let’s get the big picture
Just start writing
<template> <div class="container"> <div class="left"> Content area </div> <div class="right"> list </div> </div> </template> <style> /* */ * {margin: 0; margin: 0; padding: 0; list-style: none; } body { background: #389acc; } </style> <style scoped> /* App own style */. margin: 50px auto; display: flex; } .left { flex: 1; background: #fff; margin-right: 10px; text-align: center; line-height: 200px; color: #ccc; font-size: 26px; } .right { width: 350px; background: #fff; } </style>Copy the code
Here we have two divs, the one on the left automatically sized, the one on the right fixed, and the result looks like this
Create a List component
Now that the big frame is set up, let’s build some details, because all we need to do is the list on the right, so we can pull out a separate component, so we can play around with it
Next, let’s see if it comes out, and then we’ll go ahead and import it from app.vue
Here we do a few things:
- Specify the development language (
lang="ts"
Vue3’s support for TS is already quite good (compared to V2), so it’s nice to use strong types - Define a component (
defineComponent
) : Help us define components – mainly types in TS, very convenient
It looks like this
Then, we need to introduce the List component we just wrote (although there is nothing there), three things:
import
Introduce the List component: This is easy, we need to introduce everything first- registered
List
Component: Available in componentscomponents
To register the local component, and thentemplate
The use of - Add to the template
At this point, we can see the List component on the page
Now that the basic layout is in place, let’s start writing the List
Writing a List component
First, regardless of function, the list has to have a look, so let’s add some HTML and styles:
<! -- List.vue layout --> <template> <div> <! <div class="item"> <h3 class="header"> </h3> <p class="content"> this is the content of some text. This is the content of some text, this is the content of some text, this is the content of some text </p> </div> <div class="item"> <h3 class="header"> This is a header, maybe a little long, yeah, </h3> <p class="content"> </p> < div> </div> </template>Copy the code
There’s no styling yet, so our thing looks like this:
Oh, my god, it’s ugly. It’s okay. Let’s decorate it
<style scoped> /* scoped- scoped */. Item {box-sizing: border-box; width: 350px; height: 180px; padding: 20px 20px; background: #fff; border: 1px solid #ccc; margin-bottom: -1px; }. Header {font-size: 22px; margin-bottom: 20px; /* Text is too long to truncate */ overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .content { color: #999; font-size: 14px; line-height: 26px; height: 78px; /* Multiline text truncation */ overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: 3; } </style>Copy the code
Let’s see if it’s better:
I can’t say it’s amazing, but at least it’s meeting people, right
Step 3: Add data
So far, I’ve got a little bit of stuff, but it’s still dead, and I can’t write it out directly, so we want the data, so let’s start with the simplest thing
First edition, static data
In list. vue, we add data
<script lang="ts"> import { defineComponent } from "vue"; Export default defineComponent({setup() {// Const datas = [{ID: 1, title: Multiple flights unable to land due to suspected unidentified aircraft activity. A flight tracking software used by aviation enthusiasts found that several flights had circled and waited in the air before arriving at Hangzhou Xiaoshan International Airport or diverted to nearby Ningbo Lihe International Airport on The night of April 4. "A bankrupt company in Changxing, Huzhou, with assets of 200 million yuan, was auctioned. Behind it was the figure of" The richest man in China who fell fastest ", Content: "Yes," Hanergy ", "Hanergy Thin Film" was the most obscure "monster stock" in Hong Kong stocks in 2013 and 2014, and its founder Li Hejun was the richest man in China in March 2015 with a wealth of 160 billion yuan. However, his wealth plummeted 100 billion yuan only 3 months later, and he was called the richest man in the world. Return {datas, // to use} in template; }}); </script>Copy the code
And then again, list.vue, we add loops and output
<template> <div> <div class="item"> <h3 class="header"> </h3> <p class="content"> This is the content of some text, </p> </div> </div> </template> <! <div> <div class="item" v-for="item in datas" :key="item.ID"> <h3 class="header">{{item.title }}</h3> <p class="content">{{ item.content }}</p> </div> </div> </template>Copy the code
Let’s see what happens
That’s good. There’s no shortage of one. So what we’re going to do is we’re going to animate the data
How to use dynamic data
First of all, if you want to read data, you definitely need Ajax, and this time we’re not going to focus on Ajax itself, so just make it simple and use axios
First install, CTRL + C to stop the project, then install (note that mixing package managers can be problematic)
npm i axios -S
# or
cnpm i axios -S
# or
yarn add axios
Copy the code
Complete the
Next, we need a file to hold the data in.
The files in public, by the way, will be copied to the compiled result exactly as they are, so this stuff will still be accessible when it goes live
Read the data
<script lang="ts"> import { defineComponent } from "vue"; // import axios from "axios"; Export default defineComponent({setup() {axios("/datas.json").then((res) => {console.log(res.data); // Type out what you read}); Return {datas: [], // null}; }}); </script>Copy the code
Run and see how it works (don’t forget to start NPM Run Serve)
Good. I got everything I need
Update the data
Then we need to face another problem — how to update the data
In Vue3, we have several ways to build “responsive data”, which means that after you modify the data, the view automatically rerenders in response to your changes to the data. In this case, we chose ref, which is very convenient to use with individual data (such as arrays here)
How to use Ref
So let’s start with a simple example, how do we use ref
{{name}} <button @click="name += 'a'"> {{age}} <button @click="age++"> Modify </button> </div> </div> </template> <script lang="ts"> import {defineComponent, ref } from "vue"; Export default defineComponent({setup() {let name = "blue"; // let age = ref(18); Return {name, age}; }}); </script>Copy the code
It looks like this:
Regardless of whether it’s ugly or not, what happens if we click on it?
Here we see two strange things:
- Modify the
name
(Ordinary variable) no response - Modify the
age
(Response data) respond and connectname
The changes have taken effect together
It’s actually quite simple, one by one:
-
Why is there no response to modifying name?
For performance reasons, vUE does not listen for all changes and only specific data (ref, Reactive, etc.) triggers rendering
-
Why is age valid with name?
Since vue checks for changes to all data (including non-response data) during re-rendering, changes to the natural name are also detected
Second edition, server data
It’s time to put everything above us together
<template> <div> <div class="item" v-for="item in datas" :key="item.ID"> <h3 class="header">{{ item.title }}</h3> <p class="content">{{ item.content }}</p> </div> </div> </template> <script lang="ts"> import { defineComponent, ref } from "vue"; import axios from "axios"; export default defineComponent({ setup() { const datas = ref([]); // Array of responses (human version: Then ((res) => {//1-ref =.value, Datas.value = [...datas.value,...res.data]; datas.value = [...datas.value,...res.data]; }); Return {datas, // output to the page to use}; }}); </script>Copy the code
See if you can come out:
Data this basic fix, but there is a problem, pull to the bottom it unexpectedly will not automatically update (nonsense, haven’t done 😂), how to do, continue to do
Step 4, listen to the page scroll
It’s actually pretty easy for us to auto-load, two things:
- Monitor the scroll
- When you see it’s rolling to the bottom, you get a new one
Let’s follow this procedure
Add to monitor
First of all, we know that most of the events in vue are added by @xxx, but the scroll events are Windows. We can’t window.@scroll. It’s actually very simple, just add it manually
import { onMounted, onUnmounted } from "vue";
export default defineComponent({
setup() {
// Scroll the event handler
function scrollHandle() {
console.log('roll');
}
onMounted(() = > {
// Add scroll listener when component is mounted
window.addEventListener("scroll", scrollHandle, false);
});
onUnmounted(() = > {
// Stop listening when the component is uninstalled
window.removeEventListener("scroll", scrollHandle, false); }); }});Copy the code
What was the effect?
That seems to be fine, and it does remind us to scroll, which brings us to the second question — how do we know we’re near the end
Is it close to the end?
What trifle, whole follow tongue twister like 😂
In a nutshell, we need to detect “is the user rolling to the bottom?” So how do we do that? Let’s take a look at a picture with Blue
It’s rough (you call that rough??) “, but the meaning is very clear: the page is very high, the viewable area slides up and down on the page, and we can calculate the distance between the viewable area and the bottom of the page, and if it’s below a certain threshold, we’ll say, “This is almost the end.”
Okay, so how do we calculate this distance? Let’s see another picture
There are several values on the page that you can use
-
#1-scrollTop: Roll distance
-
#2-scrollHeight: Total height of the page content
-
#3-clientHeight: The height of the viewing area
// Distance = total height - rolling distance - viewable height
let distance = scrollHeight - scrollTop - clientHeight;
Copy the code
Let’s try it in code
Look at the results
It turns out to be something like -100. Why is that? Actually very simple, our margin caused
Because margin does not count the height of the object itself, so the content is smaller than it actually looks. What should I do? Change the bai
Try it out
This is much better, so we just need to determine that the value is small enough (say 200, depending on your needs)
Let’s try it out
But there is a problem, it appears many times, what to do?
Prevent reloading
In simple terms, we can “lock” it once it has been loaded and not allow it to fire again until the load is complete
// Load logic
/ / modify before
axios("/datas.json").then((res) = > {
datas.value = [...datas.value, ...res.data];
});
/ / modified
let readyForLoad = true; // Load once by default
if (readyForLoad) {
// It needs to be loaded in order to prevent repetition
readyForLoad = false; // Lock it up
axios("/datas.json").then((res) = > {
datas.value = [...datas.value, ...res.data];
readyForLoad = true; // Open the lock only after loading, allowing it to trigger again
});
}
Copy the code
Because we need to load it all the time, so we’ll wrap it up as a function, like this
let readyForLoad = true; // Load once by default
function loadMore() {
if (readyForLoad) {
// It needs to be loaded in order to prevent repetition
readyForLoad = false; // Lock it up
axios("/datas.json").then((res) = > {
datas.value = [...datas.value, ...res.data];
readyForLoad = true; // Open the lock only after loading, allowing it to trigger again}); }}Copy the code
Our setup would then look like this:
setup() {
// Scroll the event handler
function scrollHandle() {... Omit some code...if (distance <= 200) {
console.log("Near the end!);
loadMore(); // It doesn't matter how many times the trigger is triggered} } onMounted(...) ; onUnmounted(...) ;const datas = ref([]);
let readyForLoad = true; // Load once by default
loadMore(); // Start loading once
function loadMore() {
if (readyForLoad) {
// It needs to be loaded in order to prevent repetition
readyForLoad = false; // Lock it up
axios("/datas.json").then((res) = > {
datas.value = [...datas.value, ...res.data];
readyForLoad = true; // Open the lock only after loading, allowing it to trigger again}); }}return {
datas, // Output to the page for use
};
},
Copy the code
Try the effect, basically no problem (GIF format is too poor, pressure out of the actually 10M, webM is only a few hundred K, so be careful)
conclusion
It’s time to go over what Blue said, so first of all
- use
@vue/cli
Quick construction project, convenient - Read the data using Axios
- in
mount
andunmount
Listen for the page scroll event - Calculate the distance to the bottom of the page (distance = total height – scrolling distance – viewable area height), less than a certain threshold (such as 200) as the bottom
- By “throttling” mode, prevent repeated trigger loading action
- After loading,
[...oldData, ...newData]
Join all the data together to form a new array to use - through
ref
Update views in real time
Have a bug? Would like to add?
Thank you for watching this tutorial, if you have any questions or want to talk to me, please leave a comment directly. If you find anything inappropriate in this article, please also point out, thanks in advance