feat : Home Article ReRender Success and Pagination Template add
This commit is contained in:
@@ -1,34 +1,62 @@
|
||||
import { ref, Ref } from "@vue/reactivity";
|
||||
import { listArticles } from "@/api/index";
|
||||
import { listArticles, feedArticle } from "@/api/index";
|
||||
|
||||
import { usePagination } from "@/ts/usePagination";
|
||||
|
||||
|
||||
export interface Todo {
|
||||
id: number;
|
||||
title: string;
|
||||
export interface ArticleList {
|
||||
slug: string,
|
||||
title: string,
|
||||
description: string,
|
||||
favorited: boolean,
|
||||
favoritesCount: number,
|
||||
createdAt: string,
|
||||
author: {
|
||||
username: string,
|
||||
image: string
|
||||
}
|
||||
}
|
||||
|
||||
export function usePaginationApi(
|
||||
currentPage: Ref<number>,
|
||||
rowsPerPage?: Ref<number>
|
||||
) {
|
||||
const articleLists: Ref<Todo[]> = ref([]);
|
||||
const articleLists: Ref<ArticleList[]> = ref([]);
|
||||
|
||||
const listsAreLoading = ref(false);
|
||||
const isEmpty = ref(false);
|
||||
|
||||
const { paginatedArray, numberOfPages } = usePagination<Todo>({
|
||||
const { paginatedArray, numberOfPages } = usePagination<ArticleList>({
|
||||
rowsPerPage,
|
||||
arrayToPaginate: articleLists,
|
||||
currentPage
|
||||
});
|
||||
|
||||
const feedLists = async () => {
|
||||
listsAreLoading.value = true;
|
||||
isEmpty.value = false;
|
||||
try{
|
||||
const { data } = await feedArticle();
|
||||
articleLists.value = data.articles;
|
||||
if(data.articlesCount == 0){
|
||||
isEmpty.value = true;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
} finally {
|
||||
listsAreLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const loadLists = async () => {
|
||||
listsAreLoading.value = true;
|
||||
isEmpty.value = false;
|
||||
try {
|
||||
const { data } = await listArticles();
|
||||
articleLists.value = data.articles;
|
||||
console.log(articleLists.value);
|
||||
if(data.articlesCount == 0){
|
||||
isEmpty.value = true;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
} finally {
|
||||
@@ -39,7 +67,9 @@ export function usePaginationApi(
|
||||
return {
|
||||
articleLists: paginatedArray,
|
||||
loadLists,
|
||||
feedLists,
|
||||
listsAreLoading,
|
||||
isEmpty,
|
||||
numberOfPages
|
||||
};
|
||||
}
|
||||
@@ -1,45 +1,46 @@
|
||||
<template>
|
||||
<div v-for = "art in articles.article">
|
||||
<div class="article-preview">
|
||||
<div class="article-meta">
|
||||
<a href="profile.html"><img :src="art.author.image"/></a>
|
||||
<div class="info">
|
||||
<a href="" class="author">{{art.author.username}}</a>
|
||||
<span class="date">{{convertDate(art.createdAt)}}</span>
|
||||
</div>
|
||||
<button class="btn btn-outline-primary btn-sm pull-xs-right">
|
||||
<i class="ion-heart"></i> {{art.favoritesCount}}
|
||||
</button>
|
||||
<div class="article-preview">
|
||||
<div class="article-meta">
|
||||
<a href="javascript:(0)" @click="showProfile(article.author.username)"><img :src="article.author.image"/></a>
|
||||
<div class="info">
|
||||
<a class="author"
|
||||
href="javascript:void(0)"
|
||||
@click="showProfile(article.author.username)">{{article.author.username}}</a>
|
||||
<span class="date">{{convertDate(article.createdAt)}}</span>
|
||||
</div>
|
||||
<a href="" class="preview-link">
|
||||
<h1>{{art.title}}</h1>
|
||||
<p>{{art.description}}</p>
|
||||
<span>Read more...</span>
|
||||
</a>
|
||||
<button class="btn btn-outline-primary btn-sm pull-xs-right">
|
||||
<i class="ion-heart" @click="changeFavorite(article.slug, article.favorited)"></i> {{article.favoritesCount}}
|
||||
</button>
|
||||
</div>
|
||||
<a href="javascript:(0)"
|
||||
class="preview-link"
|
||||
@click="showArticle(article.slug)">
|
||||
<h1>{{article.title}}</h1>
|
||||
<p>{{article.description}}</p>
|
||||
<span>Read more...</span>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {onMounted, reactive, ref, defineComponent} from "vue";
|
||||
import {useStore} from "vuex";
|
||||
import axios from "axios";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
import convertDate from "@/ts/common";
|
||||
import {feedArticle} from "@/api";
|
||||
import { favoriteArticle, unFavoriteArticle } from "@/api";
|
||||
import router from "@/router";
|
||||
import {useStore} from "vuex";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ArticleListFeed",
|
||||
props:{
|
||||
isEmpty: Boolean,
|
||||
isLoading: Boolean
|
||||
},
|
||||
setup(props,{ emit }){
|
||||
const articles = reactive({
|
||||
article:[
|
||||
{
|
||||
props: {
|
||||
article: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
slug: "",
|
||||
title: "",
|
||||
description: "",
|
||||
favorited: false,
|
||||
favoritesCount: 0,
|
||||
createdAt: "",
|
||||
author: {
|
||||
@@ -47,24 +48,45 @@ export default defineComponent({
|
||||
image: ""
|
||||
}
|
||||
}
|
||||
],
|
||||
articlesCount: ""}
|
||||
)
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const { data } = await feedArticle();
|
||||
articles.article = data.articles.slice();
|
||||
articles.articlesCount = data.articlesCount;
|
||||
emit("loading",false);
|
||||
if(parseInt(articles.articlesCount) == 0) {
|
||||
emit("emptied",true);
|
||||
}
|
||||
}catch (error: any){
|
||||
alert(error);
|
||||
}
|
||||
})
|
||||
return { articles, convertDate }
|
||||
}
|
||||
},
|
||||
setup(props){
|
||||
const store = useStore();
|
||||
const token = store.state.token;
|
||||
|
||||
const showProfile = (username: string) => {
|
||||
router.push({
|
||||
name: 'Profile',
|
||||
params: {username: username}
|
||||
})
|
||||
}
|
||||
|
||||
const showArticle = (slug: string) =>{
|
||||
router.push({
|
||||
name: 'ArticleDetail',
|
||||
params: {slug: slug}
|
||||
})
|
||||
}
|
||||
|
||||
const changeFavorite = async (slug: string, favorite : boolean) => {
|
||||
if(token == ''){
|
||||
await router.push({name:"Login"});
|
||||
return;
|
||||
}else{
|
||||
if(favorite){
|
||||
const { data } = await unFavoriteArticle(slug);
|
||||
props.article.favoritesCount = data.article.favoritesCount;
|
||||
props.article.favorited = data.article.favorited;
|
||||
}else{
|
||||
const { data } = await favoriteArticle(slug);
|
||||
props.article.favoritesCount = data.article.favoritesCount;
|
||||
props.article.favorited = data.article.favorited;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { convertDate, changeFavorite, showProfile, showArticle }
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,46 +1,42 @@
|
||||
<template>
|
||||
<div v-for = "art in articles.article">
|
||||
<div class="article-preview">
|
||||
<div class="article-meta">
|
||||
<a href="javascript:(0)" @click="showProfile(art.author.username)"><img :src="art.author.image"/></a>
|
||||
<a href="javascript:(0)" @click="showProfile(article.author.username)"><img :src="article.author.image"/></a>
|
||||
<div class="info">
|
||||
<a class="author"
|
||||
href="javascript:void(0)"
|
||||
@click="showProfile(art.author.username)">{{art.author.username}}</a>
|
||||
<span class="date">{{convertDate(art.createdAt)}}</span>
|
||||
@click="showProfile(article.author.username)">{{article.author.username}}</a>
|
||||
<span class="date">{{convertDate(article.createdAt)}}</span>
|
||||
</div>
|
||||
<button class="btn btn-outline-primary btn-sm pull-xs-right">
|
||||
<i class="ion-heart" @click="changeFavorite(art.slug, art.favorited)"></i> {{art.favoritesCount}}
|
||||
<i class="ion-heart" @click="changeFavorite(article.slug, article.favorited)"></i> {{article.favoritesCount}}
|
||||
</button>
|
||||
</div>
|
||||
<a href="javascript:(0)"
|
||||
class="preview-link"
|
||||
@click="showArticle(art.slug)">
|
||||
<h1>{{art.title}}</h1>
|
||||
<p>{{art.description}}</p>
|
||||
@click="showArticle(article.slug)">
|
||||
<h1>{{article.title}}</h1>
|
||||
<p>{{article.description}}</p>
|
||||
<span>Read more...</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {onMounted, reactive, defineComponent } from "vue";
|
||||
import { defineComponent } from "vue";
|
||||
import router from "@/router";
|
||||
import convertDate from '@/ts/common';
|
||||
import {favoriteArticle, listArticles, unFavoriteArticle} from "@/api";
|
||||
import { useStore } from "vuex";
|
||||
import { favoriteArticle, unFavoriteArticle } from "@/api";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ArticleListGlobal",
|
||||
props:{
|
||||
isLoading: Boolean,
|
||||
isEmpty: Boolean,
|
||||
globalActive: Boolean,
|
||||
},
|
||||
setup(props,{emit}) {
|
||||
const articles = reactive({
|
||||
article:[
|
||||
{
|
||||
index: Number,
|
||||
article: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
slug: "",
|
||||
title: "",
|
||||
description: "",
|
||||
@@ -52,9 +48,12 @@ export default defineComponent({
|
||||
image: ""
|
||||
}
|
||||
}
|
||||
],
|
||||
articlesCount: ""}
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore();
|
||||
const token = store.state.token;
|
||||
|
||||
const showProfile = (username: string) => {
|
||||
router.push({
|
||||
@@ -71,29 +70,23 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const changeFavorite = async (slug: string, favorite : boolean) => {
|
||||
if(favorite){
|
||||
await unFavoriteArticle(slug);
|
||||
if(token == ''){
|
||||
await router.push({name:"Login"});
|
||||
return;
|
||||
}else{
|
||||
await favoriteArticle(slug);
|
||||
if(favorite){
|
||||
const { data } = await unFavoriteArticle(slug);
|
||||
props.article.favoritesCount = data.article.favoritesCount;
|
||||
props.article.favorited = data.article.favorited;
|
||||
}else{
|
||||
const { data } = await favoriteArticle(slug);
|
||||
props.article.favoritesCount = data.article.favoritesCount;
|
||||
props.article.favorited = data.article.favorited;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
console.log(props.isEmpty,props.globalActive,props.isLoading);
|
||||
try {
|
||||
const { data } = await listArticles();
|
||||
articles.article = data.articles.slice();
|
||||
articles.articlesCount = data.articlesCount;
|
||||
emit("loading",false);
|
||||
if(parseInt(articles.articlesCount) == 0) {
|
||||
emit("emptied",true);
|
||||
}
|
||||
}catch (error: any){
|
||||
alert(error);
|
||||
}
|
||||
})
|
||||
return { articles, convertDate, changeFavorite, showProfile, showArticle }
|
||||
return { convertDate, changeFavorite, showProfile, showArticle }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -26,28 +26,27 @@
|
||||
:class="{ active : globalActive }">Global Feed</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-if="isLoading">
|
||||
<div v-if="listsAreLoading">
|
||||
Loading articles...
|
||||
</div>
|
||||
<div v-if="isEmpty">
|
||||
No articles are here... yet.
|
||||
</div>
|
||||
</div>
|
||||
<article-list
|
||||
v-if="isLogin && feedActive"
|
||||
:value="isLogin"
|
||||
:value2="isEmpty"
|
||||
@loading="onChangeLoading"
|
||||
@emptied="emptyCheck">
|
||||
</article-list>
|
||||
<article-list-global
|
||||
v-else
|
||||
:isLoading="isLoading"
|
||||
:isEmpty="isEmpty"
|
||||
:globalActive="globalActive"
|
||||
@loading="onChangeLoading"
|
||||
@emptied="emptyCheck">
|
||||
<div v-if="feedActive && isLogin">
|
||||
<article-list-feed v-for="(article,index) in articleLists"
|
||||
:key="article.slug"
|
||||
:article="article">
|
||||
</article-list-feed>
|
||||
</div>
|
||||
<div v-else>
|
||||
<article-list-global v-for="(article,index) in articleLists"
|
||||
:key="article.slug"
|
||||
:index="index"
|
||||
@update:Favorite="updateFavorite"
|
||||
:article="article">
|
||||
</article-list-global>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="sidebar">
|
||||
@@ -55,9 +54,6 @@
|
||||
<tag-lists></tag-lists>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="test in articleLists">
|
||||
{{test}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -78,48 +74,49 @@ import { useStore } from "vuex";
|
||||
export default {
|
||||
name: "TheHome",
|
||||
components: {
|
||||
'article-list': articleList,
|
||||
'article-list-feed': articleList,
|
||||
'article-list-global': articleListGlobal,
|
||||
'tag-lists': tagLists,
|
||||
'pagination-component': pagination,
|
||||
},
|
||||
setup(){
|
||||
const isLoading = ref(true);
|
||||
const isEmpty = ref(false);
|
||||
const store = useStore();
|
||||
const isLogin = store.state.token == '' ? false : true;
|
||||
const isLogin = ref(false);
|
||||
const feedActive = ref(true);
|
||||
const globalActive = ref(false);
|
||||
|
||||
const currentPage = ref(1);
|
||||
const rowsPerPage = ref(20);
|
||||
|
||||
const { articleLists, listsAreLoading, loadLists, numberOfPages } = usePaginationApi(currentPage, rowsPerPage);
|
||||
const { articleLists, listsAreLoading, isEmpty, loadLists, feedLists, numberOfPages } = usePaginationApi(currentPage, rowsPerPage);
|
||||
|
||||
const onChangeLoading = (val : boolean) => {
|
||||
isLoading.value = val;
|
||||
}
|
||||
const emptyCheck = (val: boolean) => {
|
||||
isEmpty.value = val;
|
||||
}
|
||||
|
||||
const feedSelect = () => {
|
||||
const feedSelect = async () => {
|
||||
feedActive.value=true;
|
||||
globalActive.value=false;
|
||||
isEmpty.value=false;
|
||||
isLoading.value=true;
|
||||
await feedLists();
|
||||
}
|
||||
|
||||
const globalSelect = () => {
|
||||
const globalSelect = async () => {
|
||||
feedActive.value=false;
|
||||
globalActive.value=true;
|
||||
isEmpty.value=false;
|
||||
isLoading.value=true;
|
||||
await loadLists();
|
||||
}
|
||||
const updateFavorite = async (index: number) => {
|
||||
console.log("index" , index);
|
||||
}
|
||||
|
||||
onMounted(async () => loadLists())
|
||||
onMounted(async () => {
|
||||
isLogin.value = store.state.token ? true : false;
|
||||
if(isLogin.value == false) {
|
||||
await loadLists();
|
||||
globalActive.value = true;
|
||||
}else{
|
||||
await feedLists();
|
||||
feedActive.value = true;
|
||||
}
|
||||
})
|
||||
|
||||
return { isLoading, isEmpty, isLogin, currentPage, rowsPerPage, numberOfPages, feedActive, globalActive, articleLists, onChangeLoading, emptyCheck, feedSelect, globalSelect };
|
||||
return { listsAreLoading, isEmpty, isLogin, currentPage, rowsPerPage, numberOfPages, feedActive, globalActive, articleLists, updateFavorite, feedSelect, globalSelect };
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user