xiaoyan2015 发表于 2019-12-17 23:42:21

taro聊天|仿微信界面|动态圈|taro+react跨端实例


项目简介:
TaroChatroom项目是基于taro+react+redux+reactNative等技术跨端实践仿微信界面聊天室,实现了消息发送、动态表情、图片预览、长按菜单、发红包、朋友圈等功能。支持编译到H5、小程序、App端。

编译效果:


实现技术:

[*]编码/技术:Vscode + react/taro/redux/react-native
[*]iconfont图标:阿里字体图标库
[*]自定义导航栏Navigation + 底部Tabbar
[*]弹窗组件:taroPop(基于Taro封装自定义模态框)
[*]支持编译:H5端 + 小程序 + RN端










入口页面、页面路径配置
/**
* @desc   Taro入口页面 app.jsx
*/

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 (
      <Provider store={store}>
      <Index />
      </Provider>
    )
}
}

Taro.render(<App />, document.getElementById('app'))taro表单验证|状态管理|存储实现
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">欢迎来到Taro-Chatroom</Text>
                </View>
                {/* 表单 */}
                <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="请输入手机号/昵称" onInput={this.handleInput.bind(this, 'tel')} />
                        </View>
                        <View className="auth-lgreg__forms-item">
                            <Input className="auth-lgreg__forms-iptxt flex1" placeholder="请输入密码" 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">忘记密码</Text>
                        <Text className="auth-lgreg__forms-link__nav" onClick={this.GoToRegister}>注册账号</Text>
                  </View>
                </View>
            </View>
      </ScrollView>

      <TaroPop ref="taroPop" />
    </View>
)taro中ReactNative端不支持同步存储,只能使用异步存储实现
https://segmentfault.com/img/bVbBvDj

/**
* @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端,则可通过如下代码包裹实现
/*postcss-pxtransform rn eject enable*/
/*postcss-pxtransform rn eject disable*/

taro中实现聊天消息滚动到最底部,由于RN端不支持 createSelectorQuery,需要做兼容处理
// 滚动至聊天底部
scrollMsgBottom = () => {
    let query = Taro.createSelectorQuery()
    query.select('#scrollview').boundingClientRect()
    query.select('#msglistview').boundingClientRect()
    query.exec((res) => {
      // console.log(res)
      if(res.height > res.height) {
            this.setState({ scrollTop: res.height - res.height })
      }
    })
}
scrollMsgBottomRN = (t) => {
    let that = this
    this._timer = setTimeout(() => {
      that.refs.ScrollViewRN.scrollToEnd({animated: false})
    }, t ? 16 : 0)
}https://segmentfault.com/img/bVbBvDW

// 点击聊天消息区域
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.selected = false
    }
    lists.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
    })
}

...

ok,到这里taro开发聊天app就基本介绍完了,后续会继续放送实例项目,希望大家能喜欢~~
最后分享个基于Vue实例项目
vue+uniapp+vuex开发的仿抖音短视频|仿陌陌直播项目


页: [1]
查看完整版本: taro聊天|仿微信界面|动态圈|taro+react跨端实例