feat : Home Article ReRender Success and Pagination Template add

This commit is contained in:
kms
2022-12-04 18:12:53 +09:00
parent 828c744285
commit 20487f5a46
4 changed files with 173 additions and 131 deletions

View File

@@ -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
};
}

View File

@@ -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 }
}
})

View File

@@ -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>

View File

@@ -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>