Use With Filter/Tabs
The loading process is exactly the same as in the previous example. The key point here is how to reset the component when we change the filter or tabs. The infinite loading component will reset itself whenever the identifier
property has changed. It sounds easy, so let's do it!
<header>
<!-- Hacker News header -->
<select v-model="newsType" @change="changeType">
<!-- Type options -->
</select>
</header>
<div v-for="(item, $index) in list" :key="$index">
<!-- Hacker News item loop -->
</div>
<infinite-loading :identifier="infiniteId" @infinite="infiniteHandler"></infinite-loading>
In the template, we add a select
element and listen for its change
event. For the InfiniteLoading
component, we add an identifier
property.
import axios from 'axios';
const api = '//hn.algolia.com/api/v1/search_by_date';
export default {
data() {
return {
page: 1,
list: [],
newsType: 'story',
infiniteId: +new Date(),
};
},
methods: {
infiniteHandler($state) {
axios.get(api, {
params: {
page: this.page,
tags: this.newsType,
},
}).then(({ data }) => {
if (data.hits.length) {
this.page += 1;
this.list.push(...data.hits);
$state.loaded();
} else {
$state.complete();
}
});
},
changeType() {
this.page = 1;
this.list = [];
this.infiniteId += 1;
},
},
};
In the script, we set default values for the select
and identifier
properties, then add the type parameter in the API request logic, and we create the changeType
method to reset the list data and infinite loading component. Please note, we must change the identifier
property after we empty the list
. Otherwise, the component may not trigger the infinite
event immediately after reset.
That's all, you're done!
Demo
<template>
<header class="hacker-news-header">
<a target="_blank" href="http://www.ycombinator.com/">
<img src="https://news.ycombinator.com/y18.svg">
</a>
<span>Hacker News</span>
<select v-model="newsType" @change="changeType()">
<option value="story">Story</option>
<option value="poll">Poll</option>
<option value="show_hn">Show hn</option>
<option value="ask_hn">Ask hn</option>
<option value="front_page">Front page</option>
</select>
</header>
<div class="container">
<div
class="hacker-news-item"
v-for="(item, $index) in list"
:key="$index"
:data-num="$index + 1">
<a target="_blank" :href="item.url" v-text="item.title"></a>
<p>
<span v-text="item.points"></span>
points by
<a
target="_blank"
:href="`https://news.ycombinator.com/user?id=${item.author}`"
v-text="item.author"></a>
|
<a
target="_blank"
:href="`https://news.ycombinator.com/item?id=${item.objectID}`"
v-text="`${item.num_comments} comments`"></a>
</p>
</div>
<infinite-loading :identifier="infiniteId" @infinite="infiniteHandler"></infinite-loading>
</div>
</template>
<script setup>
import { ref } from 'vue'
import axios from 'axios'
// import InfiniteLoading from '@'
import InfiniteLoading from '../../lib'
const page = ref(0)
const list = ref([])
const api = '//hn.algolia.com/api/v1/search_by_date?tags=story';
const newsType = ref('story')
const infiniteId = ref(new Date())
const infiniteHandler = ($state) => {
axios.get(api, {
params: {
page: page.value,
},
}).then(({ data }) => {
if (data.hits.length) {
page.value += 1;
list.value.push(...data.hits);
$state.loaded();
} else {
$state.complete();
}
});
}
const changeType = () => {
page.value = 1
list.value = []
infiniteId.value += 1
}
</script>
<style lang="scss" scoped>
.hacker-news-header {
/* position: fixed; */
top: 0;
left: 0;
right: 0;
padding: 4px 20px;
line-height: 14px;
background-color: #FF6600;
img {
display: inline;
border: 1px solid #fff;
vertical-align: middle;
}
span {
font-family: Verdana, Geneva, sans-serif;
font-size: 14px;
font-weight: bold;
vertical-align: middle;
}
select {
float: right;
color: #fff;
background-color: transparent;
border: 1px solid #fff;
outline: none;
}
}
.container {
max-height: 400px;
overflow: auto;
}
.hacker-news-item {
$gap: 40px;
margin: 10px 0;
padding: 0 10px 0 $gap;
line-height: 16px;
font-size: 14px;
&::before {
content: attr(data-num) '.';
float: left;
margin-left: -$gap;
width: $gap - 8px;
color: #888;
text-align: right;
}
> a {
color: #333;
text-decoration: none;
&:hover {
color: #000;
}
}
p {
margin: 0;
font-size: 12px;
&,
a {
color: #888;
}
a:not(:hover) {
text-decoration: none;
}
}
}
</style>