运用 angular+angular-cli+angular-router+ngrx/store+rxjs+webpack+node+wcPop 等技术实现开发的仿微信 angular 版聊天室 angular-chatroom 实例项目,实现了下拉刷新、聊天消息右键菜单、发送消息、表情(动图),图片、视频预览,红包打赏等功能。
- MVVM 框架:angular8.0 / @angular/cli
- 状态管理:@ngrx/store / rxjs
- 地址路由:@angular/router
- 弹窗组件:wcPop
- 打包工具:webpack 2.0
- 环境配置:node.js + cnpm
- 图片预览:previewImage
- 轮播滑动:swiper
{
"name": "angular-chatroom",
"dependencies": {
"@angular/animations": "~8.0.1",
"@angular/common": "~8.0.1",
"@angular/compiler": "~8.0.1",
"@angular/core": "~8.0.1",
"@angular/forms": "~8.0.1",
"@angular/platform-browser": "~8.0.1",
"@angular/platform-browser-dynamic": "~8.0.1",
"@angular/router": "~8.0.1",
"rxjs": "~6.4.0",
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.800.0",
"@angular/cli": "~8.0.3",
"@angular/compiler-cli": "~8.0.1",
"@angular/language-service": "~8.0.1",
"@ngrx/store": "^8.0.1",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"@types/swiper": "^4.4.3",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"jquery": "^2.2.3",
"karma": "~4.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"swiper": "^4.5.0",
}
}
/*
* angular 主模块配置
*/
import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { AppRoutingModule } from './app-routing.module'
// 引入状态管理
import { StoreModule } from '@ngrx/store'
import { reducer } from '../ngrx'
// 载入公共组件( component )
import { HeaderComponent } from '../components/header'
import { TabBarComponent } from '../components/tabbar'
import { XtnScroll } from '../components/xtnScroll/Scroll'
import { NotFoundComponent } from '../components/404'
// 载入页面组件( view )
import { AppComponent } from './app.component'
import { LoginComponent } from '../views/auth/login'
import { RegisterComponent } from '../views/auth/register'
import { IndexComponent } from '../views/index'
import { ContactComponent } from '../views/contact'
import { UinfoComponent } from '../views/contact/uinfo'
import { UcenterComponent } from '../views/ucenter'
import { GroupChatComponent } from '../views/chat/group-chat'
import { GroupInfoComponent } from '../views/chat/group-info'
import { SingleChatComponent } from '../views/chat/single-chat'
@NgModule({
declarations: [
// 公共组件
HeaderComponent,
TabBarComponent,
XtnScroll,
NotFoundComponent,
// 页面组件
AppComponent,
LoginComponent,
RegisterComponent,
IndexComponent,
ContactComponent,
UinfoComponent,
UcenterComponent,
GroupChatComponent,
GroupInfoComponent,
SingleChatComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
StoreModule.forRoot(reducer)
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
/*
* angular 路由守卫(验证 token )
*/
import { Router, CanActivate } from '@angular/router'
declare var wcPop: any;
export class Auth implements CanActivate{
constructor(private router: Router){}
canActivate(){
let that = this
// 验证 token
const token: boolean = window.sessionStorage.getItem('token') ? true : false
if(!token){
// 未登录授权
/*
wcPop({
content: '还未登录授权!', anim: 'shake', style: 'background:#e03b30;color:#fff;', time: 2,
end: function () {
that.router.navigate(['/login']);
}
});
*/
that.router.navigate(['/login']);
}
return token
}
}
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);
}
}
}
// 消息处理
function isEmpty() {
// var html = $editor.html();
var html = $(".J__wcEditor").html();
html = html.replace(/<br[\s\/]{0,2}>/ig, "\r\n");
html = html.replace(/<[^img].*?>/ig, "");
html = html.replace(/ /ig, "");
return html.replace(/\r\n|\n|\r/, "").replace(/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, "") == "";
}
欢迎大家一起交流学习 Q:282310962 wx:xy190310
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.