精华内容
下载资源
问答
  • 主要介绍了详解微信小程序实现仿微信聊天界面(各种细节处理),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 仿造微信界面仅供参考学习仿微信聊天界面demo采用css+div技术
  • 微信小程序源码:仿微信聊天界面源码下载,一看就是模仿微信的,聊天界面,不过说成是仿QQ也不为过哦,现在QQ和微信都是这种聊天的界面风格啦。美工水平有限,还没有过多的去美化界面,只是写出了个大概,有兴趣学习...
  • 完整的微信小程序实现 WebSocket 长链接聊天代码,包括聊天界面的样式。可直接使用,有疑问可加微信13977284413询问。有时间的话我会第一时间回复。
  • 主要为大家详细介绍了微信小程序WebSocket实现聊天对话功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 微信小程序下拉刷新上拉加载的两种实现方法 实现效果图: 方法一:onPullDownRefresh和onReachBottom方法实现小程序下拉加载和上拉刷新 首先要在json文件里设置window属性  属性  类型  描述 ...
  • 微信小程序实现仿微信聊天界面

    千次阅读 2019-11-25 16:01:33
    实现过程容易出现的问题 1、输入完内容之后页面没有自动滚动到页面底部 2、输入内容时候,原有的记录内容不会显示,被遮挡了 ... 解决第一个问题的方法是scrollTOP wx.createSelectorQuery().select(’#chat’)....

    实现过程容易出现的问题
    1、输入完内容之后页面没有自动滚动到页面底部
    2、输入内容时候,原有的记录内容不会显示,被遮挡了

    3、点击按钮发送(完成),需要点击两次才清空input内容(第一次是失去焦点,第二次是清空内容)
    (这个问题只有在安卓手机才会出现)

    在这里插入图片描述
    解决第一个问题的方法是scrollTOP (写在点击完成这个事件)
    wx.createSelectorQuery().select(’#chat’).boundingClientRect(function (rect) {
    if (rect) {
    // 使页面滚动到底部
    console.log(rect.height);
    wx.pageScrollTo({
    scrollTop: rect.height
    })
    }
    }).exec();

    解决第二个问题是input动态设置bottom

    html如下:
    <view class=“input_focus clear” style=“bottom:{{inputBottom}}px”>

    完 成

    js代码如下 获取焦点时候,让底部预留出软键盘的高度,失去焦点之后恢复原来高度
    focus: function (e) {
    console.log(e)
    this.setData({
    inputBottom:e.detail.height
    })
    },
    blur: function (e) {
    console.log(e)
    this.setData({
    inputBottom: 0
    })
    },

    解决第三个问题是 让其失去焦点之后,再清空内容

    this.setData({
    isfocus: false,
    }, () => {
    this.setData({
    inputValue: ‘’
    })
    })

    展开全文
  • 项目中用到了 olami sdk把录音或者文字转化为用户可以理解的json字符串。 效果图 (此图片来源于网络,如有侵权,请联系删除! ) 重要jS代码:   //手指按下时 语音转文字 voiceToChar:function(){ ...
  • 正好是模拟制作的微信界面和功能,源代码目录很规范,编写微信相关的小程序,运用的知识技巧是很综合的,这涉及到音频处理、查找联系人、信息、日志、消息、新朋友发现、日志记事、上传模块、微信聊天模块等,这个...
  • 主要为大家详细介绍了微信小程序实现聊天对话功能,可以发送文本、图片,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 微信小程序实现仿微信聊天界面(各种细节处理)

    万次阅读 多人点赞 2019-01-07 16:26:47
    2.键盘弹出或收起时,聊天消息没有自动滚到最底部。 首先解决第二个问题,自动滚动到最底部,这很简单,这里提供三种方法(推荐第三种): 1.计算每条消息的最大高度,设置scroll-top=(单条msg最大高度 * msg条数)...

    下面先来看看效果

    在这里插入图片描述

    为实现这样的效果,首先要解决两个问题:

    1.点击输入框弹出软键盘后,将已有的少许聊天内容弹出,导致看不到的问题;
    2.键盘弹出或收起时,聊天消息没有自动滚到最底部。

    首先解决第二个问题,自动滚动到最底部,这很简单,这里提供三种方法(推荐第三种):
    1.计算每条消息的最大高度,设置scroll-top=(单条msg最大高度 * msg条数)px。

    2.用 将展示msg的目标scroll-view包裹,
    通过js获取到该view的实际高度:

    var that = this;
    var query = wx.createSelectorQuery();
    query.select('.scrollMsg').boundingClientRect(function(rect) {
    	that.setData({
    		scrollTop: rect.height+'px';
    	});
    }).exec();
    

    3.(推荐)将所有msg都编号如:msg-0,msg-1,msg-2… 直接锁定最后一条msg,滚动到那里。
    在scroll-view中添加:scroll-into-view='{{toView}}'
    在wx:for后面添加:wx:for-index="index"
    在每个msg布局中添加:id='msg-{{index}}'
    最后直接:

    this.setData({
    	toView: 'msg-' + (msgList.length - 1)
    })
    

    到这里第二个问题解决了,那么我们回过来解决第一个问题:

    (点击输入框弹出软键盘后,将已有的少许聊天内容弹出,导致看不到的问题)
    1.首先我们需要将input的自动向上推给关掉,这里有个坑:

    在input组件中添加:adjust-position='{{false}}'
    而不是:adjust-position='false'
    这么做虽然不再向上推,但却导致了软键盘弹起时,会遮挡屏幕下部分的消息。

    2.如何解决软键盘弹起时,会遮挡屏幕下部分的消息?

    当软键盘弹起时,将scroll-view的高度缩短至软键盘遮挡不到的屏幕上方部分,当软键盘收起时,再将scroll-view的高度还原,这样解决了遮挡问题。

    提示:
    input中的bindfocus='focus'可获取软键盘高度并监听软键盘弹起,bindblur='blur'可监听软键盘收起,var windowHeight = wx.getSystemInfoSync().windowHeight;可获得屏幕高度。

    scrollHeight(滚动条高度) = windowHeight(屏幕高度) - 软键盘高度;

    最后将input组件放在软键盘上面就完成了。

    |
    |
    |
    |
    |
    |
    |

    各位要不要代码?

    |
    |
    |
    |
    |
    |
    |
    contact.js:

    // pages/contact/contact.js
    const app = getApp();
    var inputVal = '';
    var msgList = [];
    var windowWidth = wx.getSystemInfoSync().windowWidth;
    var windowHeight = wx.getSystemInfoSync().windowHeight;
    var keyHeight = 0;
    
    /**
     * 初始化数据
     */
    function initData(that) {
      inputVal = '';
    
      msgList = [{
          speaker: 'server',
          contentType: 'text',
          content: '欢迎来到英雄联盟,敌军还有30秒到达战场,请做好准备!'
        },
        {
          speaker: 'customer',
          contentType: 'text',
          content: '我怕是走错片场了...'
        }
      ]
      that.setData({
        msgList,
        inputVal
      })
    }
    
    /**
     * 计算msg总高度
     */
    // function calScrollHeight(that, keyHeight) {
    //   var query = wx.createSelectorQuery();
    //   query.select('.scrollMsg').boundingClientRect(function(rect) {
    //   }).exec();
    // }
    
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        scrollHeight: '100vh',
        inputBottom: 0
      },
    
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad: function(options) {
        initData(this);
        this.setData({
          cusHeadIcon: app.globalData.userInfo.avatarUrl,
        });
      },
    
      /**
       * 生命周期函数--监听页面显示
       */
      onShow: function() {
    
      },
    
      /**
       * 页面相关事件处理函数--监听用户下拉动作
       */
      onPullDownRefresh: function() {
    
      },
    
      /**
       * 页面上拉触底事件的处理函数
       */
      onReachBottom: function() {
    
      },
    
      /**
       * 获取聚焦
       */
      focus: function(e) {
        keyHeight = e.detail.height;
        this.setData({
          scrollHeight: (windowHeight - keyHeight) + 'px'
        });
        this.setData({
          toView: 'msg-' + (msgList.length - 1),
          inputBottom: keyHeight + 'px'
        })
        //计算msg高度
        // calScrollHeight(this, keyHeight);
    
      },
    
      //失去聚焦(软键盘消失)
      blur: function(e) {
        this.setData({
          scrollHeight: '100vh',
          inputBottom: 0
        })
        this.setData({
          toView: 'msg-' + (msgList.length - 1)
        })
    
      },
    
      /**
       * 发送点击监听
       */
      sendClick: function(e) {
        msgList.push({
          speaker: 'customer',
          contentType: 'text',
          content: e.detail.value
        })
        inputVal = '';
        this.setData({
          msgList,
          inputVal
        });
    
    
      },
    
      /**
       * 退回上一页
       */
      toBackClick: function() {
        wx.navigateBack({})
      }
    
    })
    

    contact.wxml:

    <!--pages/contact/contact.wxml-->
    
    <view>
    
      <scroll-view scroll-y scroll-into-view='{{toView}}' style='height: {{scrollHeight}};'>
        <!-- <view class='scrollMsg'> -->
        <block wx:key wx:for='{{msgList}}' wx:for-index="index">
    
          <!-- 单个消息1 客服发出(左) -->
          <view wx:if='{{item.speaker=="server"}}' id='msg-{{index}}' style='display: flex; padding: 2vw 11vw 2vw 2vw;'>
            <view style='width: 11vw; height: 11vw;'>
              <image style='width: 11vw; height: 11vw; border-radius: 10rpx;' src='../../images/contact_member.png'></image>
            </view>
            <view style='width: 4vw; height: 11vw; margin-left: 0.5vw; display: flex; align-items: center; z-index: 9;'>
              <image style='width: 4vw;' src='../../images/left_msg.png' mode='widthFix'></image>
            </view>
            <view class='leftMsg'>{{item.content}}</view>
          </view>
    
          <!-- 单个消息2 用户发出(右) -->
          <view wx:else id='msg-{{index}}' style='display: flex; justify-content: flex-end; padding: 2vw 2vw 2vw 11vw;'>
            <view class='rightMsg'>{{item.content}}</view>
            <view style='width: 4vw; height: 11vw; margin-right: 0.5vw; display: flex; align-items: center; z-index: 9;'>
              <image style='width: 4vw;' src='../../images/right_msg.png' mode='widthFix'></image>
            </view>
            <view style='width: 11vw; height: 11vw;'>
              <image style='width: 11vw; height: 11vw; border-radius: 10rpx;' src='{{cusHeadIcon}}'></image>
            </view>
          </view>
    
        </block>
        <!-- </view> -->
    
        <!-- 占位 -->
        <view style='width: 100%; height: 18vw;'></view>
      </scroll-view>
    
      <view class='inputRoom' style='bottom: {{inputBottom}}'>
        <image style='width: 7vw; margin-left: 3.2vw;' src='../../images/pic_icon.png' mode='widthFix'></image>
        <input bindconfirm='sendClick' adjust-position='{{false}}' value='{{inputVal}}' confirm-type='send' bindfocus='focus' bindblur='blur'></input>
      </view>
    </view>
    

    contact.wxss:

    /* pages/contact/contact.wxss */
    
    page {
      background-color: #f1f1f1;
    }
    
    .inputRoom {
      width: 100vw;
      height: 16vw;
      border-top: 1px solid #cdcdcd;
      background-color: #f1f1f1;
      position: fixed;
      bottom: 0;
      display: flex;
      align-items: center;
      z-index: 20;
    }
    
    input {
      width: 76vw;
      height: 9.33vw;
      background-color: #fff;
      border-radius: 40rpx;
      margin-left: 2vw;
      padding: 0 3vw;
      font-size: 28rpx;
      color: #444;
    }
    
    .leftMsg {
      font-size: 35rpx;
      color: #444;
      line-height: 7vw;
      padding: 2vw 2.5vw;
      background-color: #fff;
      margin-left: -1.6vw;
      border-radius: 10rpx;
      z-index: 10;
    }
    
    .rightMsg {
      font-size: 35rpx;
      color: #444;
      line-height: 7vw;
      padding: 2vw 2.5vw;
      background-color: #96EB6A;
      margin-right: -1.6vw;
      border-radius: 10rpx;
      z-index: 10;
    }
    

    到此就结束了,希望能帮到各位,记得拿走时请扣6
    有问题在评论区留言

    展开全文
  • 一个微信小程序界面生成器源代码,是一个界面框架,用来快速生成一些简单的微信小程序界面,里面要用到几个JAR库:bcprov-jdk15on-155.jar、commons-codec-1.8.jar、freemarker-2.3.9.jar。并附有一个简单的Demo,更...
  • 微信小程序聊天室(云开发)

    千次阅读 2020-02-19 18:42:55
    在写聊天是之前我们可以先看一需要建四个云数据表,user(用户列表),qunList (群列表),qunUserList(群用户列表),news(消息列表)接下来就是页面布局,这个布局看个人其需求我这里就讲讲大概逻辑,数据的增删...

                       

     

    在写聊天是之前我们可以先看一需要建四个云数据表,user(用户列表),qunList (群列表),qunUserList(群用户列表),news(消息列表)接下来就是页面布局,这个布局看个人其需求我这里就讲讲大概逻辑,数据的增删改查我上篇文章已经讲过了,今天我就不详细写了

    一.登录

    1.必须有个授权按钮,授权之后将用户基本信息跟opinId存入缓存,跟数据库

        <button class="login" open-type="getUserInfo" bindgetuserinfo="login">授权登录</button>

     登录页面加载的时候判断用户是否受过权,我这里用的是缓存中的openId,判断缓存中是否有openId,有直接跳转到首页,

      onLoad(options) {
        that = this
          if (wx.getStorageSync('openId')) {
            wx.reLaunch({
              url: '../group/group',
            })
          }
      },

     没有就点击授权,获取用户基本信息;然后判断数据库中是否有对应用户信息,有的话把基本信息跟opinId存入缓存然后跳转首页

    // 登录
      login() {
        wx.showLoading({
          title: '加载中,请稍等...',
        })
          wx.login({
            success: function(res) {
              code = res.code
              wx.getUserInfo({
                success: function(res) {
                  name = res.userInfo.nickName
                  hend = res.userInfo.avatarUrl
                  wx.setStorageSync('userInfo', res.userInfo)
                  wx.cloud.callFunction({
                    name: "openId",
                    success(res) {
                      wx.setStorageSync('openId', res.result.openid)
                      openId = res.result.openid
                      // 判断数据库中是否已经有数据
                      DB.collection('user').where({
                          _openId: openId,
                        })
                        .get({
                          success: function(res) {
                            console.log(1234321, res)
                            if (res.data.length == 0) {
                              console.log(1)
                              that.userAdd()
                            } else {
                                wx.reLaunch({
                                  url: '../group/group',
                                })
                            }
                          }
                        })
                    },
                    fail(res) {
                      console.log('登录失败', res)
                    }
                  })
                }
              })
            }
          })
      },

     没有的话就将对应基本信息传到云函数

    // 添加用户信息
      userAdd() {
        wx.cloud.callFunction({
          name: "login",
          data: {
            openId: openId,
            name: name,
            hend: hend,
          },
          success(res) {
              wx.hideLoading()
              wx.showToast({
                title: '授权成功!',
              })
              setTimeout(() => {
                wx.reLaunch({
                  url: '../group/group',
                })
              }, 1000)
             
          },
          fail(res) {
            console.log('登录失败', res)
          }
        })
      }

     云函数将接收数据存入数据库;然后跳转首页

    // 云函数入口文件
    const cloud = require('wx-server-sdk')
    
    cloud.init({
      env: ''
    })
    
    const db = cloud.database()
    exports.main = async(event, context) => {
      var name = event.name
      var hend = event.hend
      var openId = event.openId
      return await db.collection('user').add({
        // data 字段表示需新增的 JSON 数据
        data: {
          name: name,
          hend: hend,
          _openId: openId
        }
      })
    
    }
    
    

    授权登录差不多到这里就完了

    二.建群 

    写一个加群的按钮和群的展示列表

    <view >
      <block wx:for="{{list}}" wx:key=''>
        <view class="list_bo" bindtap="list" data-_id="{{item.qunId}}" bindlongpress="longPress" data-index="{{index}}" data-_openId="{{item._openId}}">
          <!-- <view class="list_bo" wx:if='{{item.establishName}}' > -->
          <image class="list_hand" src="{{item.establishHend}}"></image>
          <view class="establishName">{{item.establishName}} {{item.qunName}}</view>
          <view class="delbtn" wx:if="{{index==delId&memberTis=='删除'}}" data-_id="{{item.qunId}}" catchtap="deleteBtn">删除</view>
          <view class="delbtn" wx:if="{{index==delId&memberTis=='退出'}}" data-_id="{{item.qunId}}" catchtap="signOutBtn">退出</view>
        </view>
      </block>
      <view class="del">长按可删除</view>
      <view class="jia" bindtap="jia">+</view>
    </view>

    1.创建一个群聊,我这里群信息只写了个群名称跟简介,群头像就用创建用户的头像

    <view>
      <view class="bo">
        <view class="bto_bor">
          <view class="title">群名称</view>
          <input class="input" maxlength="15" placeholder="不超过15个字" value="" bindinput="qunName"></input>
        </view>
        <view class="bto_bor" style="border-bottom: 0rpx solid #f7f5f6;">
          <view class="title" style="line-height: 220rpx">说明</view>
          <textarea class="textarea" maxlength="100" placeholder="不超过200个字" value="" bindinput="qunTitle"></textarea>
        </view>
      </view>
      <button type="primary" size="default" bindtap="subm" > 保存</button>
    </view>

     创建群的时候获取到所输入的群的信息传到云函数存入数据库,然后再将个人基本信息存入群的用户列表,数据字段看个人需求;每个聊天室需求不一样,数据也不一样

    const DB = wx.cloud.database()
    var util = require('../../utils/util.js');
    var qunId
    Page({
      data: {
        qunName: '',
        qunTitle: '',
      },
     
      // 群名
      qunName(e) {
        let val = e.detail.value
        this.setData({
          qunName: val
        })
      },
      // 说明
      qunTitle(e) {
        let val = e.detail.value
        this.setData({
          qunTitle: val
        })
      },
      // 提交
      subm() {
        wx.showLoading({
          title: '加载中,请稍等...',
        })
        let qunName = this.data.qunName
        let qunTitle = this.data.qunTitle
        let _openId = wx.getStorageSync('openId')
        let userInfo = wx.getStorageSync('userInfo');
        wx.cloud.callFunction({
          name: "add_qun",
          data: {
            // 禁言状态
            prohibit: '0',
            // 创建者的 openid
            _openId: _openId,
            // 群名称
            qunName: qunName,
            // 群说明
            qunTitle: qunTitle,
            // 创建时间
            dataTime: util.nowTime(),
            establishName: userInfo.nickName,
            establishHend: userInfo.avatarUrl,
    
          },
          success(res) {
            console.log(222222222, qunTitle)
            qunId = res.result._id
    
            wx.cloud.callFunction({
              name: "qunUserList",
              data: {
                qunId: qunId,
                _openId: _openId,
                typeId: '0',
                dataTime: util.nowTime(),
                // 创建者名称
                establishName: userInfo.nickName,
                //创建者头像
                establishHend: userInfo.avatarUrl,
                // 群名称
                qunName: qunName,
                // 群说明
                qunTitle: qunTitle,
    
              },
              success(res) {
                console.log(333333333, res)
                wx.hideLoading()
                wx.showToast({
                  title: '创建成功',
                  icon: 'none',
                })
                setTimeout(() => {
                  wx.reLaunch({
                    url: '../news/news?qunId=' + qunId
                  })
                },1000)
              },
              fail(res) {
                console.log('登录失败', res)
              }
            })
    
          },
          fail(res) {
            console.log('登录失败', res)
          }
        })
      },
    
    })

     存群信息

    // 云函数入口文件
    const cloud = require('wx-server-sdk')
    
    cloud.init({
      env: 'y1831836688'
    })
    
    const db = cloud.database()
    exports.main = async (event, context) => {
      return await db.collection('qunList').add({
        // data 字段表示需新增的 JSON 数据
        data: event
      })
    
    }
    
    

      存群用户信息

    // 云函数入口文件
    const cloud = require('wx-server-sdk')
    
    cloud.init({
      env: ''
    })
    
    const db = cloud.database()
    exports.main = async(event, context) => {
      return await db.collection('qunUserList').add({
        data: event
      })
    
    }

    群建完之后,接下来我们,获取群数据并展示到群群列表;

     getList() {
        let openId = wx.getStorageSync('openId')
    
        DB.collection('qunUserList').where({
            _openId: openId
          })
          .get({
            success: function(res) {
              console.log('我所在的群', res)
              let qunList = res.data;
              that.setData({
                listLength: qunList.length,
                list: qunList
              })
             
            }
          })
      },

    三.聊天界面

    1.聊天界面我就不写了;我就写一下大概逻辑:获取输入框输入的内容;存入数据库

    发送消息:

    // 发送消息
      sendOut(e) {
        console.log(1111, e)
        let title = e.detail.value
        if (title == '') {
          wx.showToast({
            title: '请输入聊天内容',
            icon: 'none',
          })
        } else {
          var data = {
            _qunId: qunId,
            _openId: wx.getStorageSync('openId'),
            // 消息
            text: title,
            // 消息
            img: '',
            // 时间
            dataTime: util.nowTime(),
            // 头像
            sendOutHand: wx.getStorageSync('userInfo').avatarUrl,
            // 昵称
            sendOutname: wx.getStorageSync('userInfo').nickName
          }
          console.log(data)
          wx.cloud.callFunction({
            name: "news",
            data: data,
            success(res) {
              console.log('消息发送', res)
              that.setData({
                title: ''
              })
    
            },
            fail(res) {
              console.log('登录失败', res)
            }
          })
        }
      },

    发送图片: 

    // 发送图片
      upLoad() {
        var that = this
        // 让用户选择一张图片
        wx.chooseImage({
          success: chooseResult => {
            // 将图片上传至云存储空间
            wx.cloud.uploadFile({
              // 指定上传到的云路径
              cloudPath: util.imgName() + 'textImg.png',
              // 指定要上传的文件的小程序临时文件路径
              filePath: chooseResult.tempFilePaths[0],
              // 成功回调
              success: res => {
                console.log('上传成功', res)
                let imgUrl = res.fileID
                wx.cloud.callFunction({
                  name: "news",
                  // data: {
                  //   imgUrl: imgUrl
                  // },
                  data: {
                    _qunId: qunId,
                    _openId: wx.getStorageSync('openId'),
                    // 消息
                    text: '',
                    // 消息
                    img: imgUrl,
                    // 时间
                    dataTime: util.nowTime(),
                    // 头像
                    sendOutHand: wx.getStorageSync('userInfo').avatarUrl,
                    // 昵称
                    sendOutname: wx.getStorageSync('userInfo').nickName
                  },
                  success(res) {
                    console.log('图片发送成功', res)
                  },
                  fail(res) {
                    console.log('返回失败', res)
                  }
                })
              },
            })
          },
        })
      },

    获取聊天数据;这是个动态监听数据库数据变化的;只要数据变化就会走,不用担心消息发送成功之后不会实时更新问题;左右布局,我这里是判断消息列表存入的opinId来判断的;如果列表里的opinId字段跟缓存里的opinId相同的话就显示右边,其它的都显示到左边。

     // 获取成员消息
      onMsg(qunId) {
        console.log('2222222', qunId)
        const watcher = DB.collection('news')
          // 按 progress 降序
          // .orderBy('progress', 'desc')
          // 取按 orderBy 排序之后的前 10 个
          // .limit(10)
          .where({
            _qunId: qunId
          })
          .watch({
            onChange: function(snapshot) {
              console.log('snapshot', snapshot)
              var listArr = snapshot.docs;
              // console.log('---', listArr)
              listArr.forEach((item, idx) => {
                // console.log('---', item)
                // console.log(wx.getStorageSync('openId') + ':' + item._openId)
                item.type = wx.getStorageSync('openId') == item._openId ? 1 : 2;
                item.sendOutname = wx.getStorageSync('openId') == item._openId ? '我' : '';
              })
    
              that.setData({
                list: listArr
              })
              setTimeout(() => {
                that.bottom()
              }, 500)
              console.log('-----------------------s', listArr)
            },
            onError: function(err) {
              console.error('----------------error', err)
            }
          })
      },

    源码链接: https://download.csdn.net/download/qq_41241504/12351483

     

    展开全文
  • 微信小程序环信即时聊天
  • 后期打算在小程序中添加即时聊天的功能,但是目前这个还没有考虑好以一种什么样的形势去实现,先接入一个腾讯AI提供的免费闲聊接口。先做一个大概的页面及功能。 腾讯AI地址: https://ai.qq.com/doc/nlpchat.shtml#...

    后期打算在小程序中添加即时聊天的功能,但是目前这个还没有考虑好以一种什么样的形势去实现,先接入一个腾讯AI提供的免费闲聊接口。先做一个大概的页面及功能。

    腾讯AI地址:

    https://ai.qq.com/doc/nlpchat.shtml#基础闲聊接口

    有兴趣,可以试一试,当然,这种免费且不限次数的机器人肯定不会太聪明,期望值别太高。

    我这里实现的效果是,可以发文字,表情,图片以及语音,,当然如果你还想要更多的功能,就需要自己去拓展了。

    最后的效果:

    在这里插入图片描述

    其余的就不多介绍了,感兴趣的同学可以自行研究下代码:

    Aichat.wxml

    <!-- 顶部title及返回键 -->
    <view class="index" style="height:{{globalData.CustomBar}}px;padding-top: {{globalData.StatusBar}}px;">
      <!-- 如果正在输入title变正在输入中 -->
      <image catchtap="fanhui" mode="widthFix" class="index-img" src="/images/leftrow.png"></image><text>{{news?'正在输入中...':openid}}</text>
    </view>
    <view class="chat-index" style="margin-top:{{globalData.CustomBar}}px;height:calc(100vh - {{globalData.CustomBar}}px);">
      <view wx:if="{{playing}}" style="position: fixed;top: 75px;" class="chat-cbins">正在播放语音</view>
      <!-- 聊天列表 -->
      <scroll-view bindtouchstart="scrollstart" style="height: calc(100% - {{chatheight?chatheight:'50'}}px);{{emojis || camera?'transition:all 0.5s;':'transition:all 0.1s;'}}" scroll-with-animation="{{animation}}" class="scroll-view" scroll-y="{{true}}" scroll-into-view="{{curr}}">
        <!-- 循环消息列表 -->
        <view wx:for="{{newsList}}" wx:key="index" class="news {{item.openid == openid?'contrary':''}}" id="jump{{index}}">
          <!-- 用户头像 -->
          <view class="mews-image">
            <image src="{{item.logo}}" mode='aspectFill'></image>
          </view>
          <!-- 用户消息,消息分四种类型,语音,表情,图片,文字 -->
          <!-- 当用户标识等于系统默认用户标识的时候 -->
          <view class="news-centent {{item.openid == openid?'centent-right':'centent-left'}}" >
            <view class="{{item.openid == openid?'trianright':'trianleft'}}"></view>
            <text selectable="{{true}}" wx:if="{{item.news_type == 'text'}}" class="{{item.openid == openid?'background_right':'background_left'}}" >{{item.news_centent}}</text>
            <image class="news-images" catchtap="picture" data-src="{{item.news_centent.src}}" style="{{item.news_centent.width <= 100?'width:'+item.news_centent.width*2+'px;height:'+item.news_centent.height*2+'px':''}}{{item.news_centent.width > 100 && item.news_centent.width < 400?'width:130px;height:'+item.news_centent.height/(item.news_centent.width / 130)+'px':''}}{{item.news_centent.width > 400 && item.news_centent.width <= 600?'width:'+item.news_centent.width/2.5+'px;height:'+item.news_centent.height/2.5+'px':''}}{{item.news_centent.width > 600 && item.news_centent.width <= 800?'width:'+item.news_centent.width/4+'px;height:'+item.news_centent.height/4+'px':''}}{{item.news_centent.width > 800?'width:150px;height:'+item.news_centent.height/(item.news_centent.width / 150)+'px':''}};" wx:if="{{item.news_type == 'image'}}" src="{{item.news_centent.src}}"></image>
            <view class="news-voice" wx:if="{{item.news_type == 'voice'}}" bindtap="{{cuindex == index?'suspend':'play'}}" data-voice="{{item.news_centent.voice}}" data-index="{{index}}" > 
              <text wx:if="{{item.openid == openid}}">{{item.news_centent.dimen < '1'?'1':item.news_centent.dimen}}"</text>
              <image src="/images/{{item.openid == openid?'voice-right':'voice-left'}}.png"></image>
              <text wx:if="{{item.openid != openid}}">{{item.news_centent.dimen < '1'?item.news_centent.dimen:'1'}}"</text>
            </view>
          </view>
        </view>
      </scroll-view>
      <!-- 底部功能栏 -->
      <view class="chat-bottom" id="chat-height">
        <!-- 点击语音功能 -->
        <view class="chat-centent">
          <view class="chat-pression">
            <image wx:if="{{!voice}}" catchtap="speak" src="/images/voice.png"></image>
            <image wx:if="{{voice}}" catchtap="speak" src="/images/keyboard.png"></image>
          </view>
          <view class="chat-tencvi" style="{{sendout?'width:67%;':''}}">
            <textarea adjust-position="{{false}}" bindfocus="getkey" bindblur="getblur" wx:if="{{!voice}}" bindinput="moninput" value="{{news}}" maxlength="-1" auto-height />
            <view  bindtouchstart="touchdown" bindtouchend="touchup" wx:if="{{voice}}">按住 说话</view>
          </view>
          <view class="chat-pression">
            <image wx:if="{{!emojis}}" catchtap="emoji" src="/images/emotion.png"></image>
            <image wx:if="{{emojis}}" catchtap="emoji" src="/images/keyboard.png"></image>
          </view>
          <view class="chat-pression" wx:if="{{!sendout}}">
            <image catchtap="camerax" src="/images/plus.png"></image>
          </view>
          <view class="chat-news" catchtap="message" style="{{sendout?'transition:all 0.5s;width:15%;':'width:0;position: absolute;right: 0;visibility: hidden;'}}">
            <view>发送</view>
          </view>
        </view>
        <!-- 点击表情图标 -->
        <view class="chat-cube" wx:if="{{emojis}}">
          <view class="cube-title">所有表情</view>
          <view class="cube-centent">
            <view catchtap="expression" data-item="{{item}}" wx:for="{{pression}}" wx:key="index">{{item}}</view>
          </view>
        </view>
        <!-- 点击加号图标 -->
        <view class="chat-camera" wx:if="{{camera}}">
          <view wx:for="{{feature}}" wx:key="index" class="camera-feature" catchtap="featch" data-index="{{index}}">
            <view class="feature-src">
              <image src="{{item.src}}"></image>
            </view>
            <view class="feature-text">{{item.name}}</view>
          </view>
        </view>
      </view>
    </view>
    <!-- 加载图标 -->
    <view class="animation" wx:if="{{alcur}}">
      <image src="/images/recording.gif"></image>
    </view>
    

    Aichat.js

    var app = getApp()
    Page({
      data: {
        // 全局变量,控制全局显示样式
        globalData:{
          StatusBar:'',
          Custom:'',
          CustomBar:'',
        },
        // 消息列表(存在缓存中)
        newsList:[],
        // 用户唯一标识
        openid:'',
        // 头像
        figureurl_wx:'',
        // 是否显示加载图标
        animation:false,
        // 是否是发送声音
        voice:false,
        // 是否发送完成
        sendout:false,
        // 是否发送照片
        camera:false,
        // 新消息
        news:'',
        // 表情数组
        pression:[],
        // 是否是发送表情
        emojis:false,
        // 聊天列表高度
        curra:0,
        // 功能相册图标
        feature:[
          { src: '/images/album.png', name: '相册' }
        ],
        // 软键盘是否关闭
        alcur:false,
        // 视野(软键盘高度)
        vision:'',
        // 定时器对象
        time:'',
        // 期间
        duration:'',
        // 是否被正在播放录音
        playing:false,
        // 
        cuindex:'',
        // ai回答
        aiAnswer:'',
      
      },
      /**
       * 自定义导航栏,返回上一级
       */
      fanhui:function(e){
        // 清除聊天缓存
        wx.removeStorage({
          key: 'newsList',
          success: function(res) {
             
          },
        });
        wx.navigateBack({
          delta: 1
        });
      },
      /**
       * 监听页面底部输入框
       */
      cuinbut:function(e){
        let that = this
        setTimeout(function () {
          wx.createSelectorQuery().select('#chat-height').boundingClientRect(function (rect) {
            that.setData({
              // 底部输入框的高度
              chatheight: parseFloat(rect.height) + parseFloat(that.data.curra),
              // 当前最后一条信息
              curr: 'jump' + JSON.stringify(that.data.newsList.length - 1)
            })
          }).exec()
        }, 100);
        console.log(wx.getStorageSync('newsList'));
      },
      /**
       * 生命周期----显示页面
       */
      onShow:function(e){
        // 页面赋值,最新一条数据索引标识
        this.setData({
          curr: 'jump' + JSON.stringify(this.data.newsList.length-1)
        })
      },
      /**
       * 生命周期加载页面
       */
      onLoad: function (options) {
        let that = this;
        that.getUseridFromStorage();
        // 获取系统信息
        wx.getSystemInfo({
          success: e => {
            that.data.globalData.StatusBar = e.statusBarHeight;
            let capsule = wx.getMenuButtonBoundingClientRect();
            if (capsule) {
              that.data.globalData.Custom = capsule;
              that.data.globalData.CustomBar = capsule.bottom + capsule.top - (e.statusBarHeight + 15);
            } else {
              that.data.globalData.CustomBar = e.statusBarHeight + 50;
            }
          }
        });
        that.data.figureurl_wx = options.figureurl_wx;
        that.setData({
          // 用户唯一标识(这里是用户名)
          openid:options.openid,
          // 全局变量
          globalData: that.data.globalData,
          // 聊天记录存储在缓存中
          newsList: wx.getStorageSync('newsList'),
          // 表情列表
          pression: app.emoji.pression,
          // 录音
          vision: wx.getRecorderManager(),
        });
      },
        /**
       * 从缓存中获取用户信息
       */
      getUseridFromStorage:function()
      {
        var self = this;
        // 从缓存中获取用户id
        wx.getStorage({
          key: 'userinfo',
          success (res) {
            self.data.user_id = res.data.id;
            self.data.figureurl_wx = res.data.figureurl_wx;
            self.data.openid = res.data.nickname;
          }
        });
      },
      /**
       * 失去焦点事件
       */
      getkey:function(e){
        // 这个setdata的值没有用,wxml中无应用
        this.setData({
          curra: e.detail.height,
          emojis: false,
          camera: false
        })
        this.cuinbut();
      },
    /**
     * 获取焦点事件
     */
      getblur:function(e){
        this.setData({
          curra: 0,
          emojis: false,
          camera: false
        })
        this.cuinbut();
      },
      /**
       * 获取input输入的消息
       */
      moninput:function(e){
        let that = this
        that.cuinbut();
        this.setData({
          sendout: e.detail.value?true:false,
          news: e.detail.value,
        })
      },
      /**
       * 滚动条开始滚动,收起表情列表以及功能列表
       */
      scrollstart:function(e){
        this.setData({
          emojis: false,
          camera: false,
        })
        this.cuinbut();
      },
      /**
       * 点击语音图标时(收起功能栏)
       */
      speak:function(e){
        this.setData({
          voice: !this.data.voice,
          emojis:false,
          camera:false,
        })
        this.cuinbut();
      },
      /**
       * 点击表情栏时(收起功能栏)
       */
      emoji:function(e){
        this.setData({
          emojis: !this.data.emojis,
          voice:false,
          camera:false,
        })
        this.cuinbut();
      },
      /**
       * 点击功能栏时,收起声音和表情 
       */
      camerax:function(e){
        this.setData({
          camera: !this.data.camera,
          voice: false,
          emojis: false,
        })
        this.cuinbut();
      },
      /**
       * 上传图片
       */
      upload:function(e){
        const that = this
        // 微信选择图片
        wx.chooseImage({
          count: 1,
          success: function (res) {
            // 这是临时文件路径
            const src = res.tempFilePaths[0];
            // 获取图片信息
            wx.getImageInfo({
              src,
              success: function (res) {
                const { width, height } = res
                const newChatList = [...that.data.newsList,{
                  news_type: 'image',
                  news_centent: { src, width, height },
                  openid: that.data.openid,
                  logo:that.data.figureurl_wx
                }];
                // 用户消息发送完成,调用接口,等待AI回话
                that.aiChat('');
                that.setData({
                  animation: true,
                  newsList: newChatList,
                });
                // 同步设置缓存
                wx.setStorageSync('newsList', newChatList);
                that.cuinbut();
                // 用户消息发送完成,调用接口,等待AI回话
                that.aiChat();
              }
            })
          }
        })
      },
      /**
       * 点击看大图
       */
      picture:function(e){
        let src = e.currentTarget.dataset.src;
        wx.previewImage({
          current: src,
          urls: [src]
        })
      },
      /**
       * 发送消息接口
       */
      message:function(e){
        let that = this
        const newChatList = [...that.data.newsList, {
          news_type: 'text',
          news_centent: that.data.news,
          openid: that.data.openid,
          logo:that.data.figureurl_wx
        }];
        // 用户消息发送完成,调用接口,等待AI回话
        that.aiChat(that.data.news);
      
        that.setData({
          animation: true,
          newsList: newChatList,
          sendout:false,
          news: '',
        })
        wx.setStorageSync('newsList', newChatList);
        that.cuinbut();
      },
      /**
       * 选择表情
       */
      expression:function(e){
        let item = e.currentTarget.dataset.item
        this.setData({
          sendout: true,
          news: this.data.news+=item,
        })
      },
      /**
       * 点击功能图标
       */
      featch:function(e){
        let that = this
        let index = e.currentTarget.dataset.index
        if(index == 0){
          that.upload();
        }
      },
      /**
       * 按住说话
       */
      touchdown: function (e) {
        let that = this
        wx.stopVoice();
        that.setData({
          alcur: true,
          playing: false,
          cuindex: ''
        })
        that.data.duration = 0
        that.data.time = setInterval(function () {
          that.setData({
            duration: that.data.duration+1
          })
        },1000);
        // 开始录音
        wx.startRecord({
          success: function (res) {
            const newChatList = [...that.data.newsList, {
              news_type: 'voice',
              news_centent: { voice: res.tempFilePath, dimen: that.data.duration},
              openid: that.data.openid,
              logo:that.data.figureurl_wx
            }];
            // 用户消息发送完成,调用接口,等待AI回话
            that.aiChat('');
            that.setData({
              newsList: newChatList,
            })
            wx.setStorageSync('newsList', newChatList);
            that.cuinbut();
            // 用户消息发送完成,调用接口,等待AI回话
            that.aiChat();
          },
          fail:function(e){
            that.touchup();
          }
        });
        console.log(wx.getStorageSync('newsList'));
      },
      /**
       * 录音完成
       */
      touchup: function (e) {
        let that = this
        wx.stopRecord()
        clearInterval(that.data.time)
        that.setData({
          alcur:false
        })
      },
      /**
       * 播放录音
       */
      play: function (e) {
        console.log('123456');
        let that = this
        let voice = e.currentTarget.dataset.voice
        var index = e.currentTarget.dataset.index
        if (!that.data.playing){
          that.setData({
            playing:true,
            cuindex:index
          })
          wx.playVoice({
            filePath: voice,
            success: function () {
              that.setData({
                playing: false,
                cuindex:''
              })
            },
          })
        }
      },
      /**
       * 暂停录音
       */
      suspend:function(e){
        wx.stopVoice();
        this.setData({
          playing: false,
          cuindex: ''
        })
      },
      /**
       * 聊天接口
       * @param str 用户发的消息
       */
      aiChat:function(str)
      {
        var self = this;
        // 请求后台接口获取文章列表
        wx.request({
          // 请求连接
          url: 'https://guanchao.site/index/im/tencentAI',
          // 请求所需要的的参数
          data: {
            'str':str
          },
          success(result){
            self.data.aiAnswer = result.data.data.answer;
            if(result.data.msg != 'ok')
            {
              self.data.aiAnswer = "你的问题太深奥了,我没有办法回答~";
            }
            const newChatList = [...self.data.newsList, {
              news_type: 'text',
              news_centent: self.data.aiAnswer,
              openid: 'ai',
              logo:'https://guanchao.site/uploads/atricle/5c0a66cac42cb.jpeg'
            }];
            self.setData({
              animation: true,
              newsList: newChatList,
              sendout:false,
              news: '',
            })
            wx.setStorageSync('newsList', newChatList);
            self.cuinbut();
          }
        });
      },
      clicks:function(){
        console.log('12345');
      }
    })
    

    Aichat.json

    {
      "usingComponents": {},
      "navigationBarTitleText": "AI聊天",
      "navigationStyle": "custom"
    }
    

    Aichat.wxss

    page{
      background-color: #EDEDED;
    }
    .index{
      position:fixed;
      width: 100%;
      float: left;
      height: 64px;
      padding: 20rpx 220rpx 0 0;
      box-shadow: 0rpx 0rpx 0rpx;
      min-height: 0px;
      display: flex;align-items: center;
      background-color:#fff;
      z-index:9999;
      border-bottom: 1px solid #f7f7f7;
      top: 0;
    }
    .index-img{
      width: 34rpx;
      margin-left: 20rpx;
    }
    .index>text{
      margin-left: 20rpx;
      font-size: 28rpx;
      font-weight: bold;
    }
    .chat-index{
      /* padding-top: 30px; */
      width: 100%;
      float: left;
      overflow: hidden;
    }
    .scroll-view{
      width: 100%;
      float: left;
      overflow: hidden;
      background-color: #EDEDED;
    }
    .contrary{
      display:flex;
      flex-direction:row-reverse;
    }
    .news{
      width: 94%;
      float: left;
      overflow: hidden;
      padding: 0 3% 0 3%;
      margin-bottom: 26rpx;
    }
    .news:first-child{
      margin-top: 60rpx
    }
    .mews-image{
      width: 70rpx;
      height: 70rpx;
      float: left;
    }
    .mews-image>image{
      width: 100%;
      height: 100%;
      border-radius: 10rpx;
    }
    .news-centent{
      width: 70%;
      float: left;
      overflow: hidden;
      position: relative;
    }
    .centent-right{
      margin-right: 10rpx;
      padding: 0 15rpx 0 0;
    }
    .centent-left{
      margin-left: 10rpx;
      padding: 0 0 0 15rpx;
    }
    .trianright{
      width:0;
      height:0;
      border-top:15rpx solid transparent;
      border-bottom:15rpx solid transparent;
      border-left:15rpx solid #FFFFFF;
      position: absolute;
      right: 0;
      top: 20rpx;
    }
    .trianleft{
      width:0;
      height:0;
      border-top:15rpx solid transparent;
      border-bottom:15rpx solid transparent;
      border-right:15rpx solid #95EB69;
      position: absolute;
      left: 0;
      top: 20rpx;
    }
    .centent-right>text{
      float: right;
    }
    .centent-right>.news-images{
      float: right;
    }
    .centent-right>.news-voice{
      float: right;
    }
    .centent-left>text{
      float: left;
    }
    .centent-left>.news-images{
      float: left;
    }
    .centent-left>.news-voice{
      float: left;
    }
    .news-centent>text{
      word-wrap:break-word;
      word-break:normal; 
      padding: 16.5rpx;
      /* background-color: #95EB69; */
      color: #000200;
      border-radius: 8rpx;
      font-size: 28rpx;
      max-width: 100%;
      line-height: 42rpx;
    }
    .news-centent>.news-images{
      max-width: calc(100%);
      padding: 16.5rpx;
      background-color: #95EB69;
      border-radius: 8rpx;
    }
    .news-centent>.news-voice{
      height: 70rpx;
      background-color: #95EB69;
      border-radius: 8rpx;
      padding: 0 10rpx;
      display: flex;
      align-items: center;
    }
    .centent-left>.news-voice>text{
      padding: 0 30rpx 0 15rpx;
      font-size: 26rpx;
      font-weight: bold;
    }
    .centent-right>.news-voice>text{
      padding: 0 15rpx 0 30rpx;
      font-size: 26rpx;
      font-weight: bold;
    }
    .centent-left>.news-voice>image{
      float: left;
    }
    .centent-right>.news-voice>image{
      float: right;
    }
    .news-voice>image{
      width: 50rpx;
      height: 42rpx;
    }
    .chat-bottom{
      width: 100%;
      float: left;
      overflow: hidden;
      background-color: #F7F7F7;
      transition:all 0.5s;
    }
    .chat-centent{
      width: 100%;
      float: left;
      overflow: hidden;
      position: relative;
      padding: 0 1.5%;
    }
    .chat-pression{
      width: 7%;
      height: 100rpx;
      display: flex;
      align-items: center;
      text-align: center;
      float: left;
    }
    .chat-pression>image{
      width: 45rpx;
      height: 45rpx;
      margin: 0 auto;
    }
    .chat-tencvi{
      width: 73%;
      padding: 0 1%;
      float: left;
      display: flex;
      align-items: center;
      transition:all 0.5s;
    }
    .chat-tencvi>textarea{ 
      background-color: #fff;
      border-radius: 8rpx;
      width: 100%;
      padding: 3%;
      font-size: 28rpx;
      margin: 20rpx 0;
      max-height: 180rpx;
    }
    .chat-tencvi>view{
      width: 100%;
      padding: 3%;
      margin: 20rpx 0;
      background-color: #fff;
      border-radius: 8rpx;
      font-size: 26rpx;
      text-align: center;
    }
    .chat-news{
      height: 100rpx;
      float: right;
      display: flex;
      align-items: center;
      
    }
    .chat-news>view{
      width: 80%;
      background-color: #07C160;
      color: #fff;
      border-radius: 8rpx;
      height: 60rpx;
      line-height: 60rpx;
      font-size:26rpx;
      text-align: center;
    }
    .chat-cube{
      width: 100%;
      float: left;
      overflow: hidden;
      height: 400rpx;
      background-color: #EDEDED;
      border-top: 1px solid #ddd;
      padding:2% 0 8% 0;
      overflow-y: auto;
    }
    .cube-title{
      width: 100%;
      float: left;
      font-size: 24rpx;
      padding:0 3.5%;
      position: relative;
      top: 10rpx;
    }
    .cube-centent{
      width: 100%;
      float: left;
      overflow: hidden;
    }
    .cube-centent>view{
      margin-top: 30rpx;
      width: 12.5%;
      float: left;
      text-align: center;
    }
    .chat-camera{
      width: 100%;
      float: left;
      overflow: hidden;
      padding-bottom: 60rpx;
      background-color: #EDEDED;
      border-top: 1px solid #ddd;
      overflow-y: auto;
    }
    .camera-feature{
      margin: 60rpx 0 0 5%;
      width: 18.75%;
      float: left;
      overflow: hidden;
      text-align: center;
      font-size: 20rpx;
    }
    .feature-src{
      background-color: #fff;
      border-radius: 15rpx;
      float: left;
      width: 80rpx;
      height: 80rpx;
      margin: 0 calc(50% - 40rpx);
      text-align: center;
    }
    .feature-src>image{
      width: 40rpx;
      height: 40rpx;
      margin:20rpx;
    }
    .feature-text{
      width: 100%;
      float: left;
      margin-top: 10rpx;
    }
    .animation{
      z-index: 10;
      position: fixed;
      width:300rpx;
      height: 300rpx; 
      border-radius: 50%;
      margin: calc((100vh - 300rpx)/2) calc((100% - 300rpx)/2);
    }
    .animation>image{
      width: 100%;
      height: 100%;
      border-radius: 50%;
    }
    .animation::before {
      content: "";
      display: block;
      background-color: #ccc;
      filter: blur(10rpx);
      position: absolute;
      width: 100%;
      height: 100%;
      top: 10rpx;
      left: 10rpx;
      z-index: -1;
      opacity: 0.4;
      transform-origin: 0 0;
      border-radius: inherit;
      transform: scale(1, 1);
    }
    .chat-cbins{
      z-index: 10;
      width: 100%;
      background-color: rgba(26, 26, 26, 0.6);
      color: #fff;
      padding: 3%;
      font-size: 22rpx;
    }
    .background_left{
      background-color: #95EB69;
    }
    .background_right{
      background-color: #FFFFFF;
    }
    

    代码基本上就是这些了,其实没有多少东西,当然,就这么几行代码实现出来的效果肯定是有bug的,这个不要有太高的期望。

    有好的建议,请在下方输入你的评论。
    欢迎访问我的小程序:
    在这里插入图片描述

    展开全文
  • 主要为大家详细介绍了微信小程序实现留言功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 效果图 wxml <view class="container "> <!-- stars --> <view class="star star-1"></view> <view class="star star-2"></view> <...view class="cloud
  • 微信小程序分享 实现微信小程序分享和app内微信分享 小程序分享很简单,我们通过button的open-type属性 <!-- #ifdef MP-WEIXIN --> <button class="share-btn" open-type="share">立即分享</button&...
  • 第一次写小程序,老板就让我用websoket写个聊天对话,群聊这种。第一次写聊天功能,第一次用websoket,第一次用小程序,这是在考验我吗?不过我还是研究了一下,终于实现了。 首先看一下界面界面很简单,就是首页刚...
  • 开发的时候这个老表帮了我不少忙,帮忙测试找问题,还别说一开始有很多问题。在这里感谢这位老表。 目前只支持文字聊天。消息列表页面仿微信,chat页面仿QQ,我真是个带天才哈哈哈。 # 背景 在本文开始前,请确保...
  • 微信小程序-仿QQ

    2017-11-21 15:51:22
    微信小程序-仿QQ微信 微信小程序官方demo,官方文档,开发工具,高仿手机QQ应用程序,持续更新中...
  • 微信小程序中各个界面之间的传值和通知比较蛋疼。所以模仿了iOS中的通知中心,在微信小程序中写了一套类似的通知中心。 通知中心可以做到:1对多发消息,传递object。使用十分简洁。 使用时,在需要接收消息的界面...
  • 微信小程序即时通讯 开发这个项目付出了我很多心血,如果对你有帮助和启发的话,希望在GitHub上给个star!也是对我工作的支持和肯定! 也非常感谢对项目中文本超长溢出布局的问题的修正和提交! 介绍: wechat-im是...
  • 小程序制作仿微信聊天的细节处理

    千次阅读 2019-06-02 11:32:37
    记录做的一次仿聊天小程序碰到的一些细节 问题: 1.键盘输入框随内容自动增高 2.每次发完消息屏幕在发出消息的最底部(以及上拉在最上面) 3.键盘弹起不盖住屏幕内容 解决: 一、解决输入框内容的自动增高...
  • 微信小程序录制语音波浪效果 为测试使用,带了些其他元素
  • 薪资是比去年找的实习涨了1.5倍,不过还是好低,希望以后能更加努力啦~ 这次我要给大家分享的是我上个学期做的期末作品,一个抖音版的“知乎”,其实就是一个话题类的微信小程序,希望对有这方面需求的人有一些帮助~...
  • 适用范围:所有版本微信小程序库 日期 :2019/9/2 前端: <scroll-view style="height:{{height}}vh;width: 100vw;display: flex; position: relative;flex-direction: column;top:{{top?top:0}}px;" ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,209
精华内容 4,083
关键字:

微信小程序聊天界面

微信小程序 订阅