Infinite scroll & filter version of Hacker News
An infinite scroll & filter Hacker News demo, build with Vue.js and Vue-infinite-loading plugin
by PeachScript
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<script src="https://unpkg.com/vue-infinite-loading@%5E2/dist/vue-infinite-loading.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<div id="app">
<header class="hacker-news-header">
<a target="_blank" href="http://www.ycombinator.com/">
<img src="https://news.ycombinator.com/y18.gif">
</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="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>
SCSS
body {
padding-top: 28px;
background-color: #F6F6EF;
}
.hacker-news-header {
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 4px 20px;
line-height: 14px;
background-color: #FF6600;
img {
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;
}
}
.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;
}
}
}
JavaScript
const api = '//hn.algolia.com/api/v1/search_by_date';
new Vue({
el: '#app',
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;
},
},
});