15.blog前端-博客首页

App.vue

<template>
  <div id="app">
    <!--博客首页显示-->
    <router-view>

    </router-view>

    <!--回到顶部的组件-->
    <go-top></go-top>
  </div>
</template>

<script>
  import GoTop from "@/components/gotop/GoTop"
export default
{
  name: 'App',
  components:
  {
    "go-top": GoTop,

  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

这里由@作为src目录,需要进行一个配置

vue.config.js:

const path = require('path')
function resolve(dir) {
    return path.join(__dirname, dir)
}
module.exports =
    {
        lintOnSave:true,
        pages:
            {
                index:
                    {
                        entry: 'src/main.js',
                    }
            },
        configureWebpack: {
            resolve: {
                alias: {
                    '@': resolve('src')
                }
            }
        }
    }

在components下新建gotop目录,新建组件GoTop.vue,实现首页到了底部,点击一个按钮重新回到顶部:

<template>
    <transition>
        <div @click="toTop" v-if="topShow" class="me-to-top">
            <i class="el-icon-caret-top"></i>
        </div>
    </transition>
</template>

<script>
export default
{
    name:'GoTop',
    data()
    {
        return{
            topShow:false//默认不在底部就不显示
        }
    },
    methods:
    {
        toTop()//回到顶部
        {
            document.body.scrollTop = 0;
            document.documentElement.scrollTop = 0;
            this.topShow = false;
        },
        needToTop()
        {
          let currentHeight = document.documentElement.scrollTop ||  document.body.scrollTop;
          this.topShow = currentHeight > 400;
        },
    },
    mounted()
    {
        this.$nextTick(()=>
        {
            //对窗体的滚动添加一个事件,监听窗体的滚动(只要滚动栏一滚动,该事件就生效)
            window.addEventListener("scroll", this.needToTop);
        });
    }
}
</script>

<style>
    .me-to-top
    {
        background-color: #fff;
        /*相对于浏览器窗口进行定位*/
        position: fixed;
        right: 100px;
        bottom: 150px;
        width: 40px;
        height: 40px;
        border-radius: 20px;
        /*移入该范围光标变成手指*/
        cursor: pointer;

        transition: .3s;
        /*阴影度*/
        box-shadow: 0 0 6px rgba(0, 0, 0, .12);
        /*重叠度*/
        z-index: 5;
    }

    .me-to-top i
    {
        color: #00d1b2;
        display: block;
        line-height: 40px;
        text-align: center;
        font-size: 18px;
    }
</style>

这里需要引入elementUI的一个样式icon,需要先安装elementUI 

然后package.json文件会出现相应的依赖 

 main.js引入elementUI

import Vue from 'vue'
import App from './App.vue'
import router from "./router";
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  router,
}).$mount('#app')

重新运行就有该样式了 

在views下添加Index.vue,充当中间的页面

<template>
  <div>
    <el-container>
        <el-main class="myArticles">
            <!--文章列表-->
            <ArticleItem v-for="article in articles"
                         v-bind="article"
                         :key="article.id"
            ></ArticleItem>
        </el-main>
        <el-aside>Aside</el-aside>
    </el-container>
  </div>
</template>

<script>
    import ArticleItem from "@/components/article/ArticleItem"
    export default
    {
        name: '',
        components:
        {
          ArticleItem,
        },
        data()
        {
            return{
                articles:
                [
                    {
                        id:"1",
                        weight:1,
                        title:"标题1",
                        commentCounts:123,
                        viewCounts:123,
                        summary:"概要11",
                        author:"作者",
                        tags:[{"tagName":"vue"}],
                        createDate:"3333"
                    },
                    {
                        id:"2",
                        weight:1,
                        title:"标题2",
                        commentCounts:123,
                        viewCounts:123,
                        summary:"概要11",
                        author:"作者",
                        tags:[{"tagName":"vue"}],
                        createDate:"111"
                    },
                    {
                        id:"3",
                        weight:1,
                        title:"标题3",
                        commentCounts:123,
                        viewCounts:123,
                        summary:"概要11",
                        author:"作者",
                        tags:[{"tagName":"vue"}],
                        createDate:"222"
                    }
                ]
            }
        }
    }
</script>

<style scoped>
.el-container
{
    width: 960px;
}
/*右侧边栏*/
.el-aside
{
    /*右侧和主部空了20px的距离*/
    margin-left: 20px;
    width: 260px;
}
/*主栏*/
.el-main {
    padding: 0px;
    line-height: 16px;
}
/*文章列表*/
.el-card {
    border-radius: 0;
}
/*设置卡片最后一个子元素除外的样式,第一个不用和上面有间隙*/
.el-card:not(:first-child)
{
    margin-top: 20px;
}
</style>

在router的index文件中添加对应的路由(不然App的router-view没有显示的)

import Vue from 'vue'
import VueRouter from 'vue-router'
import foo from '../pages/foo'
import bar from '../pages/bar'
Vue.use(VueRouter)

const router = new VueRouter({
    routes:
    [
        {
            path:"/",
            component: r => require.ensure([], () => r(require('@/views/Index')), 'index')
        }
    ]
});
export default router

 文章列表是由一组card组成,所以在components下新建article,在其下新建ArticleItem.vue:

<template>
    <el-card class="my-area" :body-style="{ padding: '16px' }">
        <!--文章标题、评论数、阅读文章数-->
        <div class="my-article-header">
            <a @click="view(id)" class="my-article-title">{{title}}</a>

            <el-button v-if="weight > 0" class="my-article-icon" type="text">置顶</el-button>

            <!--评论数-->
            <span class="my_pull-right my_article-count">
                <i class="my-icon-comment"></i>&nbsp;
                {{commentCounts}}
            </span>

            <!--阅读文章数-->
            <span class="my-pull-right my-article-count">
	    	    <i class="el-icon-view"></i>&nbsp;
                {{viewCounts}}
	        </span>
        </div>

        <!--摘要-->
        <div class="my-article-description">
            {{summary}}
        </div>

        <!--作者、标签、时间-->
        <div class="my-article-footer">
            <span class="my-article-author">
                <i class="my-icon-author"></i>&nbsp;
                <el-tag>{{author}}</el-tag>
            </span>

            <el-tag v-for="t in tags" :key="t.tagName" size="mini" type="success">
                {{t.tagName}}
            </el-tag>

            <span class="my-pull-right my-article-count">
                <i class="el-icon-time"></i>&nbsp;
                {{createDate | format}}
            </span>
        </div>

    </el-card>
</template>

<script>
    export default
    {
        name:"ArticleItem",
        props:
            {
                id: String,
                weight: Number,
                title: String,
                commentCounts: Number,
                viewCounts: Number,
                summary: String,
                author: String,
                tags: Array,
                createDate: String
            },
        methods:
            {
                /*点击文章标题,跳转到文章详情*/
                view(id)
                {
                    this.$router.push({path:`/view/${id}`})
                }
            }
    }
</script>

<style>
    /*文章header*/
    .my-article-header
    {
        padding-bottom: 10px;
    }
    /*标题大小*/
    .my-article-title
    {
        font-weight: 600;
    }
    /*是否置顶icon*/
    .my-article-icon
    {
        padding: 3px 8px;
    }
    /*阅读文章数*/
    my-article-count
    {
        color: #ff00ff;
        padding-left: 14px;
        font-size: 13px;
    }
    /*??*/
    .my-pull-right
    {
        float: right;
    }
    /*文章摘要*/
    .my-article-description
    {
        font-size: 13px;
        line-height: 24px;
        margin-bottom: 10px;
    }
    .my-article-author
    {
        color: #aa00ff;
        padding-right: 18px;
        font-size: 13px;
    }
    .el-tag
    {
        margin-left: 6px;
        color: #ffffff;
        background-color: #ff00ff;
    }
</style>

时间格式化工具类:

/*文章创建时间格式化*/
export function formatTime(time)
{
    const d = new Date(time);
    const now = Date.now();

    const diff = (now - d) /1000;//单位为秒

    if(diff<30)/*如果文章创建时间小于30秒*/
    {
        return "刚刚";
    }else if(diff < 3600)
    {
        /*向上取整*/
        return Math.ceil(diff/60) + "分钟前";
    }else if(diff < 3600 * 24)
    {
        return Math.ceil(diff/3600) + "小时前";
    }else if(diff < 3600 * 24 *2)
    {
        return "1天前";
    }
    return time;
}

main.js里面使用:

/*格式化时间*/
import {formatTime} from "./utils/time";
Vue.filter('format',formatTime);

文章列表是一个分页列表,这里我们需要实现,下拉分页,即如果拉到底部,就会请求下一页的数据,如果有数据就加载出来,如果没数据,就证明到达最后一页

新建scrollpage/index.vue

<!--加载动画-->
<template>
    <div ref="scroll" id="scroll-page" style="overflow: hidden">
        <slot></slot>
        <!--loading动画,加载的数据的过程中显示 elementUI load-->
        <div
            style="height: 40px;margin-top: 10px;z-index: 1"
            v-loading="loading"
            element-loading-text="拼命加载中"
            element-loading-spinner="el-icon-loading"
            element-loading-background="rgba(245,245,245)">
        </div>
    </div>

</template>

<script>
    export default
    {
        name: "index",
        props: {
            loading: Boolean,
            noData: Boolean,
            offset: Number
        },
        mounted() {
            //绑定事件监听,滚动的时候触发
            window.addEventListener('scroll', this.handleScroll, false);
        },
        beforeDestroy() {
            //移出事件监听
            window.removeEventListener('scroll', this.handleScroll);
        },
        data() {
            return {
                scrollAction: {
                    x: 'undefined',
                    y: 'undefined'
                }
            }
        },
        methods: {
            handleScroll(e) {
                let that = this;
                if (!that.noData) {
                    //如果有数据,触发
                    let curHeight = document.documentElement.scrollTop || document.body.scrollTop;
                    //获取div区域
                    let scrollPage = document.getElementById('scroll-page');

                    if ((curHeight + window.innerHeight >= that.$refs.scroll.offsetHeight + that.offset) && that.isDownDirection())
                    {
                        //判断是否到达底部
                        if (!that.loading) {
                            //调用load加载数据
                            that.$emit('load')
                        }
                    }
                }
            },
            isDownDirection()
            {
                if (typeof this.scrollAction.x == 'undefined') {
                    this.scrollAction.x = window.pageXOffset;
                    this.scrollAction.y = window.pageYOffset;
                }
                let diffX = this.scrollAction.x - window.pageXOffset;
                let diffY = this.scrollAction.y - window.pageYOffset;

                this.scrollAction.x = window.pageXOffset;
                this.scrollAction.y = window.pageYOffset;

                if (diffX < 0) {
                    // Scroll right
                } else if (diffX > 0) {
                    // Scroll left
                } else if (diffY < 0) {
                    // Scroll down
                    return true
                } else if (diffY > 0) {
                    // Scroll up
                } else {
                    // First scroll event
                }
                return false
            }

        }
    }
</script>

<style scoped>

</style>

 在views下新建common文件夹,其中新建ArticleScrollPage.vue,

将文章列表放入滚动分页区域内

<template>
    <scroll-page :loading="loading"
                 :offset="offset"
                 :no-data="noData"
                 @load="load">
        <article-item v-for="article in articles"
                      :key="article.id"
                      v-bind="article">
        </article-item>
    </scroll-page>
</template>

<script>
    import ArticleItem from '@/components/article/ArticleItem'
    import ScrollPage from '@/components/scrollpage'
    export default
    {
        name: "ArticleScrollPage",
        props: {
            offset: {
                type: Number,
                default: 0
            }
        },
        watch: {
        },
        created() {
            this.getArticles()
        },
        data() {
            return {
                loading: false,
                noData: false,
                //分页信息
                innerPage: {
                    pageSize: 5,
                    page: 1,
                    name: 'a.createDate',
                    sort: 'desc'
                },
                //文章列表
                articles: []
            }
        },
        methods: {
            load() {
                //下拉触发分页的时候,调用接口加载
                alert("触发分页")
                this.getArticles();
            },
            getArticles() {
                let that = this
                that.loading = true
                that.articles = that.articles.concat([
                    {
                        id:"1",
                        weight:1,
                        title:"标题1",
                        commentCounts:123,
                        viewCounts:123,
                        summary:"概要11",
                        author:"作者",
                        tags:[{"tagName":"vue"}],
                        createDate:"3333"
                    },
                    {
                        id:"232",
                        weight:1,
                        title:"标题1",
                        commentCounts:123,
                        viewCounts:123,
                        summary:"概要11",
                        author:"作者",
                        tags:[{"tagName":"vue"}],
                        createDate:"3333"
                    },
                    {
                        id:"2",
                        weight:1,
                        title:"标题2",
                        commentCounts:123,
                        viewCounts:123,
                        summary:"概要11",
                        author:"作者",
                        tags:[{"tagName":"vue"}],
                        createDate:"11111"
                    },
                    {
                        id:"3",
                        weight:1,
                        title:"标题3",
                        commentCounts:123,
                        viewCounts:123,
                        summary:"概要11",
                        author:"作者",
                        tags:[{"tagName":"vue"}],
                        createDate:"2222"
                    },
                    {
                        id:"4",
                        weight:1,
                        title:"标题3",
                        commentCounts:123,
                        viewCounts:123,
                        summary:"概要11",
                        author:"作者",
                        tags:[{"tagName":"vue"}],
                        createDate:"2222"
                    },
                    {
                        id:"5",
                        weight:1,
                        title:"标题3",
                        commentCounts:123,
                        viewCounts:123,
                        summary:"概要11",
                        author:"作者",
                        tags:[{"tagName":"vue"}],
                        createDate:"2222"
                    },
                    {
                        id:"6",
                        weight:1,
                        title:"标题3",
                        commentCounts:123,
                        viewCounts:123,
                        summary:"概要11",
                        author:"作者",
                        tags:[{"tagName":"vue"}],
                        createDate:"2222"
                    },
                    {
                        id:"7",
                        weight:1,
                        title:"标题3",
                        commentCounts:123,
                        viewCounts:123,
                        summary:"概要11",
                        author:"作者",
                        tags:[{"tagName":"vue"}],
                        createDate:"2222"
                    },
                    {
                        id:"8",
                        weight:1,
                        title:"标题3",
                        commentCounts:123,
                        viewCounts:123,
                        summary:"概要11",
                        author:"作者",
                        tags:[{"tagName":"vue"}],
                        createDate:"2222"
                    }
                ]);
                this.noData = false;
                that.loading = false
            }
        },
        components: {
            'article-item': ArticleItem,
            'scroll-page': ScrollPage
        }
    }
</script>

<style scoped>
    .el-card {
        border-radius: 0;
    }

    .el-card:not(:first-child) {
        margin-top: 10px;

    }
</style>

这样,views下的Index就直接用ArticleScrollPage组件即可

<template>
  <div>
    <el-container>
        <el-main class="myArticles">
            <!--文章列表-->
            <ArticleScrollPage>

            </ArticleScrollPage>
        </el-main>
        <el-aside>Aside</el-aside>
    </el-container>
  </div>
</template>

<script>
    import ArticleScrollPage from "@/components/common/ArticleScrollPage"
    export default
    {
        name: '',
        components:
        {
            ArticleScrollPage,
        },
    }
</script>

<style scoped>
.el-container
{
    width: 960px;
}
/*右侧边栏*/
.el-aside
{
    /*右侧和主部空了20px的距离*/
    margin-left: 20px;
    width: 260px;
}
/*主栏*/
.el-main {
    padding: 0px;
    line-height: 16px;
}
/*文章列表*/
.el-card {
    border-radius: 0;
}
/*设置卡片最后一个子元素除外的样式,第一个不用和上面有间隙*/
.el-card:not(:first-child)
{
    margin-top: 20px;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值