微信小程序实战-第6章 API应用案例(下)
6.1 【案例5】模拟时钟
6.1.1案例分析
6.1.2前导知识
canvas用法:
- 创建canvas.wxml文件。
<canvas canvas-id="myCanvas"></canvas>
- canvas组件默认样式如下。
canvas {
width: 300px;
height: 150px;
display: block;
position: relative;
}
第1步:创建Canvas绘图上下文对象CanvasContext
const ctx = wx.createCanvasContext('myCanvas')
第2步:使用Canvas绘图上下文进行绘图描述
ctx.setFillStyle('red') // 设置填充色为红色
// 画一个矩形,填充为红色
ctx.fillRect(10, 20, 150, 75) // ctx.fillRect(x, y, width, height)
第3步:画图
ctx.draw()
第1步:创建Canvas绘图上下文对象CanvasContext
const ctx = wx.createCanvasContext('myCanvas')
第2步:设置线条颜色和线宽
ctx.setStrokeStyle('#ff0000')
ctx.setLineWidth(2)
第3步:移动画笔坐标位置,绘制(外部大圆)
ctx.moveTo(160, 100)
ctx.arc(100, 100, 60, 0, 2 * Math.PI, true)
第4步:移动画笔坐标位置,绘制(嘴巴线条)
ctx.moveTo(140, 100)
ctx.arc(100, 100, 40, 0, Math.PI, false)
第5步:移动画笔坐标位置,绘制(左眼圆圈)
ctx.moveTo(85, 80)
ctx.arc(80, 80, 5, 0, 2 * Math.PI, true)
第6步:移动画笔坐标位置,绘制(右眼圆圈)
ctx.moveTo(125, 80)
ctx.arc(120, 80, 5, 0, 2 * Math.PI, true)
第7步:画出当前路径的边框
ctx.stroke()
第8步:移动画笔坐标位置,绘制(左眼圆圈)
wx.draw ()
CanvasContext.draw ():将之前在绘图上下文中的描述(路径、样式、变形)画到canvas中。
CanvasContext.arc():创建一条弧线。
CanvasContext.rect():创建一个矩形路径。
CanvasContext.lineTo():新增一个新点,用stroke方法来画线条。
CanvasContext.moveTo():把路径移动到画布中的指定点,不创建线条。
6.1.3钟表页面布局
clock.wxml
<canvas canvas-id="myCanvas" class="mycanvas"></canvas>
clock.wxss
.mycanvas{ width: 100%;height: 100%;position: fixed; }
6.1.4钟表页面绘制
clock.js
Page({
width: 0, height: 0 ,// 初始化宽高
onLoad: function() { wx.getSystemInfo({ }) }, // 获取系统的宽高
timer:null,
onReady: function() {
… …
function draw(){ } // 绘制函数
function drawClock(ctx, radius) {} // 绘制表盘部分
function drawHand(ctx, radius) {} // 绘制指针部分
}
})
6.2 【案例6】罗盘动画
6.2.1案例分析
6.2.2前导知识
6.2.3设计罗盘界面布局
6.2.4手指触摸旋转罗盘
compass.js
var animation
var angle = 0
var x1, y1, x3, y3
// 判断坐标系是顺时针还是逆时针
function judgeturn(x1, y1, x3, y3) {
var x2 = 150
var y2 = 150
return !((x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2) > 0)
}
6.2.5单击按钮操作罗盘
rotate: function() {
animation.rotate(Math.random() * 720 - 360).step()
this.setData({
animation: animation.export()
})
},
scale: function() {
animation.scale(Math.random() * 2).step()
this.setData({
animation: animation.export()
})
},
translate: function() {
animation.translate(Math.random() * 100 - 50,
Math.random() * 100 - 50).step()
this.setData({
animation: animation.export()
})
},
skew: function() {
animation.skew(Math.random() * 90, Math.random() * 90).step()
this.setData({
animation: animation.export()
})
},
rotateAndScale: function() {
animation.rotate(Math.random() * 720 - 360)
.scale(Math.random() * 2)
.step()
this.setData({
animation: animation.export()
})
},
rotateThenScale: function() {
animation.rotate(Math.random() * 720 - 360).step()
.scale(Math.random() * 2).step()
this.setData({
animation: animation.export()
})
},
all: function() { // 旋转-缩放-移动-倾斜
animation.rotate(Math.random() * 720 - 360)
.scale(Math.random() * 2)
.translate(Math.random() * 100 - 50, Math.random() * 100 - 50)
.skew(Math.random() * 90, Math.random() * 90)
.step()
this.setData({
animation: animation.export()
})
},
allOrder: function() { // 旋转-缩放-移动-倾斜
animation.rotate(Math.random() * 720 - 360).step()
.scale(Math.random() * 2).step()
.translate(Math.random() * 100 - 50, Math.random() * 100 - 50).step()
.skew(Math.random() * 90, Math.random() * 90)
.step()
this.setData({
animation: animation.export()
})
},
reset: function() {
animation.rotate(0, 0).scale(1).translate(0, 0).skew(0, 0)
.step({duration: 0})
this.setData({
animation: animation.export()
})
}
6.3 【案例7】文件上传与下载
6.3.1案例分析
6.3.2前导知识
var rec = wx.getRecorderManager() //获取全局唯一的录音管理器rec
recorderManager.start(options) // 开始录音
recorderManager.onStart(() => {} ) // 监听录音开始事件
recorderManager.onResume(() => {} )// 监听录音继续事件
recorderManager.onPause(() => {} ) // 监听录音暂停事件
recorderManager.onStop((res) => {const { tempFilePath } = res }) // 监听录音结束事件
recorderManager.onFrameRecorded((res) => { const { frameBuffer } = res }) // 监听已录制完指定帧大小的文件事件
wx.chooseImage({
success (res) {
const tempFilePaths = res.tempFilePaths
wx.uploadFile({
url: 'https://xxxx', // 开发者服务器地址
filePath: tempFilePaths[0],
name: 'file', // 文件对应的key
formData: {'user': 'test'}, // HTTPS请求中其他额外的form data
success (res){ const data = res.data // do something }
}) }
})
wx.downloadFile({
url: : 'https://xxxx',
success (res) {
if(res.statusCode === 200){
wx.playVoice({ filePath: res.tempFilePath })
}
}
})
6.3.3录音和上传
在Page()前面编写代码,获取音频实例对象和录音管理器对象,并在录音完成后保存音频文件的临时路径
index.js
var tempFilePath = null // 音频文件临时路径
var audioCtx = wx.createInnerAudioContext() // 获取音频对象
var rec = wx.getRecorderManager() // 获取录音管理器对象
rec.onStop(res => {
tempFilePath = res.tempFilePath
console.log(tempFilePath)
})
Page({ …… })
6.3.4文件的下载
6.4 【案例8】在线聊天系统
6.4.1案例分析
6.4.2前导知识
wx.connectSocket({
url: 'ws://127.0.0.1:3000' // 服务器地址
})
wx.sendSocketMessage({
data: msg,
success: () => {}
})
wx.connectSocket({ url: 'ws://127.0.0.1:3000', })
wx.onSocketOpen(function() { console.log('连接成功'); })
// 监听服务器端发送到客户端的消息
wx.onSocketMessage(msg => {
var data = JSON.parse(msg.data)
console.log(data)
})
6.4.3编写Node.js服务器端代码
本节选择使用Node.js搭建开发者服务器,安装Node.js,创建项目:
npm init –y
npm install websocket
npm install nodemon -g
执行上述命令后,在项目目录下创建socket.js文件,编写代码如下:
const http = require('http')
// 引入WebSocket
const WebSocketServer = require('websocket').server
// 创建一个HTTP Server
const httpServer = http.createServer((request, response) => {
response.writeHead(404)
response.end()
})
const wsServer = new WebSocketServer({
httpServer, autoAcceptConnections: true
})
wsServer.on('connect', connection => {
connection.on('message', message => {
if (message.type === 'utf8') {
var data = {content: '自动回复', date: '2019-01-16'}
connection.sendUTF( JSON.stringify(data) ) // 服务器返回的信息
} })
// 连接的关闭监听
connection.on('close', (reasonCode, description) => {
console.log('[' + new Date() + '] Peer ' + connection.remoteAddress +
' disconnected.')
})
// 接收控制台中的输入
process.stdin.on('data', function(data){
var data = data.toString().trim()
data = {'content': data, 'date': '2010-01-01'}
connection.sendUTF( JSON.stringify(data) )
})
})
app.listen(3000, () => {
console.log('[' + new Date() + '] server is listening on port 3000')
})
nodemon socket.js
6.4.4实现通信功能
{
"pages":[
"pages/index/index"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTextStyle":"black"
}
}
Page({
onLoad: function() {
wx.connectSocket({ url: 'ws://127.0.0.1:3000' })
// 连接成功
wx.onSocketOpen(function() {
wx.sendSocketMessage({ data: '你好' })
})
wx.onSocketMessage(function(msg) {console.log(msg) })
wx.onSocketClose(function(res) { console.log('WebSocket已关闭') })
}
})
执行上述代码,在服务器控制台看到输出结果。
>> message content from client: 你好
小程序端控制台接收消息结果,如下图所示:
6.4.5编写聊天界面
index.wxml
<view class="chat-news" wx:for="{{newslist}}" >
<!-- (role值为me,发送的消息显示在右侧 )-->
<block wx:if="{{item.role == 'me'}}">
<view class="news-lf"></view>
</block>
<!-- (role值为server,收到的消息显示在左侧)-->
<block wx:else>
<view class="news-rl"></view>
</block>
</view>
index.wxml
<form class="sendMessage">
<input type="text" cursor-spacing="80" placeholder="请输入聊天内容.."
value="{{massage}}" bindinput="bindChange"></input>
<button type="primary" bindtap="send" formType="reset" size="small"
button-hover="blue">发送</button>
</form>
进入index.js文件,监听服务器发送给客户端的消息,并将消息显示在页面中。
wx.onSocketMessage((msg) => {
var data = JSON.parse(msg.data)
data.role = 'server' // 设置角色; data.id = ++this.id
var list = this.data.newslist; list.push(data)
this.setData({
newslist: list, // 将新消息追加到消息列表
message: null // 发送完成之后清空输入框信息
})
this.rolling_bottom()
})
编写rolling_bottom()方法,使聊天内容始终显示在最底端。
rolling_bottom: function() {
var s = 0
var list = wx.createSelectorQuery().selectAll('.list')
list.boundingClientRect(rects => {
rects.forEach( rect => {
this.setData({ scrollTop: rect.bottom })
})
}).exec()
},
初始化data:{}数据。
data: {
scrollTop: 0,
message: '',
newslist: []// 消息列表数组
},
编写input输入框绑定事件bindChange()函数,监听input值的改变。
bindChange(res) {
this.setData({ message: res.detail.value })
}
编写“发送”按钮绑定事件send()函数,判断发送内容是否为空。
id: 0,
send: function() { // 判断发送内容是否为空
if (this.data.message) { // 如果不为空
wx.sendSocketMessage({ data: this.data.message })
this.rolling_bottom(); var list = []
list = this.data.newslist var temp = { … }
list.push(temp); this.setData({ newslist: list, message: null })
} else { ... } // 在后面编写发送对象为空的逻辑代码
this.rolling_bottom()
}
编写temp对象。
var temp = {
id: this.id++, // id
content: this.data.message, // 输入的内容
// 系统时间,引用utils/util.js 中formatTimeNew函数
date: utils.formatTimeNew(new Date()),
role: 'me' // 角色
}
编写发送对象为空的逻辑代码。
else {
// 弹出提示框
wx.showToast({
title: '消息不能为空哦~',
icon: 'none',
duration: 2000
})
}
this.rolling_bottom()
}
编写关闭页面的onUnload()函数,关闭WebSocket连接。
// 页面卸载,关闭连接
onUnload: function () {
wx.closeSocket()
console.log('连接已断开')
}
本章总结
本章讲解了canvas绘图、animation动画、文件上传与下载、录音与播放,以及通过WebSocket实现在线聊天系统。通过本章学习,读者应掌握这些技术的使用,能够利用canvas来绘制各种图形;能够使用animation动画实现移动、旋转、移动、缩放等效果;能够根据实际需求开发文件上传、下载、录音、在线聊天等功能。