back-top-dom.vue 3.82 KB
<template>
    <div :class="classes" :style="styles" @click="back">
        <slot>
            <div class="back-top-dom-inner">
                <i class="ivu-icon ivu-icon-chevron-up"></i>
            </div>
        </slot>
    </div>
</template>
<script>
    const prefixCls = 'back-top-dom';

    export default {
        name: 'back-top-dom',
        props: {
            height: {
                type: Number,
                default: 400
            },
            bottom: {
                type: Number,
                default: 30
            },
            right: {
                type: Number,
                default: 30
            },
            duration: {
                type: Number,
                default: 1000
            }
        },
        data() {
            return {
                backTop: false
            };
        },
        mounted() {
            document.getElementsByClassName('layout-content')[0].addEventListener('scroll', this.handleScroll, true);
            document.getElementsByClassName('layout-content')[0].addEventListener('resize', this.handleScroll, true);

        },
        beforeDestroy() {
            document.getElementsByClassName('layout-content')[0].removeEventListener('scroll', this.handleScroll, false);
            document.getElementsByClassName('layout-content')[0].removeEventListener('resize', this.handleScroll, false);
        },
        computed: {
            classes() {
                return [
                    `${prefixCls}`,
                    {
                        [`${prefixCls}-show`]: this.backTop
                    }
                ];
            },
            styles() {
                return {
                    bottom: `${this.bottom}px`,
                    right: `${this.right}px`
                };
            },
        },
        methods: {
            handleScroll() {
                this.backTop = document.getElementsByClassName('layout-content')[0].scrollTop >= document.getElementsByClassName('layout-content')[0].clientHeight + 92;
            },
            back() {
                const sTop = document.getElementsByClassName('layout-content')[0].scrollTop;

                this.scrollTop(document.getElementsByClassName('layout-content')[0], sTop, 0, this.duration);
                this.$emit('on-click');
            },
            scrollTop(el, from = 0, to, duration = 5000) {

                const difference = Math.abs(from - to);
                const step = Math.ceil(difference / duration * 50);

                function scroll(start, end) {
                    if (start === end) {
                        return;
                    }

                    el.scrollTop = 0;
                }
                scroll(from, to, step);
            }
        }
    };
</script>
<style lang="scss" scoped>
    .back-top-dom {
        position: fixed;
        z-index: 1002;
        cursor: pointer;
        display: none;

        &.back-top-dom-show {
            display: block;
        }

        .back-top-dom-inner {
            background-color: rgba(0, 0, 0, 0.6);
            border-radius: 2px;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
            transition: all 0.2s ease-in-out;

            .ivu-icon {
                display: inline-block;
                font-family: Ionicons;
                speak: none;
                font-style: normal;
                font-weight: 400;
                font-variant: normal;
                text-transform: none;
                text-rendering: auto;
                line-height: 1;
                -webkit-font-smoothing: antialiased;
                -moz-osx-font-smoothing: grayscale;
                color: #fff;
                font-size: 24px;
                padding: 8px 12px;
            }

            .ivu-icon-chevron-up:before {
                content: "\F126";
            }
        }
    }
</style>