5分钟

任务 4 小程序页面实现

任务目的

编写小程序界面和必要的交互脚本。

任务步骤

1.删除小程序自动生成的多余页面

将 miniprogram 文件夹下小程序自动生成的多余的页面进行删除,包括:

  • components 文件夹
  • images 文件夹下所有的图片(保留 images 文件夹)
  • pages 文件夹下除 index 文件夹之外的其他文件夹。
删除多余文件夹和文件

可以在微信开发者工具中删除,也可以直接进入硬盘进行删除。

2.改写小程序配置文件

点击 miniprogram 文件夹下的 app.json,将 app.json 改写为

{
  "pages": [
    "pages/index/index"
  ],
  "window": {
    "backgroundColor": "#F6F6F6",
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#F6F6F6",
    "navigationBarTitleText": "趣味复读机器人",
    "navigationBarTextStyle": "black"
  },
  "sitemapLocation": "sitemap.json",
  "style": "v2"
}

小程序的配置比较简单,主要把多余的页面删除,仅留 index 页面,修改默认的主题名即可。

3.修改 index 页面

下载本次小程序开发所需的图片资源,点击此处下载。将下载后的文件解压放到 miniprogram/images 文件夹下。

添加图片

将 index 文件夹下默认带的 user-unlogin.png 删除。将 index.wxml 替换成以下代码。

<view class="flex-row" style="display:flex;">
  <checkbox-group name="checkbox" class="check">
    <label bindtap='changeVoiceType' wx:for="{{voiceTypes}}" wx:key="index" data-voiceType="{{item.num}}" class='{{item.checked?"is_checked":""}}'>
      <checkbox hidden='false' /> {{item.name}}
    </label>
  </checkbox-group>
</view>
<scroll-view upper-threshold="100" scroll-into-view="{{toView}}" scroll-top="{{scrollTop}}" scroll-y="true" enable-back-to-top="true" style="height: {{scroll_height}}px;" class="message-list">
	<!-- 每一行 -->
	<view class="row" wx:for="{{message_list}}" wx:key="index" id="row_{{index}}">
		<!-- 头像与内容文本 -->
		<view class="body" style="flex-flow: {{item.myself == 0 ? 'row' : 'row-reverse'}}">
			<view class="avatar-container">
				<image class="avatar" src="{{item.head_img_url}}" />
			</view>
			<!-- 画三角箭头 -->
			<view class="triangle" style="{{item.myself == 1 ? 'right: 140rpx; background: #7ECB4B' : 'left: 140rpx;'}}"></view>
			<view class="content" style="{{item.myself == 1 ? 'background: #7ECB4B' : ''}}">
        <view bindtap="playVoice" data-src="{{item.content}}" style="width:40px">
          <image class="ico" src="/images/voice.png"/>
        </view>
			</view>
		</view>
	</view>
</scroll-view>
<view class="hud-container" wx:if="{{status != state.normal}}">
	<view class="hud-background"></view>
	<view class="hud-body">
		<image src="/images/mic.png" />
		<view class="tip {{status == state.cancel ? 'warning' : ''}}">{{tips[status]}}</view>
	</view>
</view>
<view class="reply">
	<view class="opration-area">
		<button class="voice-button" bindlongpress="record" bindtouchstart="touchStart" bindtouchmove="touchMove" bindtouchend="touchEnd">{{tips[status]}}</button>
	</view>
</view>

将 index 文件夹下 index.wxss 替换成以下代码

/*聊天记录*/
.message-list {
	/*margin-bottom: 54px;*/
	background: rgb(235, 235, 235);
}

/*单元行*/
.row {
  display: flex;
  flex-direction: column;
  margin: 0 30rpx;
}

/*日期*/
.datetime {
	font-size: 10px;
	padding: 10px 0;
	color: #999;
	text-align: center;
}

/*主体*/
.body {
	display: flex;
	flex-direction: row;
	align-items: flex-start;
	justify-content: flex-start;
	width: 100%;
	margin-top: 10px;
}


/*头像容器*/
.body.avatar-container {
	width: 20%;
}

/*头像*/
.body .avatar {
	width: 80rpx;
	height: 80rpx;
	border-radius: 50%;
	margin: 0 20rpx;
}

/*文本消息*/
.body .content {
	font-size: 16px;
	background: #fff;
	border-radius: 5px;
	padding: 10px;
	line-height: 22px;
	margin-bottom: 10px;
}

/* 三角箭头 */
.body .triangle {
	background: white;
	width: 20rpx;
	height: 20rpx;
	margin-top: 26rpx;
	transform: rotate(45deg);
	position: absolute;
}

/*图片消息*/
.picture {
	width: 160px;
}

/*回复框*/
.reply {
	display: flex;
	flex-direction: row;
	justify-content: flex-start;
	align-items: center;
	position: fixed;
	bottom: 0;
	width: 100%;
	height: 54px;
	border-top: 1px solid rgb(215, 215, 215);
	background: rgb(245, 245, 245);
}

.reply .voice-image {
	width: 25px;
	height: 25px;
	margin-left: 3%;
}

/*文本输入或语音录入*/
.reply .opration-area {
	flex: 1;
	padding: 8px;
}

/*按住说话button*/
.voice-button {
	height: 36px;
	color: #818181;
	font-size: 14px;
	line-height: 24px;
	width: 300px !important;
  background: #F9F9F9
}

/*悬浮提示框*/
.hud-container {
	position: fixed;
	width: 150px;
	height: 150px;
	left: 50%;
	top: 50%;
	margin-left: -75px;
	margin-top: -75px;
}

/*背景层*/
.hud-background {
	position: absolute;
	width: 100%;
	height: 100%;
	background: #999;
	opacity: .8;
	z-index: 11;
	border-radius: 10px;
}

/*悬浮框主体*/
.hud-body {
	position: relative;
	width: 100%;
	height: 100%;
	z-index: 19;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	align-items: center;
}

/*图标*/
.hud-body image {
	margin-top: 20px;
	width: 80px;
	height: 80px;
}

/*文字*/
.hud-body .tip {
	color: #fff;
	text-align: center;
	width: 90%;
	line-height: 34px;
	margin: 0 auto;
	margin-bottom: 10px;
}

.hud-body .warning {
	background: #cc3333;
	border-radius: 5px;
}

.ico{ 
  width: 43rpx; 
  height: 50rpx; 
  float: left;
}

label{
   border:2rpx solid #aaaaaa;
}
.check {
  display:flex;
  flex-wrap:wrap;
  justify-content:space-around;
}
.check label {
  color: #818181;
  width: 175rpx;
  height: 60rpx;
  border-radius: 8rpx;
  display: flex;
  align-items: center;
  margin: 0 5rpx;
  justify-content: center;
  margin-top: 20rpx;
  font-size: 30rpx;
}
.is_checked {
   background: #7ECB4B;
   color: #fff !important;
   border: 2rpx solid #fff;
}
.is_checked>checkbox {
  color: red;
}

将 index 文件夹下 index.js 替换成以下代码

Page({
  data: {
    message_list: [],
    scroll_height: wx.getSystemInfoSync().windowHeight - 54,
    page_index: 0,
    cancel: false,
    status: 0,
    tips: ['按住 说话', '松开 结束', '取消 发送'],
    voiceTypes: [{
        name:'亲和女声',
        num:0,
        checked:true
      },{
        name:'亲和男声',
        num:1,
        checked: false
      },{
        name:'成熟男声',
        num:2,
        checked: false
      },{
        name:'温暖女声',
        num:4,
        checked: false
      }],
    voiceType:0,
    state: {
      'normal': 0,
      'pressed': 1,
      'cancel': 2
    },
    toView: '',
    currentText: ''
  },
  //录音功能,后期改写
  record: function () {

  },
  //录音结束后将会发送语音到界面,后期改写
  stop: function () {
    this.sendVoice("tempfile",1)
    this.sendVoice("tempfile", 0)
  },
  touchStart: function (e) {
    // 触摸开始
    var startY = e.touches[0].clientY;
    // 记录初始Y值
    this.setData({
      startY: startY,
      status: this.data.state.pressed
    });
  },
  touchMove: function (e) {
    // 触摸移动
    var movedY = e.touches[0].clientY;
    var distance = this.data.startY - movedY;
    this.setData({
      status: distance > 50 ? this.data.state.cancel : this.data.state.pressed
    });
  },
  touchEnd: function (e) {
    // 触摸结束
    var endY = e.changedTouches[0].clientY;
    var distance = this.data.startY - endY;
    this.setData({
      cancel: distance > 50 ? true : false,
      status: this.data.state.normal
    });
    // 不论如何,都结束录音
    this.stop();
  },
  scrollToBottom: function () {
    this.setData({
      toView: 'row_' + (this.data.message_list.length - 1)
    });
  },
  sendVoice: function (tempUrl, num) {
    var message_list = this.data.message_list;
    var message = {
      myself: num,
      head_img_url: '/images/userimg.jpg',
      content: tempUrl,
    };
    message_list.push(message);
    this.setData({
      message_list: message_list
    })
    this.scrollToBottom()
    setTimeout(() => {
      wx.hideLoading();
    }, 500)
  },
  changeVoiceType:function(e){
    let voiceType = e.currentTarget.dataset.voicetype;
    let arrys = this.data.voiceTypes;
    for(let i = 0;i<arrys.length;i++){
      if(arrys[i].num == voiceType){
        arrys[i].checked = true
      }else{
        arrys[i].checked = false
      }
    }
    this.setData({
      voiceTypes: arrys,
      voiceType:voiceType
    })
  },
  //播放语音功能,后期填写功能
  playVoice:function(){

  }
})

替换完毕后,保存代码,或者点击【编译】按钮,可以从模拟器中看到效果

模拟器中小程序效果