今天多新增一些功能,好讓我們的 Recently.vue 有點作用。
首先去到 AddArticle.vue 將我們的 template 多新增可以添加文章 tags 的部分。
<template>
<b-row>
<b-modal id="modal-1" title="下一步?" @ok="F_updateArticle(articleData, addOrUpdate , $attrs)">
<p class="my-4">如要{{ addOrUpdate }}文章請按確認</p>
</b-modal>
<b-col cols="12">
<label for="input-large">文章標題:</label>
<b-form-input id="input-large" size="lg" placeholder="請輸入文章標題" v-model="title"></b-form-input>
</b-col>
<b-col cols="12">
<MarkdownPro
@on-save="updateData"
v-model="value"
></MarkdownPro>
</b-col>
<b-col cols="12">
<div>
<label for="tags-pills">請輸入文章標籤</label>
<b-form-tags
input-id="tags-pills"
v-model="tags"
tag-variant="info"
size="lg"
separator=" ,;"
placeholder="可以使用空格、逗號、分號、enter 鍵來輸入標籤"
remove-on-delete
></b-form-tags>
<p class="mt-2">Value: {{ tags }}</p>
</div>
</b-col>
<b-col class="mt-2"><b-button v-b-modal.modal-1 variant="primary">點擊{{ addOrUpdate }}文章</b-button></b-col>
</b-row>
</template>
<script>
...
data () {
return {
articleData: {},
title: '',
value: '',
addOrUpdate: '新增',
tags: [],
createdAt: null
}
},
methods: {
updateData (saveEventInfo) {
const splitter = '<!-- more -->'
const self = this
if (saveEventInfo.value.indexOf(splitter) === -1) {
saveEventInfo.value = saveEventInfo.value.slice(0, 20) + splitter + saveEventInfo.value.slice(20)
}
saveEventInfo.stopOnMore = saveEventInfo.value.split(splitter)
saveEventInfo.stopOnMore = saveEventInfo.stopOnMore[0] + '...'
if (this.addOrUpdate !== '更新') this.createdAt = new Date().getTime()
this.F_showUser().then(res => {
this.articleData.contentData = {
title: self.title,
createdAt: self.createdAt,
value: saveEventInfo.value,
stopOnMore: saveEventInfo.stopOnMore,
html: saveEventInfo.html
}
this.articleData.authorInfo = {
displayName: res.displayName,
email: res.email,
uid: res.uid,
photoURL: res.photoURL
}
this.articleData.aboutCategory = {
tags: self.tags
}
})
}
}
</script>
給文章添加標題並上傳文章看看,應該會上傳陣列,我們後面就用這個陣列來渲染當作可點擊 tag。
// ArticleList.vue
<template>
<div class="article__blocks">
<div class="article__blocks__block" v-for="article in filterPosts" :key="article.id">
<div class="article__blocks__block_title">
<h3>{{ article.contentData.title }}</h3>
</div>
<div class="article__blocks__block_content">
<p>{{ article.aboutCategory.tags }}</p>
</div>
<div class="article__blocks__block_tags">
<p>{{ article.contentData.stopOnMore }}</p>
</div>
<div class="goto" @click="gotoArticle(article.id)" :data-articleId="article.id">
<p> >> 繼續閱讀</p>
</div>
</div>
<div class="article__tags--expose" v-show="false">
// 用插槽暴漏出去我們的所有 tag
<slot name="tagsFiltered" :tagsFiltered="tagsFiltered"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'ArticleList',
props: ['chooseTag'],
data () {
return {
mainPosts: [],
tags: [],
tagsFiltered: null,
filterPosts: []
}
},
watch: {
// 用來處理父層 bind 進來的值,用於顯示相對應 tag 的文章
chooseTag: function (newVal, oldVal) {
if (newVal === 'all') {
this.filterPosts = this.mainPosts
return 'done'
}
const filterPost = this.mainPosts.filter(ele => {
return ele.aboutCategory.tags.indexOf(newVal) !== -1
})
this.filterPosts = filterPost
}
},
created () {
const buffer = []
this.F_getCollectionDocsSort('posts', { where: 'contentData.createdAt', order: 'desc' }).then(docs => {
// this.mainPosts 成為我們回復顯示所有文章的原始資料
this.mainPosts = docs
// 另外拷貝一份出去作為過濾文章使用,v-for 掛載這個
this.filterPosts = JSON.parse(JSON.stringify(this.mainPosts))
this.tags = this.filterPosts.map(ele => {
return ele.aboutCategory.tags
})
this.tags.forEach(ele => [
buffer.push(...ele)
])
// 放入 Set 中自動過濾所有重複 tag
this.tagsFiltered = new Set(buffer)
// 轉回陣列
this.tagsFiltered = Array.from(this.tagsFiltered)
})
}
}
</script>
// Home.vue
<template>
<b-container class="pageHome">
<b-row>
<b-col cols="9">
<ArticleList
:chooseTag="storeChooseTags"
>
<!-- 先暴露值出來丟入方法改變父層作用域 storeAllTags,儲存所有 tag -->
<template v-slot:tagsFiltered="{tagsFiltered: tags}">
{{ getChildValue(tags) }}
</template>
</ArticleList>
</b-col>
<b-col cols="3">
<!-- 在綁定所有 tags 給 Recently.vue -->
<Recently
:tags="storeAllTags"
>
<template v-slot:chooseTagDispose="{chooseTagDispose: tag}">
{{ getChildSelectTag(tag) }}
</template>
</Recently>
</b-col>
</b-row>
</b-container>
</template>
<script>
// @ is an alias to /src
import ArticleList from '@/components/ArticleList.vue'
import Recently from '@/components/Recently.vue'
export default {
name: 'Home',
data () {
return {
storeAllTags: [],
storeChooseTags: null
}
},
components: {
ArticleList,
Recently
},
methods: {
getChildValue (value) {
this.storeAllTags = value
},
getChildSelectTag (tag) {
this.storeChooseTags = tag
}
}
}
</script>
<template>
<div class="recentlyArticle">
<b-list-group>
<b-list-group-item @click="chooseTagDispose='all'" button>
所有文章
</b-list-group-item>
<b-list-group-item @click="chooseTagDispose=tag" v-for="tag in tags" :key="tag" class="d-flex justify-content-between align-items-center" button>
{{ tag }}
</b-list-group-item>
</b-list-group>
<slot v-show="false" name="chooseTagDispose" :chooseTagDispose="chooseTagDispose"></slot>
</div>
</template>
<script>
export default {
name: 'Recently',
props: ['tags'],
data () {
return {
chooseTagDispose: null
}
}
}
</script>
再看到 Home.vue,可以看見我們把暴漏出來每次 click 的值再綁定進 ArticleList,裡面有個 watch 還記得嗎 ? 每次都會去依照丟進來的 tag 進行過濾,並返回相對應的文章們,到這邊結束,我們即可透過點擊 Recently.vue 渲染出來的 tag 進行文章的切換,你也可以把這些 tag 改成其他你喜歡的樣式,比如說 button 等等。
// Home.vue 沒改變,換註解方便解說而已
<template>
<b-container class="pageHome">
<b-row>
<b-col cols="9">
<!-- 再把每次改變的 storeChooseTags 都 bind 進 ArticleList -->
<ArticleList
:chooseTag="storeChooseTags"
>
<template v-slot:tagsFiltered="{tagsFiltered: tags}">
{{ getChildValue(tags) }}
</template>
</ArticleList>
</b-col>
<b-col cols="3">
<Recently
:tags="storeAllTags"
>
<!-- 先暴漏出來每次 click 的 tag 並丟進方法改變 storeChooseTags 值 -->
<template v-slot:chooseTagDispose="{chooseTagDispose: tag}">
{{ getChildSelectTag(tag) }}
</template>
</Recently>
</b-col>
</b-row>
</b-container>
</template>
<script>
// @ is an alias to /src
import ArticleList from '@/components/ArticleList.vue'
import Recently from '@/components/Recently.vue'
export default {
name: 'Home',
data () {
return {
storeAllTags: [],
storeChooseTags: null
}
},
components: {
ArticleList,
Recently
},
methods: {
getChildValue (value) {
this.storeAllTags = value
},
getChildSelectTag (tag) {
this.storeChooseTags = tag
}
}
}
</script>
沒事也可以逛逛我們其他團隊成員的文章啦 ~~
eien_zheng: 前端小嘍嘍的Golang學習旅程_The journey of learning Golang 系列
PollyPO技術: 前端設計轉前端工程師-JS踩坑雜記 30 天 系列
阿電: 忍住不打牌位,只要30天VueJS帶你上A牌 系列
喬依司: 實作經典 JavaScript 30 系列