使用vue.js和webpack完成文章的评论和分页组件

学习了vue.js一段时间,拿它来做2个小组件,练习一下。
我这边是用webpack进行打包,也算熟悉一下它的运用。
源码放在文末的 github 地址上。

首先是index.html

<!DOCTYPE html>
<html>
<head>
    <title>Page</title>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
            font-family: 'Open Sans', Arial, sans-serif;
        }
        .contianer {
            width: 50%;
            height: auto;
            margin: 20px auto;
        }
        article {
            margin-bottom: 50px;
        }
    </style>
</head>
<body>
    <div class='contianer'>
        <article>
            文章内容...
        </article>
        <div id='main'>
            <app></app>        
        </div>
    </div>
    <script type="text/javascript" src='bundle.js'></script>
</body>
</html>

我将 app这个组件放在 <div id='main'></div>
通过webpack打包后,入口的js文件是entry.js,用来引入app.vue组件
entry.js

let Vue = require('vue');

import App from './components/app';

let app_vue = new Vue({
    el: '#main',
    components: {
        app: App
    }
});

接下来看下这个app组件

<style type="text/css" scoped>
    
</style>

<template>
    <comment :cur-page-index="curPageIndex" :each-page-size="eachPageSize" :comment-url="commentUrl" 
        :comment-params="commentParams" :comment-is-sync="commentIsSync">
        
    </comment>
    <page :cur-page-index.sync="curPageIndex" :each-page-size="eachPageSize" :page-url="pageUrl" 
        :page-params="pageParams" :page-is-sync="pageIsSync">

    </page>
</template>    

<script type="text/javascript">
    import Comment from './comment';
    import Page from './page';

    export default {
        data () {
            return {
                curPageIndex: 1,
                eachPageSize: 7,
            }
        },
        components: {
            comment: Comment,
            page: Page
        },
    }
</script>

它有2个子组件,分别是comment.vuepage.vue,通过动态绑定数据,进行父子间组件通信,我是这样认为的,对于 当前在第几页 应当由 page.vue传递给app.vue,所以这里我们使用 双向绑定,其余的如 params, url, isSync,即向后台请求数据的东西以及是否同步或异步操作<当然,这里我还没有测试过后台数据,目前是直接js生成静态数据>。

接下来,看下comment.vue评论组件

<style type="text/css" scoped>
    .comt-mask {
        opacity: 0.5;
    }
    .comt-title {
        
    }
    .comt-line {
        width: 100%;
        height: 2px;
        background-color: #CCC;
        margin: 10px 0;
    }
    .comt-wrap {
        
    }
    .comt-user {
        float: left;
    }
    .comt-img {
        width: 34px;
        height: 34px;
        border-radius: 17px;
    }
    .comt-context {
        margin: 0 0 0 60px;
    }
    .comt-name {
        color: #2B879E;
        margin-bottom: 10px;
        font-size: 18px;
    }
</style>

<template>
    <div v-if="hasComment" :class="{'comt-mask': loading}">
        <h3 class='comt-title'>{{ totalCommentCount }}  条评论</h3>
        <div class="comt-line"></div>
        <div class="comt-wrap" v-for="comment of commentArr">
            <div class="comt-user">
                <img src='{{ comment.avatar }}' class="comt-img"/>
            </div>
            <div class="comt-context">
                <p class="comt-name">{{ comment.name }}</p>            
                <p>
                    {{ comment.context }}
                </p>
            </div>
            <div class="comt-line"></div>
        </div>
    </div>
</template>

<script type="text/javascript">
    import {getCommentData, getTotalCommentCount} from './getData';

    export default {
        props: {
            curPageIndex: {
                type: Number,
                default: 1,
            },
            eachPageSize: {
                type: Number,
                default: 7,
            },
            commentUrl: {
                type: String,
                default: '',
            },
            commentParams: {
                type: Object,
                default: null,
            },
            commentIsSync: {
                type: Boolean,
                default: true,
            },
        },
        data () {
            return {
                totalCommentCount: 0,
                hasComment: false,
                loading: true,            
            }
        },
        computed: {
            commentArr () {
                this.loading = true;
                let res =  getCommentData(this.commentUrl, this.commentParams, this.commentIsSync, this.curPageIndex, this.eachPageSize);
                this.loading = false;
                return res;
            },
        },
        created () {
            let cnt =  getTotalCommentCount(this.commentUrl, this.commentParams);
            this.totalCommentCount = cnt;
            this.hasComment = cnt > 0;
        }
    }
</script>

这里的 getData.js 将在下面提到,是我们获取数据的位置。
loading: 本意是在跳转页码加载评论时,对于当前评论加载0.5的透明度的遮罩,然后ajax通过它的回调函数来取消遮罩,现在这样就不能实现了,只能强行写下,然而是没有用的..
hasComment: comment组件第一次加载的时候,我们就去请求获得总共的数据长度,如果没有数据,则不显示comment组件布局内容
·curPageIndex·: 通过父组件app传递下来,使用的是props
这些数据,我们都设置一个默认值与类型比较好。
page.vue

<style type="text/css" scoped>
    .page {
        text-align: center;
        margin: 30px;
    }
    .page-btn {
        color: gray;
        background-color: white;
        border: white;
        width: 30px;
        height: 30px;
        margin: 5px;
        font-size: 18px;
        outline: none;
    }
    .page-btn-link {
        cursor: Crosshair;
    }
    .page-btn-active {
        border: 1px solid gray;
        border-radius: 15px;
    }
</style>

<template>
    <div class="page">
        <button v-for="pageIndex of pageArr" track-by='$index' :class="{'page-btn': true, 'page-btn-active': 
            this.curPageIndex === pageIndex, 'page-btn-link': checkNum(pageIndex)}" 
            @click="clickPage(pageIndex)" >
                {{ pageIndex }}
        </button>        
    </div>
</template>

<script type="text/javascript">
    import {getTotalPageCount} from './getData';

    export default {
        props: {
            totalPageCount: {
                type: Number,
                default: 0,
            },
            curPageIndex: {
                type: Number,
                default: 1,
            },
            eachPageSize: {
                type: Number,
                default: 7,
            },
            pageAjcn: {
                type: Number,
                default: 4,
            },
            pageUrl: {
                type: String,
                default: '',
            },
            pageParams: {
                type: Object,
                default: null,
            },
            pageIsSync: {
                type: Boolean,
                default: true,
            }                        
        },
        data () {
            return {

            }
        },
        computed: {
            pageArr () {
                let st = 1,
                    end = this.totalPageCount,
                    cur = this.curPageIndex,
                    ajcn = this.pageAjcn,
                    arr = [],
                    left = Math.floor(ajcn / 2),
                    right = ajcn - left;
                    
                if (end == 0 || cur == 0) {
                    return arr;
                } else {
                    console.log(st, end, cur, left, right);
                    arr.push(st);
                    console.log(st+1, cur-left);
                    if (st + 1 < cur - left) {
                        arr.push('...');
                    }
                    for (let i = Math.max(cur - left, st + 1); i <= cur - 1; ++i) {
                        arr.push(i);
                    }
                    if (cur != st) {
                        arr.push(cur);
                    }
                    for (let i = cur + 1; i <= cur + right && i <= end - 1 ; ++i) {
                        arr.push(i);
                    }
                    if (cur + right < end - 1) {
                        arr.push('...');
                    }
                    if (end != cur) {
                        arr.push(end);
                    }
                    return arr;
                }    
            }
        },
        methods: {
            clickPage (curIndex) {
                if (Number.isInteger(curIndex)) {
                    this.curPageIndex = curIndex;
                }
            },
            checkNum (curIndex) {
                return Number.isInteger(curIndex);
            }            
        },
        created () {
            this.totalPageCount = getTotalPageCount(this.pageUrl,     this.pageParams, this.pageIsSync, 
                this.eachPageSiz);
        }
    }
</script>

主要是个对于 组件事件的运用,=最常见的click事件,以及classstyle的绑定,根据 curPageIndexthis.pageIndex来比较,判断是否拥有这个class,通过computed计算属性,来获得 页码数组 因为会根据当前页 有所变化,created的时候 计算出总页码。
最后一个是 目前生成获取静态数据的js文件.

// let data = {
//     avatar: '',  头像
//     name: '',  用户名
//     context: '', 评论内容
// }
let dataArr = [];

function randomStr (len) {
    return Math.random().toString(36).substr(len);
}

function initData () {
    for (var i = 0; i<45 ; ++i) {
        let _avator = "./resources/" + i%7 + ".jpg";
        let _name = randomStr(20);
        let _context = randomStr(2);
        dataArr.push({
            avatar: _avator,
            name: _name,
            context: _context
        });
    }
}

if (!dataArr.length) {
    initData();
}

export function getCommentData (url = '', params = null, isSync = true, curPageIndex = 1, eachPageSize = 7) {
    /* ajax */
    let st = (curPageIndex - 1) * eachPageSize;
    let end = st + eachPageSize;

    return dataArr.slice(st, end);
}

export function getTotalCommentCount(url = '', params = null, isSync = true) {
    /* ajax */
    return dataArr.length;
}

export function getTotalPageCount(url = '', params = null, isSync = true, eachPageSize = 7) {
    /* ajax */
    return Math.floor((dataArr.length + eachPageSize -1 ) / eachPageSize);
}

就这样了吧。
github地址

    原文作者:radical
    原文地址: https://segmentfault.com/a/1190000005805967
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞