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 { ref, Ref } from "@vue/reactivity";
import { listArticles } from "@/api/index"; import { listArticles, feedArticle } from "@/api/index";
import { usePagination } from "@/ts/usePagination"; import { usePagination } from "@/ts/usePagination";
export interface Todo { export interface ArticleList {
id: number; slug: string,
title: string; title: string,
description: string,
favorited: boolean,
favoritesCount: number,
createdAt: string,
author: {
username: string,
image: string
}
} }
export function usePaginationApi( export function usePaginationApi(
currentPage: Ref<number>, currentPage: Ref<number>,
rowsPerPage?: Ref<number> rowsPerPage?: Ref<number>
) { ) {
const articleLists: Ref<Todo[]> = ref([]); const articleLists: Ref<ArticleList[]> = ref([]);
const listsAreLoading = ref(false); const listsAreLoading = ref(false);
const isEmpty = ref(false);
const { paginatedArray, numberOfPages } = usePagination<Todo>({ const { paginatedArray, numberOfPages } = usePagination<ArticleList>({
rowsPerPage, rowsPerPage,
arrayToPaginate: articleLists, arrayToPaginate: articleLists,
currentPage 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 () => { const loadLists = async () => {
listsAreLoading.value = true; listsAreLoading.value = true;
isEmpty.value = false;
try { try {
const { data } = await listArticles(); const { data } = await listArticles();
articleLists.value = data.articles; articleLists.value = data.articles;
console.log(articleLists.value); if(data.articlesCount == 0){
isEmpty.value = true;
}
} catch (err) { } catch (err) {
console.log(err); console.log(err);
} finally { } finally {
@@ -39,7 +67,9 @@ export function usePaginationApi(
return { return {
articleLists: paginatedArray, articleLists: paginatedArray,
loadLists, loadLists,
feedLists,
listsAreLoading, listsAreLoading,
isEmpty,
numberOfPages numberOfPages
}; };
} }

View File

@@ -1,45 +1,46 @@
<template> <template>
<div v-for = "art in articles.article"> <div class="article-preview">
<div class="article-preview"> <div class="article-meta">
<div class="article-meta"> <a href="javascript:(0)" @click="showProfile(article.author.username)"><img :src="article.author.image"/></a>
<a href="profile.html"><img :src="art.author.image"/></a> <div class="info">
<div class="info"> <a class="author"
<a href="" class="author">{{art.author.username}}</a> href="javascript:void(0)"
<span class="date">{{convertDate(art.createdAt)}}</span> @click="showProfile(article.author.username)">{{article.author.username}}</a>
</div> <span class="date">{{convertDate(article.createdAt)}}</span>
<button class="btn btn-outline-primary btn-sm pull-xs-right">
<i class="ion-heart"></i> {{art.favoritesCount}}
</button>
</div> </div>
<a href="" class="preview-link"> <button class="btn btn-outline-primary btn-sm pull-xs-right">
<h1>{{art.title}}</h1> <i class="ion-heart" @click="changeFavorite(article.slug, article.favorited)"></i> {{article.favoritesCount}}
<p>{{art.description}}</p> </button>
<span>Read more...</span>
</a>
</div> </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> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import {onMounted, reactive, ref, defineComponent} from "vue"; import { defineComponent } from "vue";
import {useStore} from "vuex";
import axios from "axios";
import convertDate from "@/ts/common"; 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({ export default defineComponent({
name: "ArticleListFeed", name: "ArticleListFeed",
props:{ props: {
isEmpty: Boolean, article: {
isLoading: Boolean type: Object,
}, default: () => {
setup(props,{ emit }){ return {
const articles = reactive({
article:[
{
slug: "", slug: "",
title: "", title: "",
description: "", description: "",
favorited: false,
favoritesCount: 0, favoritesCount: 0,
createdAt: "", createdAt: "",
author: { author: {
@@ -47,24 +48,45 @@ export default defineComponent({
image: "" 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> <template>
<div v-for = "art in articles.article">
<div class="article-preview"> <div class="article-preview">
<div class="article-meta"> <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"> <div class="info">
<a class="author" <a class="author"
href="javascript:void(0)" href="javascript:void(0)"
@click="showProfile(art.author.username)">{{art.author.username}}</a> @click="showProfile(article.author.username)">{{article.author.username}}</a>
<span class="date">{{convertDate(art.createdAt)}}</span> <span class="date">{{convertDate(article.createdAt)}}</span>
</div> </div>
<button class="btn btn-outline-primary btn-sm pull-xs-right"> <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> </button>
</div> </div>
<a href="javascript:(0)" <a href="javascript:(0)"
class="preview-link" class="preview-link"
@click="showArticle(art.slug)"> @click="showArticle(article.slug)">
<h1>{{art.title}}</h1> <h1>{{article.title}}</h1>
<p>{{art.description}}</p> <p>{{article.description}}</p>
<span>Read more...</span> <span>Read more...</span>
</a> </a>
</div> </div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import {onMounted, reactive, defineComponent } from "vue"; import { defineComponent } from "vue";
import router from "@/router"; import router from "@/router";
import convertDate from '@/ts/common'; import convertDate from '@/ts/common';
import {favoriteArticle, listArticles, unFavoriteArticle} from "@/api"; import { useStore } from "vuex";
import { favoriteArticle, unFavoriteArticle } from "@/api";
export default defineComponent({ export default defineComponent({
name: "ArticleListGlobal", name: "ArticleListGlobal",
props:{ props:{
isLoading: Boolean, index: Number,
isEmpty: Boolean, article: {
globalActive: Boolean, type: Object,
}, default: () => {
setup(props,{emit}) { return {
const articles = reactive({
article:[
{
slug: "", slug: "",
title: "", title: "",
description: "", description: "",
@@ -52,9 +48,12 @@ export default defineComponent({
image: "" image: ""
} }
} }
], }
articlesCount: ""} }
) },
setup(props) {
const store = useStore();
const token = store.state.token;
const showProfile = (username: string) => { const showProfile = (username: string) => {
router.push({ router.push({
@@ -71,29 +70,23 @@ export default defineComponent({
} }
const changeFavorite = async (slug: string, favorite : boolean) => { const changeFavorite = async (slug: string, favorite : boolean) => {
if(favorite){ if(token == ''){
await unFavoriteArticle(slug); await router.push({name:"Login"});
return;
}else{ }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;
}
} }
} }
return { convertDate, changeFavorite, showProfile, showArticle }
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 }
} }
}) })
</script> </script>

View File

@@ -26,28 +26,27 @@
:class="{ active : globalActive }">Global Feed</a> :class="{ active : globalActive }">Global Feed</a>
</li> </li>
</ul> </ul>
<div v-if="isLoading"> <div v-if="listsAreLoading">
Loading articles... Loading articles...
</div> </div>
<div v-if="isEmpty"> <div v-if="isEmpty">
No articles are here... yet. No articles are here... yet.
</div> </div>
</div> </div>
<article-list <div v-if="feedActive && isLogin">
v-if="isLogin && feedActive" <article-list-feed v-for="(article,index) in articleLists"
:value="isLogin" :key="article.slug"
:value2="isEmpty" :article="article">
@loading="onChangeLoading" </article-list-feed>
@emptied="emptyCheck"> </div>
</article-list> <div v-else>
<article-list-global <article-list-global v-for="(article,index) in articleLists"
v-else :key="article.slug"
:isLoading="isLoading" :index="index"
:isEmpty="isEmpty" @update:Favorite="updateFavorite"
:globalActive="globalActive" :article="article">
@loading="onChangeLoading"
@emptied="emptyCheck">
</article-list-global> </article-list-global>
</div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<div class="sidebar"> <div class="sidebar">
@@ -55,9 +54,6 @@
<tag-lists></tag-lists> <tag-lists></tag-lists>
</div> </div>
</div> </div>
<div v-for="test in articleLists">
{{test}}
</div>
</div> </div>
</div> </div>
@@ -78,48 +74,49 @@ import { useStore } from "vuex";
export default { export default {
name: "TheHome", name: "TheHome",
components: { components: {
'article-list': articleList, 'article-list-feed': articleList,
'article-list-global': articleListGlobal, 'article-list-global': articleListGlobal,
'tag-lists': tagLists, 'tag-lists': tagLists,
'pagination-component': pagination, 'pagination-component': pagination,
}, },
setup(){ setup(){
const isLoading = ref(true);
const isEmpty = ref(false);
const store = useStore(); const store = useStore();
const isLogin = store.state.token == '' ? false : true; const isLogin = ref(false);
const feedActive = ref(true); const feedActive = ref(true);
const globalActive = ref(false); const globalActive = ref(false);
const currentPage = ref(1); const currentPage = ref(1);
const rowsPerPage = ref(20); 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) => { const feedSelect = async () => {
isLoading.value = val;
}
const emptyCheck = (val: boolean) => {
isEmpty.value = val;
}
const feedSelect = () => {
feedActive.value=true; feedActive.value=true;
globalActive.value=false; globalActive.value=false;
isEmpty.value=false; await feedLists();
isLoading.value=true;
} }
const globalSelect = () => { const globalSelect = async () => {
feedActive.value=false; feedActive.value=false;
globalActive.value=true; globalActive.value=true;
isEmpty.value=false; await loadLists();
isLoading.value=true; }
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> </script>