【需要源代码请加个人微信】:wx2876001800 提供前端和后端技术支持(java/php均可支持)
采用[email protected]/[email protected]/[email protected]/store等技术开发的angular版仿微信界面聊天室,主要实现了下拉刷新、长按右键菜单、发送消息、表情(动图),图片、视频预览,打赏、红包等功能。
技术架构:
- MVVM框架:angular8 + @angular/cli + @angular/router
- 状态管理:@ngrx/store + rxjs
- 地址路由:@angular/router
- 弹窗组件:wcPop
- 打包工具:webpack 2.0
- 环境配置:node.js + cnpm
- 图片预览:previewImage
- 轮播滑动:swiper
学习不停歇、研发不终止,近段时间一直在捣鼓angular框架技术,发现并没有想象的那么难,不过也踩过一些坑,之前有使用vue开发过仿微信聊天,想着基于angular+angular-cli+angular-router+ngrx/store+rxjs+webpack+node+wcPop等技术开发的仿微信angular-chatroom聊天室实战项目,实现了下拉刷新、聊天消息右键菜单、发送消息、表情(动图),图片、视频预览,红包打赏等功能
技术架构:
- MVVM框架:angular8.0 / @angular/cli
- 状态管理:@ngrx/store / rxjs
- 地址路由:@angular/router
- 弹窗组件:wcPop
- 打包工具:webpack 2.0
- 环境配置:node.js + cnpm
- 图片预览:previewImage
- 轮播滑动:swiper
package.json依赖安装:
-
{ -
"name": "angular-chatroom", -
"aboutMe": "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", -
}, -
"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/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 {}
-
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, "") == ""; -
}
-
/* -
* 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 -
} -
}