前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >vue.js聊天IM系统|聊天室|群聊

vue.js聊天IM系统|聊天室|群聊

原创
作者头像
andy2018
修改于 2019-04-09 03:42:51
修改于 2019-04-09 03:42:51
13K00
代码可运行
举报
文章被收录于专栏:h5h5
运行总次数:0
代码可运行

vue2.0仿微信聊天室|vue-chatRoom实例项目|vue全家桶仿微信聊天app

基于vue+vuex+vue-router+webpack2.0+es6+wcPop+iconfont等技术开发的仿微信界面聊天室,之前使用h5开发过一版h5聊天室,实现了微信聊天功能、发送消息/表情,图片、视频预览,打赏、红包等功能。

技术栈

  • MVVM框架:Vue.js 2.0
  • 状态管理:Vuex
  • 页面路由:Vue-router
  • 弹窗插件:wcPop
  • 打包工具:webpack 2.0
  • 环境配置:node.js + cnpm
  • 图片插件:vue-photo-preview

页面地址路由、登录拦截:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 *  页面地址路由js
 */ 
import Vue from 'vue'
import _router from 'vue-router'
import store from '../vuex'

Vue.use(_router) //应用路由

const router = new _router({
    routes: [
        // 登录、注册
        {
            path: '/login',
            component: resolve => require(['../views/auth/login'], resolve),
        },
        {
            path: '/register',
            component: resolve => require(['../views/auth/register'], resolve),
        },

        // 首页、通讯录、我
        {
            path: '/',
            component: resolve => require(['../views/index'], resolve),
            meta: { showHeader: true, showTabBar: true, requireAuth: true }
        },
        {
            path: '/contact',
            component: resolve => require(['../views/contact'], resolve),
            meta: { showHeader: true, showTabBar: true, requireAuth: true },
        },
        {
            path: '/contact/uinfo',
            component: resolve => require(['../views/contact/uinfo'], resolve),
        },
        {
            path: '/ucenter',
            component: resolve => require(['../views/ucenter'], resolve),
            meta: { showHeader: true, showTabBar: true, requireAuth: true }
        },
        // 聊天页面
        {
            path: '/chat/group-chat',
            component: resolve => require(['../views/chat/group-chat'], resolve),
            meta: { requireAuth: true }
        },
        {
            path: '/chat/single-chat',
            component: resolve => require(['../views/chat/single-chat'], resolve),
            meta: { requireAuth: true }
        },
        {
            path: '/chat/group-info',
            component: resolve => require(['../views/chat/group-info'], resolve),
            meta: { requireAuth: true }
        }

        // ...
    ]
})

// 注册全局钩子拦截登录状态
const that = this
router.beforeEach((to, from, next) => {
    const token = store.state.token
    // 判断该路由地址是否需要登录权限
    if(to.meta.requireAuth){
        // 通过vuex state获取当前token是否存在
        if(token){
            next()
        }else{
            // console.log('还未登录授权!')
            next()
            wcPop({
                content: '还未登录授权!', style: 'background:#e03b30;color:#fff;', time: 2,
                end: function(){
                    next({ path: '/login' })
                }
            });
        }
    }else{
        next()
    }
})

export default router

vue聊天界面源码片段:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// >>> 【表情、动图swiper切换模块】--------------------------
        var emotionSwiper;
        function setEmotionSwiper(tmpl) {
            var _tmpl = tmpl ? tmpl : $("#J__emotionFootTab ul li.cur").attr("tmpl");
            $("#J__swiperEmotion .swiper-container").attr("id", _tmpl);
            $("#J__swiperEmotion .swiper-wrapper").html($("." + _tmpl).html());

            emotionSwiper = new Swiper('#' + _tmpl, {
                // loop: true,
                // autoplay: true,
                // 分页器
                pagination: {
                    el: '.pagination-emotion', clickable: true,
                },
            });
        }
        // 表情模板切换
        $("body").on("click", "#J__emotionFootTab ul li.swiperTmpl", function () {
            // 先销毁swiper
            emotionSwiper && emotionSwiper.destroy(true, true);
            var _tmpl = $(this).attr("tmpl");
            $(this).addClass("cur").siblings().removeClass("cur");

            setEmotionSwiper(_tmpl);
        });


        // >>> 【视频预览模块】--------------------------
        $("body").on("click", "#J__chatMsgList li .video", function () {
            var _src = $(this).find("img").attr("videoUrl"), _video;
            var videoIdx = wcPop({
                id: 'wc__previewVideo',
                skin: 'fullscreen',
				// content: '<video id="J__videoPreview" width="100%" height="100%" controls="controls" x5-video-player-type="h5" x5-video-player-fullscreen="true" webkit-playsinline preload="auto"></video>',
				content: '<video id="J__videoPreview" width="100%" height="100%" controls="controls" preload="auto"></video>',
				shade: false,
                xclose: true,
                style: 'background: #000;padding-top:48px;',
                anim: 'scaleIn',
                show: function(){
                    _video = document.getElementById("J__videoPreview");
                    _video.src = _src;
                    if (_video.paused) {
                        _video.play();
                    } else {
                        _video.pause();
                    }
                    // 播放结束
                    _video.addEventListener("ended", function(){
                        _video.currentTime = 0;
                    });
                    // 退出全屏
                    _video.addEventListener("x5videoexitfullscreen", function(){
                        wcPop.close(videoIdx);
                    })
                }
			});
        });


        // >>> 【编辑器+表情处理模块】------------------------------------------
        // ...处理编辑器信息
        function surrounds() {
            setTimeout(function () { //chrome
                var sel = window.getSelection();
                var anchorNode = sel.anchorNode;
                if (!anchorNode) return;
                if (sel.anchorNode === $(".J__wcEditor")[0] ||
                    (sel.anchorNode.nodeType === 3 && sel.anchorNode.parentNode === $(".J__wcEditor")[0])) {

                    var range = sel.getRangeAt(0);
                    var p = document.createElement("p");
                    range.surroundContents(p);
                    range.selectNodeContents(p);
                    range.insertNode(document.createElement("br")); //chrome
                    sel.collapse(p, 0);

                    (function clearBr() {
                        var elems = [].slice.call($(".J__wcEditor")[0].children);
                        for (var i = 0, len = elems.length; i < len; i++) {
                            var el = elems[i];
                            if (el.tagName.toLowerCase() == "br") {
                                $(".J__wcEditor")[0].removeChild(el);
                            }
                        }
                        elems.length = 0;
                    })();
                }
            }, 10);
        }

        // 定义最后光标位置
        var _lastRange = null, _sel = window.getSelection && window.getSelection();
        var _rng = {
            getRange: function () {
                if (_sel && _sel.rangeCount > 0) {
                    return _sel.getRangeAt(0);
                }
            },
            addRange: function () {
                if (_lastRange) {
                    _sel.removeAllRanges();
                    _sel.addRange(_lastRange);
                }
            }
        }

        // 格式化编辑器包含标签
        $("body").on("click", ".J__wcEditor", function(){
            $(".wc__choose-panel").hide();
        });
        $("body").on("focus", ".J__wcEditor", function(){
            surrounds();
        });
        $("body").on("input", ".J__wcEditor", function(){
            surrounds();
        });

        // 点击表情
        $("body").on("click", "#J__swiperEmotion .face-list span img", function () {
            var that = $(this), range;

            if (that.hasClass("face")) { //小表情
                var img = that[0].cloneNode(true);
                if (!$(".J__wcEditor")[0].childNodes.length) {
                    $(".J__wcEditor")[0].focus();
                }
                $(".J__wcEditor")[0].blur(); //输入表情时禁止输入法

                setTimeout(function () {
                    if (document.selection && document.selection.createRange) {
                        document.selection.createRange().pasteHTML(img);
                    } else if (window.getSelection && window.getSelection().getRangeAt) {
                        range = _rng.getRange();
                        range.insertNode(img);
                        range.collapse(false);

                        _lastRange = range; //记录当前光标位置 (否则光标会跑到表情前面)
                        _rng.addRange();
                    }
                }, 10);
            } else if (that.hasClass("del")) { //删除
                // _editor.focus();
                $(".J__wcEditor")[0].blur(); //输入表情时禁止输入法

                setTimeout(function () {
                    range = _rng.getRange();
                    range.collapse(false);
                    document.execCommand("delete");

                    _lastRange = range;
                    _rng.addRange();
                }, 10);
            } else if (that.hasClass("lg-face")) { //大表情
                var _img = that.parent().html();
                var _tpl = [
                    '<li class="me">\
                        <div class="content">\
                            <p class="author">王梅(Fine)</p>\
                            <div class="msg lgface">'+ _img + '</div>\
                        </div>\
                        <a class="avatar" href="/contact/uinfo"><img src="src/assets/img/uimg/u__chat-img11.jpg" /></a>\
                    </li>'
                ].join("");
                $("#J__chatMsgList").append(_tpl);

                wchat_ToBottom();
            }
        });

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
3 条评论
热度
最新
不行,映射好像不太对,我docker里的nginx.conf是在/etc/nginx/下面
不行,映射好像不太对,我docker里的nginx.conf是在/etc/nginx/下面
回复回复1举报
[emerg] no "events" section in configuration 启动会报这个错无解
[emerg] no "events" section in configuration 启动会报这个错无解
11点赞举报
https://blog.csdn.net/awen6666/article/details/107734184/
https://blog.csdn.net/awen6666/article/details/107734184/
回复回复点赞举报
推荐阅读
Android6.0运行时权限处理
ContextCompat.checkSelfPermission:用于检测某个权限是否已经被授予
用户1205080
2018/12/17
1.2K0
XYLibrary笔记七:XPermission使用笔记
将JitPack存储库添加到您的构建文件中 将其添加到存储库末尾的root build.gradle中:
项勇
2023/03/24
5430
XYLibrary笔记七:XPermission使用笔记
Android 6.0 运行时权限处理问题
序 自从升级到Android M以来,最大的改变就是增加了运行时权限RuntimePermission,6.0以上的系统如果没有做适配,运行了targetSDK=23的App时就会报权限错误。我们知道6.0以下的系统是按照的时候权限申请的,6.0和之后的版本是我们想要使用某个app的权限,去动态申请的,这也是基于安全上的考虑吧(比如:单机的象棋对战,请求访问通讯录权限等不合理的权限,这肯定是有问题的)。 为了保护用户的隐私,谷歌官方将权限分为了两类,一个是正常权限(Normal Permissions),这
xiangzhihong
2018/02/05
1.1K0
Android 6.0 运行时权限处理问题
Android基于EasyPermission封装实现快速权限申请
本篇是 Android 快速开发框架 ardf的第三篇,将主要介绍在 Android 开发中对权限申请的封装使用,随着 Android 系统的不断升级,Google 对权限的使用越来越严格,用户也越来越重视权限的授权,开发中很多权限都需要动态申请并取得用户授权后才能正常使用,这就导致开发中对权限申请的操作越来越频繁,那么一个对权限申请的好的封装就能大大的节省开发者的工作量、提升开发效率。 在 ardf 中则是基于 Google 提供的 EasyPermission 库进行二次封装,将权限申请的复杂处理进行简化,使用时只需关注要申请的权限以及申请成功、申请失败后的业务处理即可。
loongwind
2023/01/01
2K0
Android基于EasyPermission封装实现快速权限申请
【Android从零单排系列四十四】《聊一下Android数据权限permission》
小伙伴们,在前面的几篇文章中,我们谈到了Android开发中的几种数据存储方式及数据持久化,本文我们介绍下Android开发中的另一部分内容,权限管理。
再见孙悟空_
2023/07/17
1.2K0
Android 开发者必知必会的权限管理知识
导语 本文主要讲解了Android 权限管理方面几个点: Android 权限背景知识; 权限检查及权限兼容; 跳转到app管理权限页面 一、Android 权限背景知识 提到Android 权限管理,业内人士都知道Google 在Android 6.0时提出了运行时权限管理机制,在Android 6.0之前,所申请的权限只需要在AndroidManifest.xml列举就可以,从而容易导致一些安全隐患,因此,在Android 6.0 时,Google 为了更好的保护用户隐私提出了新的权限管理机制(官网
腾讯Bugly
2018/03/23
1.8K0
Android权限申请与打开权限设置页面
应用的使用需要申请权限,但是如果用户禁用掉,或者禁用并不再提醒就必须到系统设置中开启。
码客说
2020/07/03
5.9K0
PermissionX 1.7发布,全面支持Android 13运行时权限
还记得上次发布PermissionX 1.6版本还是在去年10月份的时候,当时是对Android 12系统进行了支持。详情可以参考这篇文章 PermissionX 1.6发布,支持Android 12,可能是今年最大的版本升级 。
用户1158055
2022/11/07
3.8K0
PermissionX 1.7发布,全面支持Android 13运行时权限
Android权限管理原理(4.3-6.x)
Android系统在MarshMallow之前,权限都是在安装的时候授予的,虽然在4.3时,Google就试图在源码里面引入AppOpsManager来达到动态控制权限的目的,但由于不太成熟,在Release版本中都是把这个功能给隐藏掉的。在6.0之后,Google为了简化安装流程且方便用户控制权限,正式引入了runtime-permission,允许用户在运行的时候动态控制权限。对于开发而言就是将targetSdkVersion设置为23,并且在相应的时机动态申请权限,在适配了Android6.0的App运行在Android 6.0+的手机上时,就会调用6.0相关的API,不过在低版本的手机上,仍然是按安装时权限处理。
看书的小蜗牛
2018/06/29
2.6K3
Android权限管理原理(4.3-6.x)
Android6.0权限适配及兼容库的实现
从6.0 MarshMallow开始,Android支持动态权限管理,即有些权限需要在使用到的时候动态申请,根据用户的选择需要有不同的处理,具体表现可以看下图:
看书的小蜗牛
2018/06/29
9160
Android6.0权限适配及兼容库的实现
PermissionX 1.5发布,支持申请Android特殊权限啦
Hello大家早上好,说起PermissionX,其实我已经有段时间没有更新这个框架了。一是因为现在工作确实比较忙,没有过去那么多的闲暇时间来写开源项目,二是因为,PermissionX的主体功能已经相当稳定,并不需要频繁对其进行变更。
用户1158055
2021/07/29
1.1K0
PermissionX 1.5发布,支持申请Android特殊权限啦
一个类快速实现 Android 6.0 运行时权限适配
现在来谈 Android 6.0 运行时权限适配,可以说是很过时了,可是为什么还要写呢? 一是试用了目前 GitHub 上排名比较靠前的开源项目,确实都很棒,但是在易用性还是难以令人满意,便萌生了自己撸一个的想法。 二是看了下目前国内主流的应用,发现很多都还没有适配 Android 6.0 ,因此觉得这篇文章还有它的意义。
全栈程序员站长
2021/06/22
2930
PermissionX 1.6发布,支持Android 12,可能是今年最大的版本升级
没错,PermissionX又升级了,并且这次版本变化非常大,很有可能是今年最大幅度的一次升级。
用户1158055
2021/10/13
9580
最简单的Flutter权限管理插件
这是Flutter上的一个动态权限处理的插件库,可以让Flutter应用层的开发者以非常简单的API统一处理原生的动态权限。它封装了关于权限的检查、请求,以及权限被永久拒绝时,适当的拉起系统设置页面,提示用户手动打开权限。几乎想不到拒绝使用它的理由。
arcticfox
2021/05/03
2K0
为什么说在Android中请求权限从来都不是一件简单的事情?
周末时间参加了东莞和深圳的两场GDG,因为都是线上参与,所以时间上并不赶,我只需要坐在家里等活动开始就行了。
用户1158055
2020/07/29
1.5K0
为什么说在Android中请求权限从来都不是一件简单的事情?
Android6.0动态权限适配&XMPermissions
从 Android 6.0(API 级别 23)开始,用户开始在应用运行时向其授予权限,而不是在应用安装时授予。此方法可以简化应用安装过程,因为用户在安装或更新应用时不需要授予权限。它还让用户可以对应用的功能进行更多控制;例如,用户可以选择为相机应用提供相机访问权限,而不提供设备位置的访问权限。用户可以随时进入应用的“Settings”屏幕调用权限。摘自Android官网:在运行时请求权限。
静默加载
2020/05/29
1.4K0
如何优雅地申请Android运行时权限
Android 是一个权限分隔的操作系统,其中每个应用都有其独特的系统标识。在默认情况下任何应用都没有权限执行对其他应用、操作系统或用户有不利影响的任何操作。这包括读取或写入用户的私有数据(例如联系人或电子邮件)、读取或写入其他应用程序的文件、执行网络访问、使设备保持唤醒状态等。
yuanyi928
2020/04/21
3.4K0
如何优雅地申请Android运行时权限
PermissionX现在支持Java了!还有Android 11权限变更讲解
各位小伙伴们早上好,不知道你们有没有惊讶于我的速度,因为不久之前我才新发布的开源库PermissionX今天又更新了。
用户1158055
2020/06/16
1.7K0
PermissionX现在支持Java了!还有Android 11权限变更讲解
Android6.0权限控制
  随着android6.0的更新,最大的变化莫过于新的权限控制规则。以前可以直接通过AndroidManifest配置需要的权限。而更新后,为了保证用户隐私的安全性,部分私密权限需要动态的设置,仅仅在AndroidManifest中配置已经完全不能满足需求了。   当然为了达到兼容,项目使用的SDK如果是在23之前(即6.0之前)那么会依照之前的规则直接在AndroidManifest中设置即可。而当SDK升级到6.0后,例如录音、相册、定位等私密信息,就需要按照新的规则动态的申请权限。   本文提供一个权限管理类来使开发者能够快速在6.0中配置好自己需要的权限。
饮水思源为名
2018/09/06
4480
PermissionX重磅更新,支持自定义权限提醒对话框
大家早上好,今天带来一篇原创。很高兴告诉大家,PermissionX又出新版本了。
用户1158055
2020/07/21
1.9K0
推荐阅读
相关推荐
Android6.0运行时权限处理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档