基于Taro+react+redux+RN+taroPop等技术开发的跨端聊天App实例,支持编译到多端H5+小程序+RN端,界面仿制微信聊天界面,实现了消息发送、表情、图片预览、长按菜单、红包、朋友圈等功能。
Taro三端统一聊天应用:taro-chatroom (仿微信界面聊天App)
为了展示更丰富的导航条功能,顶部导航栏和底部Tabbar均采用自定义模式,且测试兼容三端。
具体介绍可看看这篇:Taro+react自定义顶部导航 + tabbar菜单
另外项目中用到的弹窗效果也是基于taro自定义Modal实现,可参看:taro自定义对话框
项目中使用redux进行状态管理,具体用法和react里面一样。
yarn add redux redux-thunk @tarojs/redux
import Taro, { Component } from '@tarojs/taro'
import Index from './pages/index'
// 引入状态管理redux
import { Provider } from '@tarojs/redux'
import { store } from './store'
// 引入样式
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'
}
}
// 在 App 类中的 render() 函数没有实际作用
// 请勿修改此函数
render () {
return (
)
}
}
Taro.render( , document.getElementById('app'))
taro中表单操作、redux状态管理及本地存储实现
{/* logo */}
欢迎来到Taro-Chatroom
{/* 表单 */}
登录
忘记密码
注册账号
/**
* @tpl 登录模块
*/
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: '登录'
}
constructor(props) {
super(props)
this.state = {
tel: '',
pwd: '',
}
}
componentWillMount() {
// 判断是否登录
storage.get('hasLogin').then(res => {
if(res && res.hasLogin) {
Taro.navigateTo({url: '/pages/index/index'})
}
})
}
// 提交表单
handleSubmit = () => {
let taroPop = this.refs.taroPop
let { tel, pwd } = this.state
if(!tel) {
taroPop.show({content: '手机号不能为空', time: 2})
}else if(!util.checkTel(tel)) {
taroPop.show({content: '手机号格式有误', time: 2})
}else if(!pwd) {
taroPop.show({content: '密码不能为空', time: 2})
}else {
// ...接口数据
...
storage.set('hasLogin', { hasLogin: true })
storage.set('user', { username: tel })
storage.set('token', { token: util.setToken() })
taroPop.show({
skin: 'toast',
content: '登录成功',
icon: 'success',
time: 2
})
...
}
}
render () {
...
}
}
const mapStateToProps = (state) => {
return {...state.auth}
}
export default connect(mapStateToProps, {
...actions
})(Login)
项目开发中,尤其需要注意RN端样式问题,对于一些兼容处理,不希望编译到RN端,则可通过如下实现
/*postcss-pxtransform rn eject enable*/
/*postcss-pxtransform rn eject disable*/
/**
* RN 不支持针对某一边设置 style,即 border-bottom-style 会报错
* 那么 border-bottom: 1px 就需要写成如下形式: border: 0 style color; border-bottom-width: 1px;
*/
@mixin border($dir, $width, $style, $color) {
border: 0 $style $color;
@each $d in $dir {
#{border-#{$d}-width}: $width;
}
}
/**
* NOTE RN 无法通过 text-overflow 实现省略号,这些代码不会编译到 RN 中
*/
@mixin ellipsis {
/*postcss-pxtransform rn eject enable*/
overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
/*postcss-pxtransform rn eject disable*/
}
/**
* NOTE 实现多行文本省略,RN 用 Text 标签的 numberOfLines={2},H5/小程序用 -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*/
}
/**
* 对于不能打包到 RN 的样式,可以用 postcss 方式引入
*/
@mixin eject($attr, $value) {
/*postcss-pxtransform rn eject enable*/
#{$attr}: $value;
/*postcss-pxtransform rn eject disable*/
}
聊天时发送消息滚动到最底部,则需要进行兼容处理,因为ReactNative端不支持createSelectorQuery
componentDidMount() {
if(process.env.TARO_ENV === 'rn') {
this.scrollMsgBottomRN()
}else {
this.scrollMsgBottom()
}
}
// 滚动至聊天底部
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)
}
另外聊天表情使用emoj表情符,这个实现比较简单,就不介绍了。
...
// 点击聊天消息区域
msgPanelClicked = () => {
if(!this.state.showFootToolbar) return
this.setState({ showFootToolbar: false })
}
// 表情、选择区切换
swtEmojChooseView = (index) => {
this.setState({ showFootToolbar: true, showFootViewIndex: index })
}
// 底部表情tab切换
swtEmojTab = (index) => {
let lists = this.state.emotionJson
for(var i = 0, len = lists.length; i < len; i++) {
lists[i].selected = false
}
lists[index].selected = true
this.setState({ emotionJson: lists })
}
/* >>> 【编辑器/表情处理模块】------------------------------------- */
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
// 在光标处插入表情
let { 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
})
}
...
好了,到这里taro开发聊天app的分享介绍就差不多了,希望能有些帮助!!
最后附上两个基于vue开发的实例项目
vue网页端聊天:https://blog.csdn.net/yanxinyun1990/article/details/89735778
vue+uniapp仿抖音小视频:https://blog.csdn.net/yanxinyun1990/article/details/103012086