Vue 2.0 + Axios + Vue Router 實現CNode社區

這是我學習Vue以後的上手的第一個做品,還望你們多多指點。javascript

預覽地址          源碼地址            謝謝star ^_^html

項目技術棧
前端

  • Vue2.0:前端頁面展現vue

  • Vue-Router:頁面路由切換java

  • Axios:一個基於 Promise 的 HTTP 庫,向後端發起請求node

  • ES6:箭頭函數、Promise等等語法很好用ios

  • Webpack:vue init webpckgit

  • CSS3:CSS3過渡動畫及樣式github

TODO

功能上:發帖,收藏,回覆,點贊,web

實現上:使用Vuex共享各組件間的狀態

項目截圖在文章末尾。

如下爲對CNode社區提供的部分API、實現的各個組件介紹以及項目編碼中遇到的坑而又是如何解決的的總結。

API介紹

這裏因爲API內容過多,是以縮略形式展現,須要完整的圖,請到項目根目錄static文件夾中獲取。

組件介紹

pagination 分頁組件

這個組件HTML和CSS部分的代碼相對簡單,最重要的是理清各按鈕的排布邏輯。好比在點擊頁碼5時,頁碼1 就應該去除且同時頁碼6顯示在頁碼5以後;還有好比在目前頁碼爲1的狀況下,須要禁止上一頁的執行。如下是組件template中的代碼。

<template>
    <div class="pagination"> <div class="wrap"> <span @click="changeBtn">首頁</span> <span @click="changeBtn">上一頁</span> <span v-if="judge">...</span> <span v-for="(btn,index) in pagebtns" :key="index" :class="[{curtPage:btn==curtPage},'pagebtn']" @click="changeBtn(btn)" >{{btn}}</span> <span @click="changeBtn">下一頁</span> </div> </div>
  </template>複製代碼

第三個span是用來判斷當前頁碼是否大於4,若是大於4就應該用顯示...代表以前仍有頁碼。

添加了v-for指令的span是用來循環展現頁碼的。:class指令使用數組語法動態綁定類名。若是該頁碼即爲當前頁,那麼value值爲true,類名curtPage得以添加到class上。須要注意的是,這裏的pagebtn是可直接使用的類名,因此是字符串類型;若是是使用了組件data中的屬性,那就不該該使用字符串類型。

全部span的click事件是用觸發頁碼變更事件的。這裏具體實現上,按鈕爲文字的和數字的邏輯是不一樣的。對於文字按鈕,我這裏使用switch進行判斷。由於在點擊非頁碼按鈕時是獲取不到頁面的,這時就須要對所點擊按鈕的innerText作出判斷以響應,這裏爲了方便使用jQuery獲取當前頁碼的上一個DOM節點模擬點擊事件;或許要說明的是首頁按鈕的case,由於有可能頁面顯示的頁碼已經不是最開始的時候,因此要把頁碼初始化。也就是如今寫總結時纔想起,徹底能夠在模板代碼中直接傳遞肯定的頁碼做爲參數,這樣就省了不少事。

//方法一
  switch (page.target.innerText) {
            case "上一頁":
              $("span.curtPage").prev().click(); break;
            case "下一頁":
              $("span.curtPage").next().click(); break;
            case "首頁":
              this.pagebtns = [1, 2, 3, 4, 5, "..."];
              this.changeBtn(1); break;
            default:
              break;
          }
  ​
  //方法2
  <span @click="changeBtn(1)">首頁</span>
  <span @click="changeBtn(curtPage-1)">上一頁</span>複製代碼

實現樣式上效果後,更重要是點擊了頁碼後屬實能夠獲取到新一頁的內容。用Vue的話來講就是父子組件中的消息傳遞,那在這裏就是子組件(pagination)把消息(新的頁碼)傳遞到父組件(pagelist)。顯然是使用$emit()方法,在子組件中執行完改變頁碼的最後,使用$emit()向父組件發送消息,父組件中用自定義事件接受,代碼以下。

//子組件
  this.$emit("handle", this.curtPage);
  ​
  //父組件
  <pagination @handle="renderList"></pagination>
  ​
  renderList(value) {
        this.page = value;
        this.getData();
  }
  ​複製代碼

postlist組件

此組件的目的是渲染從API請求到的主題數據。佈局也卻是簡單,頂部一個主題分類tab,下面則是渲染的主題列表,CSS代碼此處不細講(到這個階段了,簡單的不該該成爲問題)。

對接口的請求,那必然涉及到Axios。考慮到這個庫的使用相對簡單,就不展開介紹使用直接上項目代碼好了。get方法的第一個參數是請求的接口地址,第二個參數是接口請求所需的參數。下面是使用了對象的形式傳遞參數,固然也能夠模板字符串拼接在地址中。請求成功後即將加載動畫取消,而且將回傳的數據賦給this.poststhis.posts是一個數組,而每一條主題數據又是一個對象,在v-for指令中渲染的就是每個對象。

methods: {
      getData() {
        this.$http
          .get("https://cnodejs.org/api/v1/topics", {
            params: {
              page: this.page,
              limit: 20}})
          .then(response => {
            this.isLoading = false;
            this.posts = response.data.data;
          })
          .catch(err => {
            console.log(err);});
      },
      renderList(value) {
        this.page = value;this.getData();}
  },
      
  beforeMount() {
      this.isLoading = true; //加載成功以前顯示加載動畫
      this.getData(); //頁面加載前獲取數據
  }複製代碼

模板中的代碼稍微值得一提的也就動態綁定類名和router的使用了。詳見下方代碼。

<span
          :class="[{putgood:(post.good==true),puttop:(post.top==true),
          'putnormal':(post.good!=true&& post.top!=true)}]"
          >
              {{post|formatTopicType}}
      </span>
  ​
      <router-link :to="{name:'post_content',params:{id:post.id,name:post.author.loginname}}">
          <span class="title">{{post.title}}</span>
      </router-link>複製代碼

這裏的動態綁定類名是針對主題分類使用的,putgoodputtop都是在post.goodpost.top爲真時纔會添加到類中,而putnormal則是在主題類別不爲置頂和精華時添加到類中。router的使用,上面代碼中路由的功能爲在點擊主題標題後跳轉到主題的詳情頁中,動態綁定的to屬性中各key含義爲:name 路由名稱,params 路由路徑中須要的參數(也即API中須要的參數)。

//路由配置文件
  {
      name: 'post_content',
      path: '/topic/:id&name=:name',
      components: {
        main: Article,
        side: Sidebar
        //router-view中的name
        //點擊首頁的文章標題後就會用article組件替換掉以前在main
        //中的postlist 組件
      }
    }複製代碼

如今兩部分代碼連起來看,就能夠清楚地看出路由的動向。代碼中另外還提到的Sidebar是下文會提到的另外一個組件,寫在乎味當走向這個路由時,頁面不止有name爲main的Article組件還有name爲Sidebar的組件。

Sidebar組件

這個組件是側邊欄組件,用於在主題詳情頁中渲染主題做者的相關信息。

組件模板分爲三個部分,做者概要信息、做者最近主題、做者參與主題。在這裏再次用到router在點擊用戶頭像時跳轉到用戶詳情頁,具體和上面上面相似,這裏就不贅述。

getSideInfo() {
        this.$http
          .get(`https://cnodejs.org/api/v1/user/${this.$route.params.name}`)
          .then(result => {
            if (result.data.success) {
              this.userinfo = result.data.data;
            }
          })
          .catch(err => {
            console.log(err);
          });
      }複製代碼

在這裏,咱們繼續來看到對用戶詳情API的請求,和以前提到的有些不一樣的是,這裏用到了this.$route.param,這個所指向的就是先前提到的路由配置文件中咱們設置的路由參數。經過這個咱們能夠輕易獲取到路由中的參數以在組件中使用。

Article組件

這個組件是主題詳情組件,用於展現主題內容回覆等。沒有不少相較以前組件的新內容。說下用到的過濾器,因爲API返回的建立時間是包含年月日等的具體時間,但但願頁面中顯示的是」幾小時錢「這樣,因此須要有過濾器對返回建立時間進行處理,這個過濾器邏輯比較簡單就不貼代碼了。另外,考慮到這種是通用的過濾器,建議放在全局中,即main.js文件。

在這個頁面中,同時存在的還有sidebar,當點擊sidebar組件中主題時,因爲Vue組件實例複用的緣由,生命週期的鉤子不會再被調用,這也意味着儘管點擊後地址欄URL發生變化,但並不會觸發getArticleData methods,此時就須要用到偵聽器watch,以監聽$route對象的變化,當路由變化時,則再次請求發起請求。

watch: {
      $route(to, from) {
        this.getArticleData();
      }
    }複製代碼

再有就是,除了簡單的豎線鍵值以外,咱們還能夠在模板中編寫JavaScript表達式,這一個feature在須要的時候會頗有用的。好比這個組件中每條回覆是有點贊數的,但咱們並不但願在點贊數爲0的時候也顯示,這個時候就能夠用到三目運算符進行判斷({{comment.ups.length>0?comment.ups.length:''}})。此外,咱們但願顯示回覆的樓層,但返回的回覆爲從0開始的數組類型,那此時咱們在模板這樣寫就行了({{index+1}}樓)。

headerbar組件

即網站頂部導航欄,這部分別的沒多少代碼,主要編碼就是在CSS了。社區用的是float,我用了下flex佈局實現。

最後還有個Userinfo組件,但考慮在實現和sidebar組件無差,這裏就不具體分享了。

印象很深的坑

路由配置中的components少寫了s,當時beforeMount裏的代碼都沒執行,控制檯也沒報錯,徹底懵逼。只好請教了眼尖的掃地僧。(全部的編程初學者都滿級近視

項目截圖

如下爲部分項目截圖,因爲在技術實現上的重複性以及接口的問題,我並無實現社區中有的所有頁面。

謝謝看完,多多指教^_^

相關文章
相關標籤/搜索