1

接着上一篇我们接着讲,关于这个网站的专题页面和2015精选页面,如果有小伙伴没看过上一篇文章,这里附上上一篇文章的的链接基于Vue,Vue-router,Vuex的简书网站模仿
这里是网站的源码下载地址 Github Repo
这里是Demo地址,在线感受vue的魅力

页面结构分析

图片描述

  • App.vue:黄色框部分和紫色框部分

  • Topic.vue:橙色框部分

  • Topic_article.vue:蓝色框部分(同时也是重点部分,实现点击排序)

学会分析页面结构,是用vue开发一个比较重要的地方(我猜的),所以我再次分析了一次。页面结构分析结束后,接下来就是上代码的时候了。

Topic.vue(橙色框部分)

topic.vue部分和上一篇文章的home.vue部分是如出一辙的,为了让大家加深印象,我就再讲一次(我不会讲我是来凑字数的,嘿嘿)。上代码:

<template>
<div>
  <div class="showbar">
    <div class="cover-image_2"></div>
    <div class="text" style="text-shadow:1px 1px 1px #000000">
      <h1>专题</h1>
      <h3>让思想汇聚,流传</h3>
      <p style="font-size:14px;margin-bottom:5px">专题内容由多位写作者提供</p>
      <a href="#"><i class="fa fa-pencil"></i>&nbsp;&nbsp;新建专题</a>
    </div>
  </div>
  <div class="article-page">
    <nav>
      <span class="search clearfloat">
        <span class="input">
          <input type="search" placeholder="搜索">
        </span>
        <span class="search-icon"><i class="fa fa-search"></i></span>
      </span>       
    </nav>
    <div class="article-list">
      <ul class="btn-group">
        <li :class="{active: show === 'hot'}">
          <a @click="displayTopic('hot')"
             v-link="'/topic/topic_article'" 
          >热门</a></li>
        <li :class="{active: show === 'recommend'}">
          <a @click="displayTopic('recommend')"
             v-link="'/topic/topic_article'" 
          >推荐</a></li>
    </div>
    <router-view></router-view>
  </div>
</div>
</template>
<script>
  import {displayTopic} from '../vuex/actions'
  export default {
    vuex:{
      getters:{
        show: state => state.show_2
      },
      actions:{
        displayTopic
      }
    }
  } 
</script>

由于橙色框部分里热门和推荐两个导航按钮,要根据两个按钮展示不同的文章,这就和上一篇文章里的Home.vue里实现的方式一样,我们通过:class="{active: show === 'hot'}来判断当前按钮是否处于被点击状态,这里的show来自于vuex(getters)获取到的show,并且给它加上不一样的样式。通过@click="displayTopic('hot')点击事件来更换不同的show值和文章内容。这样我们就实现了点击切换按钮状态和文章区域内容。下面放上点击事件的代码:
actions.js:

export const displayTopic = ({ dispatch },show) => {
    dispatch('DISPLAY_TOPIC',show)
} 

store.js:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const state = {
    topics:{
        fir: {
            img:'../../static/topic_1.jpg',
            title:'游戏',
            par:'玩转简书的第一步,从这个专题开始。\
                  想上首页热门榜么?好内容想被更多人看到么?来投稿吧!\
                  如果被拒也不要灰心哦~入选文章会进一个队列挨个上首页,请耐心等待。\
                  投稿必须原创。如果发现有非...',            
            number:'97233',
            concern:'121.7',
            keys:'故事、连载',
            time:'20160620'        
        },
        sec: {
            img:'../../static/topic_3.jpg',
            title:'诗',
            par:'诗,让你感受自己的心灵。\
                 专题主编:苏锦年 投稿须知:\
                 1.本专题收录古诗、词、现代诗以及诗词点评及指导。\
                 2.内容必须为原创,切勿用其他诗人的诗句。\
                 3.文章排版整洁,注意...',            
            number:'35420',
            concern:'146.6',
            keys:'诗',
            time:'20160630'
        }
    },
    show_2:'hot'
}

const mutations = {
    DISPLAY_TOPIC (state, show) {
        const topic = {
            hot: {
                fir: {
                    img:'url../../static/vue-demo-hot.jpg',
                    title:'游戏',
                    par:'玩转简书的第一步,从这个专题开始。\
                          想上首页热门榜么?好内容想被更多人看到么?来投稿吧!\
                          如果被拒也不要灰心哦~入选文章会进一个队列挨个上首页,请耐心等待。\
                          投稿必须原创。如果发现有非...',            
                    number:'97233',
                    concern:'121.7k',
                    keys:'故事、连载'
                },
                sec: {
                    img:'../../static/topic_3.jpg',
                    title:'诗',
                    par:'诗,让你感受自己的心灵。\
                     专题主编:苏锦年 投稿须知:\
                     1.本专题收录古诗、词、现代诗以及诗词点评及指导。\
                     2.内容必须为原创,切勿用其他诗人的诗句。\
                    3.文章排版整洁,注意...',            
                    number:'35420',
                    concern:'146.6k',
                    keys:'诗',
                    time:'20160630'
                }
            },
            recommend: {
                fir: {
                    img:'../../static/topic_1.jpg',
                    title:'游戏',
                    par:'玩转简书的第一步,从这个专题开始。\
                           想上首页热门榜么?好内容想被更多人看到么?来投稿吧!\
                           如果被拒也不要灰心哦~入选文章会进一个队列挨个上首页,请耐心等待。\
                           投稿必须原创。如果发现有非...',            
                    number:'97233',
                    concern:'121.7',
                    keys:'故事、连载',
                    time:'20160620'        
                },
                sec: {
                    img:'../../static/topic_3.jpg',
                    title:'诗',
                    par:'诗,让你感受自己的心灵。\
                         专题主编:苏锦年 投稿须知:\
                         1.本专题收录古诗、词、现代诗以及诗词点评及指导。\
                         2.内容必须为原创,切勿用其他诗人的诗句。\
                         3.文章排版整洁,注意...',            
                    number:'35420',
                    concern:'146.6',
                    keys:'诗',
                    time:'20160630'
                },
                thi: {
                    img:'../../static/topic_2.jpg',
                    title:'@IT互联网',
                    par:'@IT 专题 由 IT大分类,转定位于IT·互联网行业观察与思考,数码产品极客体验。\
                    主编:向右奔跑 http://www.jianshu.com/users/54b5900965ea...',            
                    number:'8409',
                    concern:'111.1',
                    keys:'互联网、产品、科技',
                    time:'20160625'            
                }
            }
        }
        state.show_2 = show
        state.topics = topic[show]    
    }
}
export default new Vuex.Store({
    state,
    mutations
})

这里面我省掉了上一章的代码。这里面我才用模拟的数据,可以清楚的看到实现方式。接下来讲解排序部分,这里算是一个重点吧,因为我在这里遇到了坑。

Topic_article.vue(蓝色框部分)

这部分我们要实现根据小导航的切换来显示不同的顺序(热门,推荐,最新更新),这里我只做了推荐和最新更新这两部分。首先要实现这种效果,我们第一时间想到的就应该是和大导航一样给小导航添加class绑定和点击事件。接下来看代码,先是Topic_article.vue的代码:

<template>
    <div class="topic_article_container">
        <div class="sequence-nav" v-if="show === 'recommend'">
            <a @click="sortContent('time'), change = 'new'"
            :class="{active: change === 'new'}">最新更新&nbsp;&nbsp;·</a>            
            <a @click="change = 'hot'"
            :class="{active: change === 'hot'}">热门排序&nbsp;&nbsp;·</a>
            <a @click="sortContent('concern'), change = 'new'"
            :class="{active: change === 'concern'}">关注度排序</a>
        </div>
        <ul>
            <li v-for="content in topic">
                <a href="" class="topic_article_img"><img :src="content.img"></a>
                <div class="topic_content">
                    <h5>{{ content.title }}</h5>
                    <p>{{ content.par }}</p>
                    <div class="topic_button">
                        <a href="#"><i class="fa fa-fw fa-plus"></i><span>添加关注</span></a>
                    </div>
                    <p>
                        <a href="#" style="color:#4094c7">{{ content.number}}篇文章</a>
                        &nbsp;&nbsp;·&nbsp;&nbsp;{{content.concern}}k人关注
                        <span class="topic_tag"><i class="fa fa-tags"></i>{{ content.keys}}</span>
                    </p>
                </div>
            </li>
        </ul>
    </div>
</template>
<script>
    import { sortContent } from '../vuex/actions'
    export default {
        data (){
            let change = 'hot'
            return {change}
        },
        vuex: {
            getters: {
                topic: state => state.topics,
                show: state => state.show_2
            },
            actions: {
                sortContent
            }
        }
    }
</script>

因为这个小导航栏在热门页面里是没有的,这里才用了vue的v-if功能实现,通过getters获得此时的show变量,判断是否是推荐页面,如果是就显示。这里的文章依然采用vue的列表渲染功能(真好用),同时给小导航栏设置了点击事件,和改变背景的一个变量。接下来放上actions.js里面的代码:

export const sortContent = ({ dispatch },method) => {
    dispatch('SORTCONTENT',method)
}

也是那么短小精悍,毕竟我只用于分发事件。下面是store.js里面的代码:

SORTCONTENT (state, method){
        const temp = state.topics
        let arr = []
        let Arr = objClone(state.topics)
        switch(method){
            case 'time':
                arr = [temp.fir.time, temp.sec.time, temp.thi.time].sort()
                break
            case 'concern':
                arr = [temp.fir.concern, temp.sec.concern, temp.thi.concern].sort()
                break
            default:
                break
        } 
        for(let keys in state.topics){
            if(Arr[keys][method] == arr[2]){
                state.topics.fir = Arr[keys]
            }
            else if(Arr[keys][method] == arr[1]){
                state.topics.sec = Arr[keys]
            }
            else if(Arr[keys][method] == arr[0]){
                state.topics.thi = Arr[keys]
            }
        }
        function objClone(myObj){
            if(typeof(myObj) != 'object') return myObj;
            if(myObj == null) return myObj;
            var myNewObj = new Object();
            for(var i in myObj){
                myNewObj[i] = objClone(myObj[i]);
            }
            return myNewObj;
        }
    }

这个事件的代码也很好理解,通过对不同的method,把不同的变量进行排序后赋值给一个数组,然后依次与topics做匹配,因为我这里只模拟了三个数据,故这部分操作比较简单。重点的是当我匹配topics里第三个属性(thi)的值的时候,这个时候topics里的第三个属性值已经变了(因为如果第二个属性(sec)的值是最小的,就会把这个属性赋给第三个属性,这时候第三个属性就变了,所以第三次匹配的时候还是得出和第二次同样的结果)。这时候我的做法是克隆一个和topics相同的对象,用这个对象去匹配,匹配好了之后把这个对象里相应的值赋值给topics。我讲的有点啰嗦,具体看代码实现。(ps:克隆对象的时候,我竟然直接进行赋值克隆,殊不知都是指向同一个地址空间,后来了解到需要重新开一个地址空间才能克隆,故有了上面那段objClone函数。)
到这里简书两个主要的部分就讲完了(Home.vue,Topic.vue)
接下来说一说2015年精选页面

2015精选页面

这个页面相对来说比较简单,就一个vue的列表渲染(不用列表渲染的话代码太多,太长,关键是逼格不高),先上页面:
图片描述

图中类似的标签有12个,故才用列表渲染来简化重复的代码,接下来是代码部分:

Bonus.vue

<template>
    <div class="bonus-container">
        <div class="bonus-header">
            <span class="yellow">&nbsp;&nbsp;简书2015</span>
            <i>&nbsp;·&nbsp;</i>
            <span>每月一篇好文章&nbsp;&nbsp;</span>
        </div>
        <div class="share">
            <span><a href="#"><i class="fa fa-mobile"></i>手机查看效果更佳</a></span>
            <span><a href="#"><i class="fa fa-weibo"></i>分享到微博</a></span>
            <span><a href="#"><i class="fa fa-wechat"></i>分享到微信</a></span>
            <span><a href="#">更多分享</a></span>
        </div>
        <ul class="text-list">
            <li v-for="article in articles" 
                :style="{ background: article.article.bg, backgroundSize: '100%', backgroundRepeat: 'no-repeat',      backgroundColor: '#ffffff'}" 
                <div class="content">
                    <a class="mask" href="#">
                        <div class="button">阅读全文></div>
                    </a>
                    <div class="bonus-text">
                        <div class="bonus-text-title">{{ article.article.title}}</div>
                        <div class="line"></div>
                        <div class="bonus-text-content">
                            {{article.article.content_1}}<br>
                            {{article.article.content_2}}<br>
                            {{article.article.content_3}}<br>
                            {{article.article.content_4}}<br>
                            {{article.article.content_5}}<br>
                            {{article.article.content_6}}<br>
                        </div>
                    </div>
                    <div class="author"></div>
                </div>
            </li>
</template>
<script>
    export default {
        data () {
            let articles = ''
            return {articles}
        },
        vuex: {
            getters: {
                texts: state => state.texts
            }
        },
        ready: function() {
                this.articles = [{article: this.texts.Jan}, {article: this.texts.Feb}, {article: this.texts.Mar}, 
                             {article: this.texts.Apr}, {article: this.texts.May}, {article: this.texts.Jun}, 
                             {article: this.texts.Jul}, {article: this.texts.Aug}, {article: this.texts.Sep}, 
                             {article: this.texts.Oct}, {article: this.texts.Nov},  {article: this.texts.Dec}]
        }
    }
</script>

store.js_Bonus部分

下面是store.js里面模拟的数据

    texts:{
        Jan:{
            title:'给你90天,成为不一样的自己',
            content_1:"如果你应付不了现在的生活和工作",
            content_2:"无论你走到哪里,",
            content_3:"无论你换了什么工作,什么公司,",
            content_4:"都无济于事。",
            content_5:"因为你根本没想让自己成熟起来,",
            content_6:"想让变的更优秀也不过是一句口头禅。",
            author:'',
            bg:'url(../../static/bonus_1.jpg)'
        },
        Feb:{
            title:'使你更有思想的20本书',
            content_1:"真正伟大的当代文学,",
            content_2:"正如人们借由狄更斯来了解十九世纪的英国,",
            content_3:"后人也可以通过《自由》来了解",
            content_4:"二十一世纪初期的美国。",
            content_5:"",
            content_6:"",
            author:'',
            bg:'url(../../static/bonus_2.jpg)'
        },
        Mar:{
            title:'无感是最舒适的爱情',
            content_1:"爱情原本就是个很娇气的东西,",
            content_2:"它经不起太多的矫情,你死我活和无理取闹,",
            content_3:"也经不起任何的伪装,刻意讨好和忍辱负重。",
            content_4:"当她拂去所有的惊喜,荣幸,不敢置信和小心翼翼,",
            content_5:"才是爱情最原本的样子。",
            content_6:"当她不再刻意的感受他的存在,",
            author:'',
            bg:'url(../../static/bonus_3.jpg)'
        },
        Apr:{
            title:'无感是最舒适的爱情',
            content_1:"爱情原本就是个很娇气的东西,",
            content_2:"它经不起太多的矫情,你死我活和无理取闹,",
            content_3:"也经不起任何的伪装,刻意讨好和忍辱负重。",
            content_4:"当她拂去所有的惊喜,荣幸,不敢置信和小心翼翼,",
            content_5:"才是爱情最原本的样子。",
            content_6:"当她不再刻意的感受他的存在,",
            author:'',
            bg:'url(../../static/bonus_4.jpg)'
        }

这里我只给出5条数据,后面都是重复的,代码就不过多讲解了,实现方式和前面的一样。看到这里是不是感觉写一个网页很简单,是不是觉得Vue可好玩了,是的话那就对了,加油吧!骚年!
结尾还是那句话,求个收藏什么的,如有错误,欢迎斧正。


liuiuiu俊
516 声望42 粉丝