【源碼下載地址】: 碼雲地址:https://gitee.com/wangdefu/angular_chat?_from=gitee_search
有不足之處還望各位多多指點
【演示效果】:這是打包之後上傳服務器的ng效果,首次加載速度會有點慢,請耐心等待 http://www.bester.wang
【升級版本】:整合ionic4,支持打包雙系統app,接近原生app的體驗,真正的即時通訊,真正的聊天app,對任何想整合im的項目都是零侵入性,隨時隨地整合聊天系統到你的原有項目,就是這麼簡單
【後端im技術簡介】:springboot+cloud,讓開發更簡單,微服務讓分佈式和集羣更簡單,支持不停機更新,基於業界標杆netty進行im核心開發,性能爆表
【angualr前端模板簡介】:採用angular+@angular/cli+@angular/router+@ngrx/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
-
}
-
}
【技術交流】:個人技術交流微信 xw2876001800 提供前端和後端技術支持(java/php均可支持)