Получить пост по категориям через остальные API - WordPress и Vuejs - PullRequest
0 голосов
/ 27 апреля 2018

Я пытаюсь получить данные поста через API Wordpress Restful. До сих пор я достиг:

  1. когда приложение загружено, получите первую страницу постов.
  2. тогда, если пользователь нажмет кнопку «загрузить больше постов», появится еще одна страница постов извлекается, пока больше нет сообщений для отображения

Прежде всего я создаю эту функцию в файле main.js:

Array.prototype.next = function*(){
  for(let item of this){
    yield item
  }
}

тогда в App.vue у меня есть это:

created(){
    this.$store.dispatch('setCategories') //grab posts categories
      .then(resolve=> this.$store.dispatch('setPostsCount')) //grab the number of post pages and the total number of posts
        .then(resolve=>this.$store.dispatch('loadPosts')) load the first page of posts
          .catch(err => console.log(err))
  }

это модуль магазина post.js:

  import axios from 'axios'

const postsRequest = axios.create({
    baseURL: 'https://wordpress-site/wp-json/wp/v2/posts'
  })






const state = {
    posts:[],
    filteredPosts:[],
    totalPages:null,
    totalPosts:null
}


const getters = {
    getPosts(state){
        return  state.posts
    },
    getFilteredPosts(state){
        return state.filteredPosts
    },
    getAllPostsPages(state){
        return state.totalPages
    },
    getAllPostsNumber(state){
        return state.totalPosts
    },
    getNextPage(state,getters){
        return getters.getAllPostsPages.next()
    }
}


const mutations = {
    'SET_POSTS_COUNT'(state,headers){
        state.totalPages = [...Array(parseInt(headers['x-wp-totalpages'])).keys()].map(page => page+1),
        state.totalPosts = parseInt(headers['x-wp-total']) //[...Array(parseInt(headers['x-wp-total'])).keys()]
    },
    'LOAD_POSTS'(state,posts){
        for(let post of posts){
            state.posts.push(post)
        }
        console.log(state.posts.length)   
    },
    'FILTER_BY_CATEGORY'(state,posts){
        state.filteredPosts = []
        state.filteredPosts = posts
    },
    'EMPTY_FILTERED_POSTS'(state){
        state.filteredPosts = []
    }
}


const actions = {
    setPostsCount({commit}){
        return new Promise((resolve,reject)=>{
            postsRequest.get().then(response => {
                commit('SET_POSTS_COUNT',response.headers)
                resolve()
            })  
        })

    },
    loadPosts({commit,getters}){
        let nextPage = getters.getNextPage.next()
        if(!nextPage.done){
            postsRequest.get(this.baseURL,{
                params:{
                    page: nextPage.value
                }
            }).then(response=> {

                commit('LOAD_POSTS',response.data)
            })
            .catch(err => console.log(err))
        }
    },
    loadPostsByCategory({commit,getters},index){
            postsRequest.get(this.baseURL,{
                params:{
                    categories:index
                }
            }).then(response => commit('FILTER_BY_CATEGORY',response.data))
                .catch(err => console.log(err))

    },
    loadPostsByCat({commit,getters},category){
        ...
    }
}

export default {
    state,
    getters,
    actions,
    mutations
  }

и это компонент, где я отображаю сообщения:

 <template>
    <div class="gy-read">
        <div @click="emptyFilteredPosts()">all</div>
        <div style="display:inline-block;margin-left:20px" v-for="category in categories" :key="category.id">
            <h3 @click="searchByCategory(category.index)">{{category.name}}</h3>
        </div>
        <div v-for="post in posts" :key="post.id">
            <h2>{{post.title.rendered}}</h2>
            <h4>{{post.date}}</h4>
            <h4>{{post.categories}}</h4>
        </div>
        <div>
            <button v-if="!currentCategory" @click="loadMorePosts()">load more</button>
            <button v-else @click="loadMorePostsByCat()">load more cat</button>
        </div>


    </div>

</template>

<script>

export default {
    data(){
        return{
            currentCategory:null,
        }
    },
 computed:{
     posts(){
         return this.$store.getters.getFilteredPosts.length ? this.$store.getters.getFilteredPosts : this.$store.getters.getPosts
     },
     categories(){
         return this.$store.getters.getCategories //this simply create an array of category index
     },
 },
 methods:{
     loadMorePosts(){
        this.$store.dispatch('loadPosts')

     },
     loadMorePostsByCat(){
         this.$store.dispatch('loadPostsByCat',this.currentCategory)
     },
     searchByCategory(index){
        this.currentCategory = index;
        this.$store.dispatch('loadPostsByCategory',index)
     },
     emptyFilteredPosts(){
         this.$store.commit('EMPTY_FILTERED_POSTS');
         this.currentCategory = null;
     }
 }

}
</script>

<style lang="scss">
    .gy-read{
        margin-top:150px;
    }
</style>

Теперь я застрял: когда пользователь нажимает на категорию, список state.posts заменяется списком state.filteredPosts, который содержит первые 10 сообщений, извлеченных по категории через Rest api (см. Метод searchByCategory ).

Теперь я хочу, чтобы кнопка load more обновляла список сообщений только теми, которые имеют ту же категорию, в дополнение к уже присутствующим.

Возможно ли это, или я должен пересмотреть мою реализацию?

Эта реализация отлично работает только с общим количеством сообщений, независимо от категории.

Я не могу изменить php, мне нужно работать только с vue.

Спасибо!

1 Ответ

0 голосов
/ 27 апреля 2018

Хорошо, я решил таким образом. Как предполагает Sphinx, при изменении категории я сбрасываю массив записей на 0 и делаю еще один запрос, используя также базу смещения количества уже существующих сообщений. Кажется, это работает:

компонент:

<template>
    <div class="gy-read">
        <div class="category">
            <div @click="currentCategory='all'">all</div>
            <div v-for="category in categories" :key="category.id">
                <h3 @click="currentCategory = category.index">{{category.name}}</h3>
            </div>
        </div>
        <div class="card__container">
            <router-link tag='div' class="card" :to="{name:'article', params: {slug: post.slug, post:post}}" v-for="post in posts" :key="post.id">
            <div :style="{ backgroundImage: 'url(' + post.better_featured_image.source_url+ ')' }" class="card__img"></div>
            <div class="card__content">
                <h2>{{post.title.rendered}}</h2>
                <span v-for="cat in post.categories" :key="cat">{{ cat}}</span>
            </div>  
        </router-link>
        </div>
        <div class="load">
            <button ref="button" v-if="posts.length" @click="loadMorePosts()">load more</button>
        </div>


    </div>

</template>

<script>
export default {
    data(){
        return{
            currentCategory:null,
        }
    },
    created(){

    },
 computed:{
     posts(){
         return this.$store.getters.getPosts
     },
     categories(){
         return this.$store.getters.getCategories
     }

 },
 watch:{
     currentCategory: function(cat){
         console.log(cat)
         this.$store.commit('RESET_POSTS')
         this.loadMorePosts()
     }

 },
 methods:{
     loadMorePosts(){
        this.$store.dispatch('loadPosts',this.currentCategory)
     },
 }

}
</script>

магазин

import axios from 'axios'


const state = {
    posts:[]
}


const getters = {
    getPosts(state){
        return  state.posts
    },
}

const mutations = {
    'LOAD_POSTS'(state,posts){
        for(let post of posts){
            state.posts.push(post)
        }  
    },
    'RESET_POSTS'(state){
        state.posts = []
    },
}


const actions = {
    loadPosts({commit,getters},category){
            axios.get('/posts',{
                params:{
                    categories: category === 'all' ? null : category,
                    offset: getters.getPosts.length
                }
            }).then(response=> {
                if(response.data.length){
                    console.log(response.data)
                    commit('LOAD_POSTS',response.data)
                }else{
                    //this._vm.$emit('noMorePosts',null)

                }

            })
            .catch(err => console.log(err))



    }
}

export default {
    state,
    getters,
    actions,
    mutations
  }

App.vue создал крючок:

created(){
    this.$store.dispatch('setCategories')
        .then(resolve=>this.$store.dispatch('loadPosts','all'))
          .catch(err => console.log(err))
  }
...