使用vue.js來搭建一個高仿的CNODE社區(qū)
1. cnnode社區(qū)的基本架構
項目模塊組件:
Header 頭部模塊
PostList 列表模塊
Article 文章模塊
Slider側邊欄模塊
UserInfo用戶個人中心模塊
Pagination分頁組件的開發(fā)
主要用到的技術棧有:
vue.js計算屬性
vue.js的內置指令和事件的綁定
vue.js的自定義事件和觸發(fā)
vue-router路由的跳轉和監(jiān)聽
父子組件之間的數(shù)據(jù)傳遞,
2.1 Header組件
[圖片上傳失敗...(image-d6cfcc-1563502172085)]
- 將項目中要用到的圖片和logo都存入assets文件夾中
- 創(chuàng)建一個Header組件棠众,用img標簽引入存儲在assets文件中的logo
- 在li標簽分別寫出:新手入門、API王带、關于享言、注冊、登錄
- 將組件引入App.vue纫事,就可以在頁面顯示
<template>
<div class="header">
<img src="../assets/cnodejs_light.svg" alt="">
<ul>
<li><a href="#">首頁</a></li>
<li><a href="#">新手入門</a></li>
<li><a href="#">API</a></li>
<li><a href="#">關于</a></li>
<li><a href="#">注冊</a></li>
<li><a href="#">登錄</a></li>
</ul>
</div>
</template>
<script>
export default {
name: "Header"
}
</script>
<style scoped>
.header{
background-color: #444;
height: 50px;
}
img{
max-width: 120px;
margin-left: 50px;
margin-top: 10px;
}
ul{
list-style: none;
float: right;
margin: 4px;
}
li{
display: inline-block;
padding: 10px 15px;
}
a{
text-decoration: none;
color: #ccc;
font-size: 14px;
text-shadow: none;
}
</style>
header中使用了浮動定位
ul{list-style: none; float: right;}
li{display: inline-block; }
2.2 PostList組件
API接口:https://cnodejs.org/api/v1/topics 獲取帖子列表
使用HiJson分析數(shù)據(jù)
拿到的參數(shù)分析
頭像:author.avatar_url
回復量/瀏覽量 :reply_count/visit_count
帖子的標題:title
需要使用到過濾器:
時間:last_reply_at
帖子分類:top: 代表是否置頂
good: 代表是否精華
tab 是表示除了置頂和精華之外的其余分區(qū)
--share 分享
--ask 問答
- -job 招聘
[圖片上傳失敗...(image-bcbae7-1563502172085)]
在數(shù)據(jù)還未到來時勘畔,我們顯示出一個正在加載的logo,用img標簽引入一個動態(tài)圖片丽惶,用v-if操作這個動態(tài)圖的顯示
<div class="loading" v-if="isLoading">
<img src="../assets/loading.gif" alt="">
</div>
在組件data中定義一個空數(shù)組,并且讓加載logo默認不顯示
data(){
return{
isLoading: false,
posts:[]
}
}
獲取數(shù)據(jù)用到Axios中的get請求炫七,引入之后將Axios全局掛載到Vue原型上,通過this.$http來對網(wǎng)頁進行請求
發(fā)動請求钾唬,接受響應需要axios插件
npm install axios
獲取數(shù)據(jù)用到Axios中的get請求万哪,引入之后將Axios全局掛載到Vue原型上,通過this.$http來對網(wǎng)頁進行請求
import Axios from 'axios'
Vue.prototype.$http = Axios;
在methods方法中定義一個方法getData,通過get方法獲取數(shù)據(jù),通過promise返回請求成功和請求失敗的數(shù)據(jù)知纷,并做對應的事
methods:{
getData(){
this.$http.get('https://cnodejs.org/api/v1/topics',{
params:{
page:1,
limit:20
}
})
.then(res=>{
this.isLoading = false //加載成功壤圃,去除動畫
this.posts = res.data.data
// console.log(this.posts)
})
.catch(err=>{
//處理返回失敗后的問題
console.log(err)
})
}
在頁面加載之前,觸發(fā)getData方法,并且在數(shù)據(jù)沒有到來之前琅轧,顯示加載logo伍绳,如代碼所示
beforeMount(){
this.isLoading = true //加載成功之前顯示加載動畫
this.getData() //在頁面加載之前獲取數(shù)據(jù)
}
得到數(shù)據(jù)后,渲染頁面用v-for,根據(jù)數(shù)據(jù)結構寫出所需要的數(shù)據(jù)
<template>
<div class="PostList">
<!--數(shù)據(jù)沒返回時加載-->
<div class="loading" v-if="isLoading">
<img src="../assets/loading.gif" alt="">
</div>
<!--列表-->
<div class="posts" v-else>
<ul>
<li>
<div class="toobar">
<span>全部</span>
<span>精華</span>
<span>分享</span>
<span>文檔</span>
<span>招聘</span>
</div>
</li>
<li v-for="post in posts">
<!--頭像-->
<img :src="post.author.avatar_url" alt="">
<!--回復/瀏覽-->
<span class="allcount">
<span class="reply_count">{{post.reply_count}}</span>
/{{post.visit_count}}
</span>
<!--分類-->
<span :class="[{put_good:(post.good == true),put_top:(post.top == true),
'topiclist-tab':(post.good != true && post.top != true)}]">
<span>
{{post | tabFormatter}}
</span>
</span>
<!--標題-->
<router-link :to="{
name:'post_content',
params:{id:post.id}
}">
<span>{{post.title}}</span>
</router-link>
<!--回復時間-->
<span class="last_reply">{{post.last_reply_at | formatDate}}</span>
</li>
</ul>
</div>
</div>
</template>
頁面中有帖子分類,與日期格式處理乍桂,所以這里要用到過濾器冲杀,我們將過濾器代碼寫入main.js中以便于各個組件使用
//處理日期
Vue.filter('formatDate', function (str) {
if (!str) return '';
var date = new Date(str);
var time = new Date().getTime() - date.getTime(); //現(xiàn)在的時間-傳入的時間 = 相差的時間(單位 = 毫秒)
if (time < 0) {
return '';
} else if ((time / 1000 < 30)) {
return '剛剛';
} else if (time / 1000 < 60) {
return parseInt((time / 1000)) + '秒前';
} else if ((time / 60000) < 60) {
return parseInt((time / 60000)) + '分鐘前';
} else if ((time / 3600000) < 24) {
return parseInt(time / 3600000) + '小時前';
} else if ((time / 86400000) < 31) {
return parseInt(time / 86400000) + '天前';
} else if ((time / 2592000000) < 12) {
return parseInt(time / 2592000000) + '月前';
} else {
return parseInt(time / 31536000000) + '年前';
}
}
);
// 處理顯示板塊的文字
Vue.filter('tabFormatter',function (post) {
if(post.good == true){
return '精華'
}else if(post.top == true){
return '置頂'
}else if(post.tab == 'ask'){
return '問答'
}else if(post.tab == 'share'){
return '分享'
}else{
return '招聘'
}
});
因為頭像和標題都會跳轉到新的地址效床,所以用router-link來包裹,通過to來跳轉到需要的路由和要傳統(tǒng)的所需參數(shù)
<!--頭像-->
<router-link :to="{
name:'user_info',
params:{name:post.author.loginname}
}">
<img :src="post.author.avatar_url" alt="">
</router-link>
<!--標題-->
<router-link :to="{
name:'post_content',
params:{
id:post.id,
name:post.author.loginname
}
}">
<span>{{post.title}}</span>
</router-link>
在roouter文件夾下的index.js文件中引入vue-router,然后定義路由名字,接收傳遞來的參數(shù)权谁,引入其他組件剩檀,代碼如下:
import Vue from 'vue'
import Router from 'vue-router'
import Article from '../components/Article'
import PostList from '../components/PostList'
import UserInfo from '../components/UserInfo'
Vue.use(Router);
export default new Router({
routes: [
{
name:'root',
path: '/',
components:{
main: PostList
}
},
{
name:'post_content',
path: '/topic/:id',
components:{
main: Article
}
},
{
name:'user_info',
path: '/userinfo/:name',
components:{
main: UserInfo
}
}
]
})
在父組件中引入router
import router from './router'
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
最后在App.vue組件中由router-view組件來接收,通過name的值來判定需要顯示的組件
<template>
<div id="app">
<Header></Header>
<div class="main">
<router-view name="slidebar"></router-view>
<router-view name="main"></router-view>
</div>
</div>
</template>
<script>
import Header from './components/header.vue'
// import PostList from './components/PostList.vue'
// import UserInfo from './components/UserInfo.vue'
export default {
name: 'App',
components:{
Header
}
}
</script>
- 后面的Article組件旺芽、SlideBar組件沪猴、UserInfo組件寫法都是一樣的,有跳轉的用router.link包裹采章,傳遞路由名字和參數(shù)运嗜,遇到需要遍歷的就用v-for遍歷,需要注意的有兩個地方悯舟,如下
- 第一個是在Article父組件中担租,因為寫完后會發(fā)現(xiàn)點擊下圖中兩個區(qū)域(SlideBar組件)頁面沒有變化,路由的參數(shù)雖然變了抵怎,但并不會跳轉奋救。所以我們要在Article組件中用watch監(jiān)聽路由的變化以便進行跳轉
監(jiān)聽路由代碼:
watch:{
'$route'(to,from){
this.getArticleData()
}
}
* 第二個是在SlideBar組件中蔓挖,因為只需要獲取五條數(shù)據(jù)航厚,所以要在計算屬性中寫兩個方法,然后在模板中用v-for來渲染,例:v-for="list in topcilimitby5"
### 2.3 Article組件
API https://cnodejs.org/api/v1/topic/ + 帖子ID
### 2.4 Userinfo組件
API https://cnodejs.org/api/v1/user/+ username