一、项目介绍
运用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",
- "contact": "QQ:282310962 、 wx:xy190310",
- "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",
- "tslib": "^1.9.0",
- "zone.js": "~0.9.1"
- },
- "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",
- "typescript": "~3.4.3"
- }
- }












◆ App主页面模板、app-routing路由地址配置
- <div class="weChatIM__panel clearfix">
- <div class="we__chatIM-wrapper flexbox flex__direction-column">
- <!-- 顶部 -->
- <header-bar></header-bar>
-
- <!-- 主页面 -->
- <div class="wcim__container flex1">
- <router-outlet></router-outlet>
- </div>
-
- <!-- 底部 -->
- <tab-bar></tab-bar>
- </div>
- </div>
- /*
- * angular/router路由配置
- */
- import { NgModule } from '@angular/core'
- import { Routes, RouterModule } from '@angular/router'
-
- // 引入路由验证
- import { Auth } from '../views/auth/auth'
-
- // 引入页面组件
- import { NotFoundComponent } from '../components/404'
- 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'
- export const routes: Routes = [
- {
- path: '', redirectTo: 'index', pathMatch: 'full',
- data: { showHeader: true, showTabBar: true },
- },
- // 登录、注册
- {
- path: 'login', component: LoginComponent,
- },
- {
- path: 'register', component: RegisterComponent,
- },
- // 首页、联系人、我
- {
- path: 'index', component: IndexComponent, canActivate: [Auth],
- data: { showHeader: true, showTabBar: true },
- },
- {
- path: 'contact', component: ContactComponent, canActivate: [Auth],
- data: { showHeader: true, showTabBar: true },
- },
- {
- path: 'contact/uinfo', component: UinfoComponent
- },
- {
- path: 'ucenter', component: UcenterComponent, canActivate: [Auth],
- data: { showHeader: false, showTabBar: true },
- },
- // 聊天页面
- {
- path: 'chat/group-chat', component: GroupChatComponent, canActivate: [Auth]
- },
- {
- path: 'chat/single-chat', component: SingleChatComponent, canActivate: [Auth]
- },
- {
- path: 'chat/group-info', component: GroupInfoComponent, canActivate: [Auth]
- },
- // 404
- {
- path: '**', component: NotFoundComponent,
- },
- // ...
- ];
- @NgModule({
- // imports: [RouterModule.forRoot(routes)],
- imports: [RouterModule.forRoot(routes, { useHash: true })], //开启hash模式
- exports: [RouterModule],
- providers: [Auth]
- })
- export class AppRoutingModule {}
◆ angular + ngrx/store页面状态管理

◆ angular登录、注册验证
- export class LoginComponent implements OnInit {
- private formField = {
- tel: '',
- pwd: ''
- }
-
- private auth: any
- constructor(
- private router: Router,
- private store: Store<{}>
- ) {
- let that = this
- this.store.select('auth').subscribe(v => {
- console.log(v)
- that.auth = v;
- })
- }
- ngOnInit(): void {
- if(this.auth.token){
- this.router.navigate(['/index'])
- }
- }
- handleSubmit(){
- let that = this
-
- if(!this.formField.tel){
- wcPop({ content: '手机号不能为空!', style: 'background:#eb5a5c;color:#fff;', time: 2 });
- }else if(!checkTel(this.formField.tel)){
- wcPop({ content: '手机号格式不正确!', style: 'background:#eb5a5c;color:#fff;', time: 2 });
- }else if(!this.formField.pwd){
- wcPop({ content: '密码不能为空!', style: 'background:#eb5a5c;color:#fff;', time: 2 });
- }else{
- this.store.dispatch(new actions.setToken(getToken(64)))
- this.store.dispatch(new actions.setUser(this.formField.tel))
- wcPop({
- content: '登录成功,跳转中...', style: 'background:#378fe7;color:#fff;', time: 2, shadeClose: false,
- end: function () {
- that.router.navigate(['/index'])
- }
- });
- }
- }
- }
◆ 编辑器核心消息处理
- 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, "") == "";
- }
