通过 rest api 按类别获取 post - wordpress 和 vuejs
fetch post by categories via rest api - wordpress and vuejs
我正在尝试通过 Wordpress Restful API 获取一些 post 数据。到目前为止,我取得的成就是:
- 加载应用时,获取 post 秒的第一页。
- 然后,如果用户点击按钮 'load more posts',另一个页面 posts
被获取,直到没有更多的 post 显示
首先,我在 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
}
这是我显示 posts:
的组件
<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 个 post通过 Rest api 分类(参见 searchByCategory
方法)。
现在,我希望 load more
按钮升级 post 的列表,除了已经存在的那些之外,还只包含那些具有相同类别的列表。
这可能吗,或者我必须重新考虑我的实施方式?
此实现仅适用于 post 的总量,
不管类别。
我无法修改 php,我只能使用 vue。
谢谢!
好的我就这样解决了。正如 Sphinx 所建议的,当类别更改时,我将 post 的数组重置为 0,并发出另一个请求,同时使用已经存在的 post 数量的偏移基数。似乎这行得通:
组件:
<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))
}
我正在尝试通过 Wordpress Restful API 获取一些 post 数据。到目前为止,我取得的成就是:
- 加载应用时,获取 post 秒的第一页。
- 然后,如果用户点击按钮 'load more posts',另一个页面 posts 被获取,直到没有更多的 post 显示
首先,我在 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
}
这是我显示 posts:
的组件 <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 个 post通过 Rest api 分类(参见 searchByCategory
方法)。
现在,我希望 load more
按钮升级 post 的列表,除了已经存在的那些之外,还只包含那些具有相同类别的列表。
这可能吗,或者我必须重新考虑我的实施方式?
此实现仅适用于 post 的总量, 不管类别。
我无法修改 php,我只能使用 vue。
谢谢!
好的我就这样解决了。正如 Sphinx 所建议的,当类别更改时,我将 post 的数组重置为 0,并发出另一个请求,同时使用已经存在的 post 数量的偏移基数。似乎这行得通:
组件:
<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))
}