vue2.0聊天室vue-chatRoom|仿微信界面vue+vuex+vueRouter

Vue2.0+Vuex+VueRouter仿微信界面聊天室|仿微信聊天窗口|仿微信群聊

基于vue2.0+vuex+webpack2.0+es6+wcPop等技术开发的仿微信聊天室vue-weChatRoom实战项目,实现了下拉刷新聊天消息,发送信息、表情(gif),预览大图、视频,打赏、红包等功能。

h5仿微信聊天室:https://blog.csdn.net/yanxinyun1990/article/details/84890686

  

◆ vue-router页面地址路由:

/*
 *  页面地址路由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

◆ vuex状态管理器

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        user: window.sessionStorage.getItem('user'),
        token: window.sessionStorage.getItem('token')
    },
    mutations: {
        // 将token存储到sessionStorage
        SET_TOKEN (state, data){
            state.token = data;
            window.sessionStorage.setItem('token', data);
        },
        // 获取用户名
        SET_USER (state, data){
            state.user = data;
            window.sessionStorage.setItem('user', data);
        },
        // 退出
        LOGOUT (state){
            state.user = null;
            state.token = null;
            window.sessionStorage.removeItem('user');
            window.sessionStorage.removeItem('token');
        }
    },
    getters:{}
})
// >>> 【表情、动图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();
	}
});

 

以下是一个简单的 Vue.js 实现模拟微信聊天界面,输入任何文字统一回复‘你好’的完整代码: ``` <template> <div class="chat-room"> <div class="chat-container"> <div class="chat-msg" v-for="(msg, index) in messages" :key="index"> <div class="chat-avatar"> <img :src="msg.avatar" alt="avatar" /> </div> <div class="chat-content"> <div class="chat-info"> <span class="chat-name">{{ msg.name }}</span> <span class="chat-time">{{ msg.time }}</span> </div> <div class="chat-text">{{ msg.text }}</div> </div> </div> </div> <div class="chat-input"> <input type="text" v-model="inputText" @keyup.enter="sendMessage" /> <button @click="sendMessage">发送</button> </div> </div> </template> <script> export default { name: "ChatRoom", data() { return { inputText: "", messages: [ { avatar: "https://i.pravatar.cc/50?img=1", name: "小明", time: "2021-10-01 12:00", text: "你在干嘛?", }, { avatar: "https://i.pravatar.cc/50?img=2", name: "小红", time: "2021-10-01 12:05", text: "我在看电影,你呢?", }, { avatar: "https://i.pravatar.cc/50?img=3", name: "小明", time: "2021-10-01 12:10", text: "我在写代码", }, ], }; }, methods: { sendMessage() { if (this.inputText.trim() === "") return; const time = new Date().toLocaleString(); const newMessage = { avatar: "https://i.pravatar.cc/50?img=4", name: "我", time, text: this.inputText, }; this.messages.push(newMessage); this.inputText = ""; setTimeout(() => { const reply = { avatar: "https://i.pravatar.cc/50?img=5", name: "小机器人", time: new Date().toLocaleString(), text: "你好", }; this.messages.push(reply); }, 1000); }, }, }; </script> <style> .chat-room { height: 100vh; display: flex; flex-direction: column; } .chat-container { height: calc(100% - 50px); overflow-y: scroll; padding: 10px; } .chat-msg { display: flex; margin-bottom: 10px; } .chat-avatar { margin-right: 10px; } .chat-avatar img { width: 50px; height: 50px; border-radius: 50%; } .chat-info { display: flex; justify-content: space-between; margin-bottom: 5px; } .chat-name { font-weight: bold; } .chat-time { color: #999; } .chat-text { word-wrap: break-word; } .chat-input { display: flex; justify-content: space-between; align-items: center; height: 50px; background-color: #fafafa; padding: 10px; } .chat-input input { flex: 1; height: 30px; border: none; border-radius: 5px; padding: 5px; } .chat-input button { height: 30px; margin-left: 10px; } </style> ``` 这段代码实现了一个简单的聊天室界面,包括消息列表、发送消息输入框和发送按钮。其中,消息列表使用 `v-for` 指令遍历 `messages` 数组,每个消息包括头像、昵称、时间和文本内容。发送消息时,通过 `v-model` 指令绑定输入框的值,通过 `@keyup.enter` 监听回车键事件或者点击发送按钮时调用 `sendMessage` 方法,将新消息添加到 `messages` 数组中,并且通过 `setTimeout` 函数模拟了一个简单的自动回复,即在 1 秒后添加一个 “你好” 的消息到 `messages` 数组中。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaoyan_2018

你的鼓励将是我持续作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值