使用vue.js來搭建一個高仿的CNODE社區(qū)

使用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)]

  1. 將項目中要用到的圖片和logo都存入assets文件夾中
  2. 創(chuàng)建一個Header組件棠众,用img標簽引入存儲在assets文件中的logo
  3. 在li標簽分別寫出:新手入門、API王带、關于享言、注冊、登錄
  4. 將組件引入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
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末炕吸,一起剝皮案震驚了整個濱河市姿染,隨后出現(xiàn)的幾起案子利耍,更是在濱河造成了極大的恐慌,老刑警劉巖盔粹,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異程癌,居然都是意外死亡舷嗡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門嵌莉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來进萄,“玉大人,你說我怎么就攤上這事锐峭≈惺螅” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵沿癞,是天一觀的道長援雇。 經(jīng)常有香客問我,道長椎扬,這世上最難降的妖魔是什么惫搏? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任具温,我火速辦了婚禮,結果婚禮上筐赔,老公的妹妹穿的比我還像新娘铣猩。我一直安慰自己,他們只是感情好茴丰,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布达皿。 她就那樣靜靜地躺著,像睡著了一般贿肩。 火紅的嫁衣襯著肌膚如雪峦椰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天尸曼,我揣著相機與錄音们何,去河邊找鬼。 笑死控轿,一個胖子當著我的面吹牛冤竹,可吹牛的內容都是我干的。 我是一名探鬼主播茬射,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鹦蠕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了在抛?” 一聲冷哼從身側響起钟病,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎刚梭,沒想到半個月后肠阱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡朴读,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年屹徘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衅金。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡噪伊,死狀恐怖,靈堂內的尸體忽然破棺而出氮唯,到底是詐尸還是另有隱情鉴吹,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布惩琉,位于F島的核電站豆励,受9級特大地震影響,放射性物質發(fā)生泄漏琳水。R本人自食惡果不足惜肆糕,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一般堆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧诚啃,春花似錦淮摔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至造垛,卻和暖如春魔招,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背五辽。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工办斑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人杆逗。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓乡翅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親罪郊。 傳聞我的和親對象是個殘疾皇子蠕蚜,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內容