Recently, taro has been experimenting with taro multi-terminal development. Compared with UniApp multi-terminal technology, taro is much more complex to develop multi-terminal applications, especially when compiled into app.
Develop taro-Chatroom based on Taro+ React + Redux + Rn +taroPop
Taro Technology Stack:
- Encoding/technology: vscode + react/taro/story/reactNative
- Iconfont: Ali font icon library
- Custom top navigation bar + Tabbar
- Pop-up component: taroPop (Taro based Encapsulation custom dialog)
- Support compilation: H5 + small program + App end
Taro Custom navigation bar mode
In order to achieve a unified effect, the function of the project is relatively rich. The top navigation and the bottom tabbar adopt custom component mode. Due to the previous shared article, I will not introduce it in detail here.
See the following examples of the top navigation bar/bottom Tabbar components
See the Taro Custom Modal Components: Taro Custom Modal Box Components
Entry app.jsx page configuration
JSX * @about Q: 282310962 wx: xy190310 */ import Taro, {Component} from'@tarojs/taro'
import Index from './pages/index'Redux import {Provider} from'@tarojs/redux'
import { store } from './store'// Introduce 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 effectrender () {
return (
<Provider store={store}>
<Index />
</Provider>
)
}
}
Taro.render(<App />, document.getElementById('app'))
Copy the code
Taro login/registration form validation | redux state management | local storage
It’s also easy to get form input values from taro, using the onInput event
<Input placeholder="Please enter mobile phone number/nickname" onInput={this.handleInput.bind(this, 'tel')} / >Copy the code
this.state = {
tel: ' '.pwd: ' ',
}
handleInput = (key, e) => {
this.setState({ [key]: e.detail.value })
}
Copy the code
It is easy to get the input value using the above method
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"> </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 mobile phone number/nickname" onInput={this.handleInput.bind(this, 'tel')} />
</View>
<View className="auth-lgreg__forms-item">
<Input className="auth-lgreg__forms-iptxt flex1" placeholder="Please enter your 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"</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}> register the account </Text> </View> </View> </ScrollView> <TaroPop ref="taroPop" />
</View>
)
Copy the code
/** * @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:'login'
}
constructor(props) {
super(props)
this.state = {
tel: ' '.pwd: ' ',}}componentWillMount() {// Check whether to log in to storage.get()'hasLogin').then(res => {
if(res && res.hasLogin) {
Taro.navigateTo({url: '/pages/index/index'// Submit the form handleSubmit = () => {let taroPop = this.refs.taroPop
let { tel, pwd } = this.state
if(! tel) { taroPop.show({content:'Mobile phone number cannot be empty', time: 2})
}else if(! util.checkTel(tel)) { taroPop.show({content:'Wrong format of mobile phone 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 successful',
icon: 'success', time: 2 }) ... }}render() {... } } const mapStateToProps = (state) => {return{... state.auth} }exportdefault connect(mapStateToProps, { ... actions })(Login)Copy the code
In addition, note that the TARO rn terminal does not support synchronous storage, and can only be changed to setStorageSync asynchronous storage
/** * @desc Taro local storage */ import Taro from'@tarojs/taro'
export default class Storage {
static get(key) {
return Taro.getStorage({ key }).then(res => res.data).catch(() => ' ')
}
static set(key, data){
return Taro.setStorage({key: key, data: data}).then(res => res)
}
static del(key){
Taro.removeStorage({key: key}).then(res => res)
}
static clear(){
Taro.clearStorage()
}
}
Copy the code
Style compatibility processing
For styles that do not want to compile to the RN side, wrap them as follows
/*postcss-pxtransform rn eject enable*//*postcss-pxtransform rn eject disable* /Copy the code
Rn incompatible styles can be handled uniformly through the @mixin function provided by SCSS
** * RN does not support setting a style on one side or the other. < span style = "border-bottom: 1px" style = "border-bottom: 1px"; border-bottom-width: 1px; */ @mixin border($dir, $width, $style, $color) { border: 0 $style $color; @each $d in $dir { #{border-#{$d}-width}: $width; }} /** * NOTE RN cannot implement ellipses through text-overflow, */ @mixin Ellipsis {/* postcss-pxTransform RN eject enable*/ overflow: hidden; white-space: nowrap; text-overflow: ellipsis; /* postcss-pxTransform rn eject disable*/} /** * NOTE H5/ miniprogram -webkit-line-clamp */ @mixin clamp($line) {/*postcss -pxTransform RN eject enable*/ display: -webkit-box; overflow: hidden; -webkit-line-clamp:$line; /* autoprefixer: ignore next */ -webkit-box-orient: vertical; /* postcss-pxTransform rn eject disable*/} /** * For styles that cannot be packaged into Rn, */ @mixin eject($attr, $value) {/* postcss-pxTransform RN eject enable*/ #{$attr}: $value; /*postcss-pxtransform rn eject disable*/ }Copy the code
Taro scroll to the bottom of a chat message
H5/ applet can scroll to the bottom of the chat by getting createSelectorQuery. Since RN does not support createSelectorQuery, it can only be processed in other ways.
componentDidMount() {
if(process.env.TARO_ENV === 'rn') {
this.scrollMsgBottomRN()
}else {
this.scrollMsgBottom()
}
}Copy the code
// 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)}Copy the code
The part of chat expression uses emoj emoji, which is relatively simple to implement and will not be introduced.
. MsgPanelClicked = () => {if(! this.state.showFootToolbar)return
this.setState({ showFootToolbar: false} // swtEmojChooseView = (index) => {this.setState({showFootToolbar:true, showFootViewIndex: index})} swtEmojTab = (index) => {let lists = this.state.emotionJson
for(var i = 0, len = lists.length; i < len; i++) {
lists[i].selected = false
}
lists[index].selected = trueEnclosing setState ({emotionJson: lists})} / * > > > "editor/expression processing module" -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /bindEditorInput = (e) => {
this.setState({
editorText: e.detail.value,
editorLastCursor: e.detail.cursor
})
}
bindEditorFocus = (e) => {
this.setState({ editorLastCursor: e.detail.cursor })
}
bindEditorBlur = (e) => {
this.setState({ editorLastCursor: e.detail.cursor })
}
handleEmotionTaped = (emoj) => {
if(emoj == 'del') return// Insert the emoji at the cursorlet { editorText, editorLastCursor } = this.state
let lastCursor = editorLastCursor ? editorLastCursor : editorText.length
let startStr = editorText.substr(0, lastCursor)
let endStr = editorText.substr(lastCursor)
this.setState({
editorText: startStr + `${emoj} ` + endStr
})
}
...
Copy the code
Taro taro taro taro taro taro taro taro taro Taro Taro Taro Taro Taro 😴 😴
Vue + UniApp mimics Douyin short video/Momo live chat room
In pieces the react + redux imitation WeChat web chat end | web chat instance