angular即时聊天IM实例|仿微信聊天室Angular版

1,252 阅读2分钟
angular8+angular/cli+angular/router+ngrx+webpack+node实现的仿微信界面聊天室|仿微信手机端聊天|angular聊天实战开发

技术实现

  • MVVM框架:angular8.0 / @angular/cli
  • 状态管理:@ngrx/store / rxjs
  • 地址路由:@angular/router
  • 弹窗组件:wcPop
  • 打包工具:webpack 2.0
  • 环境配置:node.js + cnpm
  • 图片预览:previewImage
  • 轮播滑动:swiper






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'])                }            });        }    }}

/* *  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    }}

/* *  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 { }

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(/&nbsp;/ig, "");
    return html.replace(/\r\n|\n|\r/, "").replace(/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, "") == "";
}