直播聊天消息滚动效果实现

实现的效果如下


7f8742e08764771fb614f6bf3b03a33f.gif

直接上代码吧

<!DOCTYPE html>
<html lang="en">

<head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="css/zhibo.css" rel="stylesheet">
</head>

<body>
    <div id="app">
        <!-- 留言输入框 -->
        <div class="liu-input" v-if="showLy">
            <div class="input-pre" @click="inpFocue" v-if="isShowXie">
                <img class="input-xie" src="./img/xie.png" alt="">
                <span class="input-tip">发表留言... ... </span>
            </div>
            <input type="text" v-model="txt" ref="inp" maxlength="40" @focus="inputFocue" @blur="inputBlur" class="input-txt">
            <div v-if="txt" class="send-act" @click="add(txt, true)"></div>
            <img src="./img/send_img.png" v-if="txt" class="input-send" alt="">
        </div>

        <!-- 留言板 -->
        <div class="out" v-if="showLy">
        </div>
        <div class="out-con" v-if="showLy">
            <div class="con-1">
                <div class="title">
                    <img src="./img/axly.png" class="title-left" alt="">
                    <div @click="hideLy" class="title-right">收起
                        <img class="right-jian" src="./img/jian_tou.png" alt="">
                    </div>
                </div>
                <div class="content-out">
                    <div class="content" ref="box" :class="{anim:animate==true}">
                        <div class="msg" v-for="(item, index) in arr" :key="index">
                            <div class="userInfo">
                                <div class="name" :style="{width:item.name.length*1.125 + 'rem'}">{{ item.name }}</div>
                                <div class="fd" v-if="item.fdName">{{ item.fdName ? item.fdName : '' }}</div>

                            </div>
                            <div class="li">
                                <span>{{ item.content }}</span>
                            </div>
                        </div>
                    </div>
                </div>

            </div>
        </div>

        <!-- 打开留言板按钮 -->
        <div class="jiao_biao" @click="showLyFun" v-if="!showLy">
            <img src="./img/ly_xin.png" alt="">
            <p>爱心留言</p>
        </div>
    </div>
    <script src="./js/data.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        let data1 = data;
        console.log(data1);
        var app = new Vue({
            el: '#app',
            data() {
                return {
                    txt: '',
                    isShowXie: true,
                    arr: [],
                    scrollDistance: 0,
                    items: [],
                    list: [],
                    showLy: false,
                    i: 5,
                    guaqi: false,
                    animate: false
                }
            },
            watch: {
                // 监听展示的数组 根据数组变化 实现滚动
                arr: {
                    handler() {
                        console.log(this.arr.length);
                        let time;
                        if (!this.showLy) {
                            return;
                        }
                        if (this.isSend) {
                            time = 100;
                        } else {
                            time = 1500;
                        }
                        setTimeout(() => {
                            let node = document.querySelector(".content-out");
                            let node1 = document.querySelector(".content");
                            if (node) {
                                this.scrollDistance = node1.clientHeight - node.clientHeight;
                                if (this.scrollDistance > 0) {
                                    this.animate = true;
                                    node1.style.transform = 'translateY(-' + this.scrollDistance + 'px)';
                                }
                            }
                        }, time);
                    },
                },
            },
            created() {
                this.getNoteList();
            },
            mounted() {
                // 网页挂起和唤醒时的操作 挂起时暂停 唤起开始
                document.addEventListener("visibilitychange", () => {
                    if (document.hidden) { //网页被挂起
                        this.guaqi = true;
                    } else {
                        this.guaqi = false;
                        let xxx = window.setInterval(() => {
                            if (!this.showLy || this.guaqi) {
                                window.clearInterval(xxx);
                                if (this.arr.length > 10) {
                                    this.arr = this.arr.slice(this.arr.length - 5);
                                }
                                return;
                            }
                            if (this.i > this.items.length - 1) {
                                this.i = 0;
                            }
                            this.add(this.items[this.i]);
                            this.i++;
                        }, 1500);
                    }
                })
            },
            methods: {
                // 留言模块
                getSubName(name) {
                    let newName;
                    if (name) {
                        if (name.length > 3) {
                            newName = name.substring(0, 3) + '...';
                        } else {
                            newName = name;
                        }
                    } else {
                        newName = '';
                    }
                    return newName;
                },
                // 获取留言列表
                getNoteList() {
                    var _this = this;
                    let items = data1;
                    // 此处先展示五笔 与i相对应 为的是:一进留言板 留言板不空荡
                    for (let index = 0; index < 5; index++) {
                        const ele = items[index];
                        ele.name = _this.getSubName(ele.name);
                        _this.arr = [
                            ..._this.arr,
                            ele,
                        ];
                    }
                    _this.items = items;
                    setTimeout(() => {
                            _this.showLy = true;
                        }, 1000)
                        // 开始滚动
                    let xxx = window.setInterval(() => {
                        if (!_this.showLy || _this.guaqi) {
                            window.clearInterval(xxx);
                            if (_this.arr.length > 10) {
                                _this.arr = _this.arr.slice(_this.arr.length - 5);
                            }
                            return;
                        }
                        if (_this.i > _this.items.length - 1) {
                            _this.i = 0;
                        }
                        _this.add(_this.items[_this.i]);
                        _this.i++;
                    }, 1500);
                },
                // 点击输入框
                inpFocue() {
                    this.$refs.inp.focus();
                },
                // 聚焦时隐藏提示文字
                inputFocue() {
                    this.isShowXie = false;
                },
                // 失去焦点时展示提示文字
                inputBlur() {
                    if (!this.txt) {
                        this.isShowXie = true;
                    }
                },
                // 新增留言
                add(element, flag) {
                    if (!element) {
                        return;
                    }
                    this.isSend = flag;
                    if (flag) {
                        if (element.length > 40) {
                            this.showMegClickFa('内容过长哦~');
                            return;
                        }
                        this.userName = '懿小诺'
                        this.fdName = '滁州'
                        console.log(this.userName);
                        let temp = {
                            "content": element,
                            "fdName": this.fdName ? this.fdName : '',
                            "id": "",
                            "name": this.getSubName(this.userName)
                        };
                        console.log(temp);
                        this.arr = [
                            ...this.arr,
                            temp
                        ];
                        this.items = [
                            ...this.items, {
                                "content": element,
                                "fdName": this.fdName ? this.fdName : '',
                                "id": "",
                                "name": this.getSubName(this.userName)
                            },
                        ];
                        // 。。。调服务提交
                        var _this = this;
                        console.log('内容', _this.txt);
                        console.log('留言成功');
                        _this.txt = '';
                       _this.inputBlur();
                    } else {
                        this.arr = [
                            ...this.arr,
                            element
                        ];
                    }
                },
                // 收起留言板
                hideLy() {
                    this.txt = ''
                    this.showLy = false;
                },
                // 展开留言板
                showLyFun() {
                    this.showLy = true;
                    let xxx = window.setInterval(() => {
                        if (!this.showLy || this.guaqi) {
                            window.clearInterval(xxx);
                            if (this.arr.length > 10) {
                                this.arr = this.arr.slice(this.arr.length - 5);
                            }
                            return;
                        }
                        if (this.i > this.items.length - 1) {
                            this.i = 0;
                        }
                        this.add(this.items[this.i]);
                        this.i++;
                    }, 1500);
                }
            }
        })
    </script>
</body>

</html>

css文件

html {
    font-size: 16px;
}

body {
    width: 100%;
    height: 100vh;
    background-color: pink;
}

* {
    padding: 0;
    margin: 0;
}

.liu-input {
    position: fixed;
    height: 3.125rem;
    bottom: 0;
    left: 0;
    width: 100%;
    z-index: 90;
    padding: 0 1.125rem;
    box-sizing: border-box;
    align-items: center;
    display: flex;
    background-color: #fff;
}

.liuyan {
    position: relative;
    height: 3.125rem;
    padding: 0 1.125rem;
    width: 100%;
    box-sizing: border-box;
    align-items: center;
    display: flex;
    background-color: #fff;
}

.input-txt,
.input-txt-area {
    flex: 1;
    padding: 0.5625rem 0.9375rem;
    border: 0;
    background: #F2F3F4;
    border-radius: 0.9375rem;
    outline: none;
    color: #3F444D;
    font-size: 0.875rem;
}

.input-txt-area {
    resize: none;
    vertical-align: top;
    outline: none;
    line-height: 1.25rem;
}

.input-pre {
    position: absolute;
    left: 2.0625rem;
}

.input-xie {
    width: 0.75rem;
}

.input-tip {
    color: #A2A6A7;
    font-size: 0.8125rem;
}

.input-send {
    margin-left: -2.3rem;
    display: block;
    width: 1.5rem;
    height: 1.5rem;
}

.send-act {
    width: 3.125rem;
    height: 2.5rem;
}


/* 角标 */

@keyframes sca {
    0% {
        transform: scale(0.8);
    }
    100% {
        transform: scale(1.2);
    }
}

.jiao_biao {
    position: fixed;
    left: 1rem;
    bottom: 6rem;
    /* bottom: 1.625rem; */
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    background-color: #FFCC00;
    padding-top: 0.5rem;
    box-sizing: border-box;
    text-align: center;
    z-index: 80;
    animation: sca 1s ease infinite forwards;
}

.jiao_biao img {
    width: 1.4375rem;
}

.jiao_biao p {
    color: #fff;
    font-size: 0.75rem;
}


/* 留言板 */

.out {
    position: fixed;
    left: 1.125rem;
    width: 80%;
    height: 430px;
    background-color: #000;
    opacity: 0.6;
    bottom: 4.25rem;
    z-index: 80;
    border-radius: 0.625rem;
    overflow: hidden;
}

.title {
    width: 100%;
    padding-left: 1.0625rem;
    padding-right: 1.0625rem;
    display: flex;
    height: 50px;
    font-size: 0.875rem;
    align-items: center;
}

.title-left {
    width: 4.8125rem;
}

.title-right {
    color: #fff;
    flex: 1;
    text-align: end;
}

.right-jian {
    width: 0.75rem;
    vertical-align: baseline;
}

.content {
    /* width: 96%; */
    width: 100%;
    /* height: 360px; */
    font-size: 0.875rem;
    transition: all 1s;
}

.content-out {
    width: 96%;
    height: 360px;
    padding-left: 0.9375rem;
    overflow: hidden;
}

.userInfo {
    display: flex;
    height: 30px;
    align-items: center;
    color: #ffffff;
}

.name {
    font-size: 1.125rem;
    max-width: 4.5rem;
}

.fd {
    max-width: calc(100% - 75px);
    margin-left: 0.25rem;
    padding: 0.0625rem 0.75rem;
    background-color: #9fa6ac;
    font-size: 0.75rem;
    border-radius: 0.875rem;
    margin-top: 0.125rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.li {
    padding: 0.3125rem 0.625rem;
    margin-bottom: 0.75rem;
    background: #ffffff;
    border-radius: 0px 0.6875rem 0.6875rem 0.6875rem;
}

.out-con {
    position: fixed;
    left: 1.125rem;
    width: 80%;
    height: 430px;
    bottom: 4.25rem;
    z-index: 81;
}

.con-1 {
    position: relative;
    width: 90%;
    height: 430px;
}

.msg {
    position: relative;
    opacity: 0;
    animation: scro 0.5s 0.2s ease forwards;
}

@keyframes scro {
    100% {
        opacity: 1;
    }
}

.anim {
    position: relative;
    transition: all 0.5s;
}

自造的假数据

let data = [{
    "content": "1",
    "fdName": "霸都合肥友爱啊",
    "id": "395",
    "mrkMonth": "",
    "name": "尚云飞",
    "userId": ""
}, {
    "content": "2",
    "fdName": "南京啊",
    "id": "393",
    "mrkMonth": "",
    "name": "梦梦子",
    "userId": ""
}, {
    "content": "3",
    "fdName": "南京啊",
    "id": "392",
    "mrkMonth": "",
    "name": "梦梦子",
    "userId": ""
}, {
    "content": "4",
    "fdName": "南京啊",
    "id": "391",
    "mrkMonth": "",
    "name": "梦梦子",
    "userId": ""
}, {
    "content": "5",
    "fdName": "南京啊",
    "id": "390",
    "mrkMonth": "",
    "name": "梦梦子",
    "userId": ""
}, {
    "content": "6",
    "fdName": "南京啊",
    "id": "389",
    "mrkMonth": "",
    "name": "梦梦子",
    "userId": ""
}, {
    "content": "7",
    "fdName": "南京啊",
    "id": "388",
    "mrkMonth": "",
    "name": "梦梦子",
    "userId": ""
}, {
    "content": "😄😄😄",
    "fdName": "合肥啊",
    "id": "387",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "9",
    "fdName": "合肥啊",
    "id": "386",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "10",
    "fdName": "合肥啊",
    "id": "385",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "11",
    "fdName": "南京啊",
    "id": "384",
    "mrkMonth": "",
    "name": "梦梦子",
    "userId": ""
}, {
    "content": "12",
    "fdName": "南京啊",
    "id": "383",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "13",
    "fdName": "南京啊",
    "id": "382",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "14",
    "fdName": "南京啊",
    "id": "381",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "15",
    "fdName": "南京啊",
    "id": "380",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "合肥合肥好",
    "fdName": "南京啊",
    "id": "379",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "17",
    "fdName": "南京啊",
    "id": "378",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "18",
    "fdName": "南京啊",
    "id": "377",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "19",
    "fdName": "南京啊",
    "id": "376",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "继续进行",
    "fdName": "南京啊",
    "id": "375",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "21",
    "fdName": "南京啊",
    "id": "374",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "22",
    "fdName": "南京啊",
    "id": "373",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "23",
    "fdName": "南京啊",
    "id": "372",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "24",
    "fdName": "南京啊",
    "id": "371",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "25",
    "fdName": "南京啊",
    "id": "370",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "26",
    "fdName": "南京啊",
    "id": "369",
    "mrkMonth": "",
    "name": "小梦子",
    "userId": ""
}, {
    "content": "27",
    "fdName": "合肥啊",
    "id": "368",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "28",
    "fdName": "合肥啊",
    "id": "367",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "9",
    "fdName": "合肥啊",
    "id": "366",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "30",
    "fdName": "合肥啊",
    "id": "365",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "7",
    "fdName": "合肥啊",
    "id": "364",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "6",
    "fdName": "合肥啊",
    "id": "363",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "5",
    "fdName": "合肥啊",
    "id": "362",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "4",
    "fdName": "合肥啊",
    "id": "360",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "3",
    "fdName": "合肥啊",
    "id": "359",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "2",
    "fdName": "合肥啊",
    "id": "358",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}, {
    "content": "1",
    "fdName": "合肥啊",
    "id": "357",
    "mrkMonth": "",
    "name": "孟是琬",
    "userId": ""
}]

有不懂的可以问哦 一起学习~

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