使用vue.js来搭建一个高仿的CNODE社区

使用vue.js来搭建一个高仿的CNODE社区

1. cnnode社区的基本架构

项目模块组件:
Header 头部模块
PostList 列表模块
Article 文章模块
Slider侧边栏模块
UserInfo用户个人中心模块
Pagination分页组件的开发

主要用到的技术栈有:

vue.js计算属性
vue.js的内置指令和事件的绑定
vue.js的自定义事件和触发
vue-router路由的跳转和监听
父子组件之间的数据传递,

2.1 Header组件

[图片上传失败...(image-d6cfcc-1563502172085)]

  1. 将项目中要用到的图片和logo都存入assets文件夹中
  2. 创建一个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分析数据
拿到的参数分析

头像:author.avatar_url
回复量/浏览量 :reply_count/visit_count
帖子的标题:title
需要使用到过滤器:
时间:last_reply_at
帖子分类:top: 代表是否置顶
                  good: 代表是否精华
                  tab 是表示除了置顶和精华之外的其余分区
                            -­share 分享
                            -­ask 问答
­                            -job 招聘

[图片上传失败...(image-bcbae7-1563502172085)]

在数据还未到来时,我们显示出一个正在加载的logo,用img标签引入一个动态图片,用v-if操作这个动态图的显示

<div class="loading" v-if="isLoading">
         <img src="../assets/loading.gif" alt="">
</div>

在组件data中定义一个空数组,并且让加载logo默认不显示

data(){
      return{
          isLoading: false,
          posts:[]
      }
  }

获取数据用到Axios中的get请求,引入之后将Axios全局挂载到Vue原型上,通过this.$http来对网页进行请求
发动请求,接受响应需要axios插件

npm install axios

获取数据用到Axios中的get请求,引入之后将Axios全局挂载到Vue原型上,通过this.$http来对网页进行请求

import Axios from 'axios'
Vue.prototype.$http = Axios;

在methods方法中定义一个方法getData,通过get方法获取数据,通过promise返回请求成功和请求失败的数据,并做对应的事

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) 
          })
      }

在页面加载之前,触发getData方法,并且在数据没有到来之前,显示加载logo,如代码所示

beforeMount(){
      this.isLoading = true //加载成功之前显示加载动画
      this.getData() //在页面加载之前获取数据
  } 

得到数据后,渲染页面用v-for,根据数据结构写出所需要的数据

<template>
  <div class="PostList">
    <!--数据没返回时加载-->
    <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(); //现在的时间-传入的时间 = 相差的时间(单位 = 毫秒)
    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来跳转到需要的路由和要传统的所需参数

<!--头像-->
                 <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,然后定义路由名字,接收传递来的参数,引入其他组件,代码如下:

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包裹,传递路由名字和参数,遇到需要遍历的就用v-for遍历,需要注意的有两个地方,如下
  • 第一个是在Article父组件中,因为写完后会发现点击下图中两个区域(SlideBar组件)页面没有变化,路由的参数虽然变了,但并不会跳转。所以我们要在Article组件中用watch监听路由的变化以便进行跳转
    监听路由代码:
    

watch:{
'$route'(to,from){
this.getArticleData()
}
}


*  第二个是在SlideBar组件中,因为只需要获取五条数据,所以要在计算属性中写两个方法,然后在模板中用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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,192评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,858评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,517评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,148评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,162评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,905评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,537评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,439评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,956评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,083评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,218评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,899评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,565评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,093评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,201评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,539评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,215评论 2 358

推荐阅读更多精彩内容