add post page
This commit is contained in:
parent
baf0b4e476
commit
576fa40506
@ -7,6 +7,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="post__btns">
|
<div class="post__btns">
|
||||||
|
<my-button @click="$router.push(`/posts/${post.id}`)">
|
||||||
|
Открыть
|
||||||
|
</my-button>
|
||||||
|
|
||||||
<my-button @click="$emit('removePost', post)">
|
<my-button @click="$emit('removePost', post)">
|
||||||
Удалить
|
Удалить
|
||||||
</my-button>
|
</my-button>
|
||||||
@ -36,4 +40,9 @@ export default {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post__btns {
|
||||||
|
display: flex;
|
||||||
|
column-gap: 10px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,177 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1>Страница постов</h1>
|
Пост по ID = {{$route.params.id}}
|
||||||
|
|
||||||
<my-input v-model="searchQuery" placeholder="Поиск" class="search"/>
|
|
||||||
|
|
||||||
<div class="app__btns">
|
|
||||||
<my-button @click="showCreateDialog" class="createBtn">
|
|
||||||
Создать пост
|
|
||||||
</my-button>
|
|
||||||
|
|
||||||
<my-select v-model="selectedSort" :options="sortOptions"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<my-dialog v-model:show="dialogVisible">
|
|
||||||
<post-form @createPost="createPost" />
|
|
||||||
</my-dialog>
|
|
||||||
|
|
||||||
<div v-if="isPostLoading" style="margin-top: 15px">Loading...</div>
|
|
||||||
<post-list v-else :posts="sortedAndSearchedPosts" @removePost="removePost" class="postList"/>
|
|
||||||
<div ref="observer" class="observer"></div>
|
|
||||||
<!-- <my-pagination-->
|
|
||||||
<!-- :currentPage="page"-->
|
|
||||||
<!-- :totalPages="totalPages"-->
|
|
||||||
<!-- @changePage="changePage"-->
|
|
||||||
<!-- />-->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import PostForm from '@/components/PostForm.vue';
|
|
||||||
import PostList from '@/components/PostList.vue';
|
|
||||||
import axios from 'axios';
|
|
||||||
import MyPagination from '@/components/ui/Pagination.vue';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
|
||||||
MyPagination,
|
|
||||||
PostForm,
|
|
||||||
PostList
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
posts: [],
|
|
||||||
dialogVisible: false,
|
|
||||||
isPostLoading: false,
|
|
||||||
selectedSort: '',
|
|
||||||
sortOptions: [
|
|
||||||
{value: 'title', name: 'По названию'},
|
|
||||||
{value: 'body', name: 'По описанию'}
|
|
||||||
],
|
|
||||||
searchQuery: '',
|
|
||||||
page: 1,
|
|
||||||
limit: 10,
|
|
||||||
totalPages: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
createPost(newPost) {
|
|
||||||
this.posts.push(newPost);
|
|
||||||
this.dialogVisible = false;
|
|
||||||
},
|
|
||||||
removePost(post) {
|
|
||||||
this.posts = this.posts.filter(p => p.id !== post.id)
|
|
||||||
},
|
|
||||||
showCreateDialog() {
|
|
||||||
this.dialogVisible = true;
|
|
||||||
},
|
|
||||||
async fetchPosts() {
|
|
||||||
try {
|
|
||||||
const { data, headers } = await axios.get(`https://jsonplaceholder.typicode.com/posts`, {
|
|
||||||
params: {
|
|
||||||
_limit: this.limit,
|
|
||||||
_page: this.page
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.posts = data;
|
|
||||||
this.totalPages = Math.ceil(headers['x-total-count'] / this.limit);
|
|
||||||
} catch (e) {
|
|
||||||
alert(e.message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async loadMorePost() {
|
|
||||||
this.page += 1
|
|
||||||
try {
|
|
||||||
const { data, headers } = await axios.get(`https://jsonplaceholder.typicode.com/posts`, {
|
|
||||||
params: {
|
|
||||||
_limit: this.limit,
|
|
||||||
_page: this.page,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.posts.push(...data);
|
|
||||||
this.totalPages = Math.ceil(headers['x-total-count'] / this.limit);
|
|
||||||
} catch (e) {
|
|
||||||
alert(e.message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// changePage(newPage) {
|
|
||||||
// this.page = newPage;
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
async mounted() {
|
|
||||||
this.isPostLoading = true;
|
|
||||||
await this.fetchPosts()
|
|
||||||
this.isPostLoading = false
|
|
||||||
|
|
||||||
|
|
||||||
console.log();
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
rootMargin: "0px",
|
|
||||||
threshold: 1.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const callback = (entries) => {
|
|
||||||
if (entries[0].isIntersecting && this.page < this.totalPages) {
|
|
||||||
this.loadMorePost();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const observer = new IntersectionObserver(callback, options);
|
|
||||||
|
|
||||||
observer.observe(this.$refs.observer)
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
sortedPost() {
|
|
||||||
return [...this.posts].sort((post1, post2) => {
|
|
||||||
return post1?.[this.selectedSort]?.localeCompare(post2?.[this.selectedSort])
|
|
||||||
})
|
|
||||||
},
|
|
||||||
sortedAndSearchedPosts() {
|
|
||||||
return this.sortedPost.filter((post) => post.title.toLowerCase().includes(this.searchQuery.toLowerCase()))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
// selectedSort(newValue) {
|
|
||||||
// this.posts.sort((post1, post2) => {
|
|
||||||
// return post1[newValue].localeCompare(post2[newValue])
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
dialogVisible(newValue) {
|
|
||||||
if (newValue) {
|
|
||||||
document.body.style.overflow = 'hidden';
|
|
||||||
} else {
|
|
||||||
document.body.style.overflow = 'auto';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// page() {
|
|
||||||
// this.fetchPosts()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="scss" scoped>
|
||||||
.createBtn {
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.postList {
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app__btns {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search {
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.observer {
|
|
||||||
height: 0px;
|
|
||||||
background: teal;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
177
src/pages/PostsPage.vue
Normal file
177
src/pages/PostsPage.vue
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1>Страница постов</h1>
|
||||||
|
|
||||||
|
<my-input v-model="searchQuery" placeholder="Поиск" class="search"/>
|
||||||
|
|
||||||
|
<div class="app__btns">
|
||||||
|
<my-button @click="showCreateDialog" class="createBtn">
|
||||||
|
Создать пост
|
||||||
|
</my-button>
|
||||||
|
|
||||||
|
<my-select v-model="selectedSort" :options="sortOptions"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<my-dialog v-model:show="dialogVisible">
|
||||||
|
<post-form @createPost="createPost" />
|
||||||
|
</my-dialog>
|
||||||
|
|
||||||
|
<div v-if="isPostLoading" style="margin-top: 15px">Loading...</div>
|
||||||
|
<post-list v-else :posts="sortedAndSearchedPosts" @removePost="removePost" class="postList"/>
|
||||||
|
<div ref="observer" class="observer"></div>
|
||||||
|
<!-- <my-pagination-->
|
||||||
|
<!-- :currentPage="page"-->
|
||||||
|
<!-- :totalPages="totalPages"-->
|
||||||
|
<!-- @changePage="changePage"-->
|
||||||
|
<!-- />-->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import PostForm from '@/components/PostForm.vue';
|
||||||
|
import PostList from '@/components/PostList.vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
import MyPagination from '@/components/ui/Pagination.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
MyPagination,
|
||||||
|
PostForm,
|
||||||
|
PostList
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
posts: [],
|
||||||
|
dialogVisible: false,
|
||||||
|
isPostLoading: false,
|
||||||
|
selectedSort: '',
|
||||||
|
sortOptions: [
|
||||||
|
{value: 'title', name: 'По названию'},
|
||||||
|
{value: 'body', name: 'По описанию'}
|
||||||
|
],
|
||||||
|
searchQuery: '',
|
||||||
|
page: 1,
|
||||||
|
limit: 10,
|
||||||
|
totalPages: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
createPost(newPost) {
|
||||||
|
this.posts.push(newPost);
|
||||||
|
this.dialogVisible = false;
|
||||||
|
},
|
||||||
|
removePost(post) {
|
||||||
|
this.posts = this.posts.filter(p => p.id !== post.id)
|
||||||
|
},
|
||||||
|
showCreateDialog() {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
},
|
||||||
|
async fetchPosts() {
|
||||||
|
try {
|
||||||
|
const { data, headers } = await axios.get(`https://jsonplaceholder.typicode.com/posts`, {
|
||||||
|
params: {
|
||||||
|
_limit: this.limit,
|
||||||
|
_page: this.page
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.posts = data;
|
||||||
|
this.totalPages = Math.ceil(headers['x-total-count'] / this.limit);
|
||||||
|
} catch (e) {
|
||||||
|
alert(e.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async loadMorePost() {
|
||||||
|
this.page += 1
|
||||||
|
try {
|
||||||
|
const { data, headers } = await axios.get(`https://jsonplaceholder.typicode.com/posts`, {
|
||||||
|
params: {
|
||||||
|
_limit: this.limit,
|
||||||
|
_page: this.page,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.posts.push(...data);
|
||||||
|
this.totalPages = Math.ceil(headers['x-total-count'] / this.limit);
|
||||||
|
} catch (e) {
|
||||||
|
alert(e.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// changePage(newPage) {
|
||||||
|
// this.page = newPage;
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
this.isPostLoading = true;
|
||||||
|
await this.fetchPosts()
|
||||||
|
this.isPostLoading = false
|
||||||
|
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
rootMargin: "0px",
|
||||||
|
threshold: 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const callback = (entries) => {
|
||||||
|
if (entries[0].isIntersecting && this.page < this.totalPages) {
|
||||||
|
this.loadMorePost();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const observer = new IntersectionObserver(callback, options);
|
||||||
|
|
||||||
|
observer.observe(this.$refs.observer)
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
sortedPost() {
|
||||||
|
return [...this.posts].sort((post1, post2) => {
|
||||||
|
return post1?.[this.selectedSort]?.localeCompare(post2?.[this.selectedSort])
|
||||||
|
})
|
||||||
|
},
|
||||||
|
sortedAndSearchedPosts() {
|
||||||
|
return this.sortedPost.filter((post) => post.title.toLowerCase().includes(this.searchQuery.toLowerCase()))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// selectedSort(newValue) {
|
||||||
|
// this.posts.sort((post1, post2) => {
|
||||||
|
// return post1[newValue].localeCompare(post2[newValue])
|
||||||
|
// })
|
||||||
|
// },
|
||||||
|
dialogVisible(newValue) {
|
||||||
|
if (newValue) {
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
} else {
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// page() {
|
||||||
|
// this.fetchPosts()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.createBtn {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postList {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app__btns {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.observer {
|
||||||
|
height: 0px;
|
||||||
|
background: teal;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,7 +1,8 @@
|
|||||||
import Main from '@/pages/Main.vue';
|
import Main from '@/pages/Main.vue';
|
||||||
import { createRouter, createWebHistory } from 'vue-router';
|
import { createRouter, createWebHistory } from 'vue-router';
|
||||||
import PostPage from '@/pages/PostPage.vue';
|
import PostsPage from '@/pages/PostsPage.vue';
|
||||||
import AboutPage from '@/pages/AboutPage.vue';
|
import AboutPage from '@/pages/AboutPage.vue';
|
||||||
|
import PostPage from '@/pages/PostPage.vue';
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
@ -10,6 +11,10 @@ const routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/posts',
|
path: '/posts',
|
||||||
|
component: PostsPage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/posts/:id',
|
||||||
component: PostPage,
|
component: PostPage,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user