Recently, we have been exploring and developing multiple terminals, which has been used before uniapp+vue develops the project of multi terminal imitative buffeting / Momo live studio Today, I want to share the TaroChat project based on the taro+react multi terminal wechat like interface chat room, which also supports compiling to H5, applet and App.
Technical realization:
- Framework technology: react / taro / Redux / react native
- iconfont Icon: Ali Font Icon Library
- Custom Navbar + Tabbar
- Pop up component: taroPop (custom dialog box based on Taro encapsulation)
- Support compilation: H5 + applet + App
/** * @desc Taro Entry page app.jsx */ import Taro, { Component } from '@tarojs/taro' import Index from './pages/index' // Introducing status management redux import { Provider } from '@tarojs/redux' import { store } from './store' // Import style import './app.scss' import './styles/fonts/iconfont.css' import './styles/reset.scss' class App extends Component { config = { pages: [ 'pages/auth/login/index', 'pages/auth/register/index', 'pages/index/index', ... ], window: { backgroundTextStyle: 'light', navigationBarBackgroundColor: '#fff', navigationBarTitleText: 'TaroChat', navigationBarTextStyle: 'black', navigationStyle: 'custom' } } // The render() function in the App class has no practical effect // Do not modify this function render () { return ( <Provider store={store}> <Index /> </Provider> ) } } Taro.render(<App />, document.getElementById('app'))
In order to unify the effect and enrich the function, the top navigation and the bottom tabbar adopt the custom component mode. As there is a sharing article before, it will not be introduced in detail here.
Top navigation bar / bottom tabbar component Taro multi terminal custom navigation bar Navbar+Tabbar instance
Taro custom Modal components refer to: Taro custom modal box component
taro login / registration form verification | redux status management | local storage
It's easy to get the input value of the form in taro, just use the onInput event directly
<Input placeholder="Please enter your mobile number/Nickname?" onInput={this.handleInput.bind(this, 'tel')} />
this.state = { tel: '', pwd: '', } handleInput = (key, e) => { this.setState({ [key]: e.detail.value }) }
return ( <View className="taro__container flexDC bg-eef1f5"> <Navigation background='#eef1f5' fixed /> <ScrollView className="taro__scrollview flex1" scrollY> <View className="auth-lgreg"> {/* logo */} <View className="auth-lgreg__slogan"> <View className="auth-lgreg__slogan-logo"> <Image className="auth-lgreg__slogan-logo__img" src={require('../../../assets/taro.png')} mode="aspectFit" /> </View> <Text className="auth-lgreg__slogan-text">Welcome to Taro-Chatroom</Text> </View> {/* form */} <View className="auth-lgreg__forms"> <View className="auth-lgreg__forms-wrap"> <View className="auth-lgreg__forms-item"> <Input className="auth-lgreg__forms-iptxt flex1" placeholder="Please enter your mobile number/Nickname?" onInput={this.handleInput.bind(this, 'tel')} /> </View> <View className="auth-lgreg__forms-item"> <Input className="auth-lgreg__forms-iptxt flex1" placeholder="Please input a password" password onInput={this.handleInput.bind(this, 'pwd')} /> </View> </View> <View className="auth-lgreg__forms-action"> <TouchView onClick={this.handleSubmit}><Text className="auth-lgreg__forms-action__btn">Sign in</Text></TouchView> </View> <View className="auth-lgreg__forms-link"> <Text className="auth-lgreg__forms-link__nav">Forget password</Text> <Text className="auth-lgreg__forms-link__nav" onClick={this.GoToRegister}>Registered account number</Text> </View> </View> </View> </ScrollView> <TaroPop ref="taroPop" /> </View> )
/** * @tpl Login module */ import Taro from '@tarojs/taro' import { View, Text, ScrollView, Image, Input, Button } from '@tarojs/components' import './index.scss' import { connect } from '@tarojs/redux' import * as actions from '../../../store/action'... class Login extends Taro.Component { config = { navigationBarTitleText: 'Sign in' } constructor(props) { super(props) this.state = { tel: '', pwd: '', } } componentWillMount() { // Determine whether to log in storage.get('hasLogin').then(res => { if(res && res.hasLogin) { Taro.navigateTo({url: '/pages/index/index'}) } }) } // Submit Form handleSubmit = () => { let taroPop = this.refs.taroPop let { tel, pwd } = this.state if(!tel) { taroPop.show({content: 'Mobile number cannot be empty', time: 2}) }else if(!util.checkTel(tel)) { taroPop.show({content: 'Wrong format of mobile number', time: 2}) }else if(!pwd) { taroPop.show({content: 'Password cannot be empty', time: 2}) }else { // ... interface data ... storage.set('hasLogin', { hasLogin: true }) storage.set('user', { username: tel }) storage.set('token', { token: util.setToken() }) taroPop.show({ skin: 'toast', content: 'Login successfully', icon: 'success', time: 2 }) ... } } render () { ... } } const mapStateToProps = (state) => { return {...state.auth} } export default connect(mapStateToProps, { ...actions })(Login)
taro scroll to the bottom of the chat message
H5 / applet can scroll to the bottom of chat by obtaining createSelectorQuery. Since RN does not support createSelectorQuery, it can only be processed in another compatible way.
// Scroll chat bottom scrollMsgBottom = () => { let query = Taro.createSelectorQuery() query.select('#scrollview').boundingClientRect() query.select('#msglistview').boundingClientRect() query.exec((res) => { // console.log(res) if(res[1].height > res[0].height) { this.setState({ scrollTop: res[1].height - res[0].height }) } }) } scrollMsgBottomRN = (t) => { let that = this this._timer = setTimeout(() => { that.refs.ScrollViewRN.scrollToEnd({animated: false}) }, t ? 16 : 0) }
This is the introduction of the development of the chat application by taro. We will continue to share the example project in the future. 😴😴
◆ vue chat room | h5+vue imitating wechat chat interface | vue imitating wechat
◆ react+redux imitation wechat client chat | web chat instance