小程序開(kāi)發(fā)教程欄目介紹微信小程序開(kāi)發(fā)的一些問(wèn)題
推薦(免費(fèi)):小程序開(kāi)發(fā)教程
微信小程序開(kāi)發(fā)問(wèn)題匯總
- 樣式如何使用變量
- video遮罩問(wèn)題
- 彈幕自動(dòng)上推信息流
- 軟鍵盤(pán)問(wèn)題
- websocket使用
-
- weapp.socket.io
- 小程序當(dāng)中的使用
小程序開(kāi)發(fā)告一段落,總結(jié)一下這段時(shí)間小程序開(kāi)發(fā)遇到的問(wèn)題及解決方案,react沖沖沖!??!
樣式如何使用變量
在wxss中,定義變量:width:var(–width–);
在js中,定義變量:viewWidth,并給這個(gè)變量賦予想要的值
在wxml中,使用wxss中的變量和js中的變量:style="–width–: {{ viewWidth }}px"
video遮罩問(wèn)題
在實(shí)現(xiàn)直播的功能時(shí),我們需要彈出紅包等遮蓋video的處理,此時(shí)會(huì)發(fā)現(xiàn),使用z-index屬性在小程序中是無(wú)效的,微信開(kāi)發(fā)者文檔提供了cover-view,cover-imge等控件實(shí)現(xiàn)遮罩的功能。
這里值得注意的是cover-view中的background-image屬性是無(wú)效的,所以我們要安放背景圖時(shí)需要使用到cover-image,并且將它的position設(shè)置為absolute, top為0, left也為0即可。
彈幕自動(dòng)上推信息流
首先是將這個(gè)scroll的高度定死,讓scroll自動(dòng)滑動(dòng)到某個(gè)item的位置:
<scroll-view class="danmu-list" scroll-y="true" scroll-into-view="{{'item_' + danmulist.length}}" style="height: {{windowHeight - 890}}rpx"> <view id="{{'item_' + (index + 1)}}" wx:for="{{danmulist}}" class="{{item.nickName == username ? 'danmu-item owner' : 'danmu-item'}}" wx:key="this"> <view class="nickname">{{item.nickName}}:</view> <view class="content {{ item.system ? 'system' : '' }}" style="color: {{ item.system ? '#71f474' : (item.color || '#fff')}}">{{item.content}}</view> </view> </scroll-view>
為scroll添加樣式:
.danmu-list { width: 750rpx; height: 290rpx; position: relative; padding-top: 27rpx;}.danmu-item { padding: 0 27rpx;}.danmu-item .nickname { color: #cdd5ff; font-size: 26rpx; display: inline-block;}.danmu-item.owner .nickname { color: #ffab00;}.danmu-item .content { color: #ffffff; font-size: 26rpx; display: inline-block;}
可以看到在小程序上的實(shí)現(xiàn),明顯比在網(wǎng)頁(yè)上要簡(jiǎn)單,我們只需要一個(gè)scroll-into-view
的屬性,并且為每個(gè)item添加一個(gè)id即可。
那么有沒(méi)有純css的實(shí)現(xiàn)呢?當(dāng)然。
我們將item都放在一個(gè)盒子中,讓盒子的相對(duì)于list底部對(duì)齊,overflow則進(jìn)行scroll,這樣同樣能實(shí)現(xiàn)現(xiàn)在的效果。
軟鍵盤(pán)問(wèn)題
此次開(kāi)發(fā),需要實(shí)現(xiàn)一個(gè)輸入框點(diǎn)擊,軟鍵盤(pán)彈起,選擇顏色功能。我們看下效果圖:
那么考慮幾個(gè)問(wèn)題:
1、選擇顏色時(shí)鍵盤(pán)失去焦點(diǎn)會(huì)縮起
微信小程序提供了一個(gè)hold-keyboard
屬性
我在input 中設(shè)定了hold-keyboard="true"
2、軟鍵盤(pán)彈出時(shí)會(huì)自動(dòng)把頁(yè)面上推,但是我們僅僅想要軟鍵盤(pán)把input框上推而不是整個(gè)頁(yè)面。
分析一下這個(gè)問(wèn)題,首先是考慮純css解決方案,把頁(yè)面設(shè)為fixed,然而不起作用;接下來(lái)考慮頁(yè)面彈起時(shí)減去軟鍵盤(pán)的高度讓它恢復(fù)到原位,這會(huì)帶來(lái)兩個(gè)問(wèn)題:1)軟鍵盤(pán)彈起后才能獲取軟鍵盤(pán)高度,這樣一來(lái)頁(yè)面的下落會(huì)產(chǎn)生嚴(yán)重的滯后;2)同樣的不起作用
這個(gè)問(wèn)題最終的解決方案是這樣的:
首先查看官方文檔,微信小程序提供了一個(gè)adjust-position
屬性
設(shè)定adjust-position=“false"
,此時(shí)的確不會(huì)進(jìn)行頁(yè)面的上推了,但是我們需要的input框上推如何實(shí)現(xiàn)?
我們可以在input的方法參數(shù)e.detail.height中拿到軟鍵盤(pán)的高度,設(shè)定input的高度為e.detail.height的高度即可。
最終代碼:
<cover-view wx:if="{{inputParam.colorShow}}" class="color-check" style="bottom: {{inputParam.bottom + (windowWidth / 750 * 90)}}px"> <cover-image class="color-background" src="{{assets}}/images/live-index-danmu-send-color-check.png"></cover-image> <cover-view class="color-list"> <cover-view wx:for="{{colorStatusList}}" wx:key="this" catchtap="checkColor" data-index="{{index}}" class="{{item.checked == 0 ? 'color-icon' : 'color-icon with-border'}}" style="background-color: {{item.color}}"></cover-view> </cover-view> </cover-view> <view class="enterDanmu" style="bottom: {{inputParam.bottom}}px"> <input hold-keyboard="true" catchtap catchfocus="enterMessage" bindconfirm="loseColor" bindinput="getInputValue" placeholder="發(fā)個(gè)彈幕唄~" placeholder-style="font-size: 26rpx; color: #09091b" style="color:{{fontcolor}};" value="{{inputParam.inpuentertValue}}" focus="{{inputParam.focus}}" adjust-position="{{false}}"></input> <image catchtap="sendMessageOperation" class="danmu-btn" src="{{assets}}images/live-index-danmu-send.png"></image> </view>
checkColor(e) { let colorStatusList = this.data.colorStatusList; let index = e.currentTarget.dataset.index; let foncolor = colorStatusList[index].color; let inputParam = this.data.inputParam inputParam.focus = true if (colorStatusList[index].checked == true) { colorStatusList[index].checked = false foncolor = '#09091b' } else { for (let colorIndex in colorStatusList) { colorStatusList[colorIndex].checked = false } colorStatusList[index].checked = true } this.setData({ colorStatusList: colorStatusList, fontcolor: foncolor, inputParam: inputParam }) }, getInputValue(e) { let inputParam = this.data.inputParam; inputParam.inputValue = e.detail.value; this.setData({ inputParam: inputParam }) }, enterMessage(e) { let inputParam = this.data.inputParam; inputParam.colorShow = true, inputParam.focus = true, inputParam.bottom = e.detail.height this.setData({ inputParam: inputParam, }) }, loseColor() { let inputParam = this.data.inputParam; inputParam.colorShow = false; inputParam.focus = false; inputParam.bottom = 0; this.setData({ inputParam: inputParam, }) }, sendMessageOperation(e) { let inputParam = this.data.inputParam; if (inputParam.inputValue != '') { this.socket.emit('message', inputParam.inputValue, this.data.fontcolor); app.api.send_message(this.data.liveId, this.data.fontcolor, inputParam.inputValue); inputParam.inputValue = ''; inputParam.colorShow = false inputParam.focus = false inputParam.bottom = 0 this.setData({ inputParam: inputParam, }) console.log("sendMessageOperation") } else { inputParam.inputValue = ''; inputParam.colorShow = false inputParam.focus = false this.setData({ inputParam: inputParam, }) } }
至于說(shuō)上面的catchtap則很好理解了,當(dāng)我們要點(diǎn)擊任意處導(dǎo)致失去焦點(diǎn)時(shí),必定要在外層綁定bindtap事件,那么此處就需要使用catchtap阻止事件的冒泡。
值得一提的是,微信小程序也提供了一個(gè)wx.onKeyboardHeightChange(function callback)
方法來(lái)監(jiān)聽(tīng)鍵盤(pán)的高度變化,但是親測(cè)這個(gè)方法并沒(méi)有很好用,嘗試了一下就棄之不用了。
websocket使用
我們都知道 HTTP 協(xié)議有一個(gè)缺陷:通信只能由客戶端發(fā)起。那么在這種情況下,如果服務(wù)器有連續(xù)的狀態(tài)變化,客戶端要獲知就非常麻煩。我們只能使用"輪詢",最典型的應(yīng)用場(chǎng)景就是聊天室了。
輪詢的效率低,非常浪費(fèi)資源。因此,工程師們一直在思考,有沒(méi)有更好的方法。WebSocket 就是這樣發(fā)明的。
那么如何在微信小程序中使用websocket呢?先來(lái)看看本次的需求:
在觀看直播的過(guò)程當(dāng)中,用戶會(huì)進(jìn)行聊天,服務(wù)器要將用戶的彈幕信息推送到每個(gè)用戶的手機(jī)端。
weapp.socket.io
weapp.socket.io是基于socket.io的微信程序環(huán)境中的客戶端,以及socket.io-client瀏覽器版本的完整功能。
安裝方式:
npm i weapp.socket.io
簡(jiǎn)單使用的代碼:
<template> <view class="content"> <button type="primary" @click="send">發(fā)送消息</button> </view></template>
// 引入 weapp.socket.io.js import io from '@/util/weapp.socket.io.js';export default { data() { return {}; }, onLoad() { // 建立一個(gè)socket連接 const socket =(this.socket = io('https://socket-io-chat.now.sh/')); /** * 客戶端socket.on()監(jiān)聽(tīng)的事件: */ // 連接成功 socket.on('connect', () => { console.log('連接成功'); }); // 正在連接 socket.on('connecting', d => { console.log('正在連接', d); }); // 連接錯(cuò)誤 socket.on('connect_error', d => { console.log('連接失敗', d); }); // 連接超時(shí) socket.on('connect_timeout', d => { console.log('連接超時(shí)', d); }); // 斷開(kāi)連接 socket.on('disconnect', reason => { console.log('斷開(kāi)連接', reason); }); // 重新連接 socket.on('reconnect', attemptNumber => { console.log('成功重連', attemptNumber); }); // 連接失敗 socket.on('reconnect_failed', () => { console.log('重連失敗'); }); // 嘗試重新連接 socket.on('reconnect_attempt', () => { console.log('嘗試重新重連'); }); // 錯(cuò)誤發(fā)生,并且無(wú)法被其他事件類型所處理 socket.on('error', err => { console.log('錯(cuò)誤發(fā)生,并且無(wú)法被其他事件類型所處理', err); }); // 加入聊天室 socket.on('login', d => { console.log(`您已加入聊天室,當(dāng)前共有 ${d.numUsers} 人`); }); // 接受到新消息 socket.on('new message', d => { console.log('new message',d); }); // 有人加入聊天室 socket.on('user joined', d => { console.log(`${d.username} 來(lái)了,當(dāng)前共有 ${d.numUsers} 人`); }); // 有人離開(kāi)聊天室 socket.on('user left', d => { console.log(`${d.username} 離開(kāi)了,當(dāng)前共有 ${d.numUsers} 人`); }); }, methods: { send(){ // 發(fā)送消息 this.socket.emit('new message', '發(fā)送消息') } }};
小程序當(dāng)中的使用
initWebSocket(live) { if(this.socket) { this.socket.disconnect(); this.socket = null; } if(live.step != '直播中') { return this.setData({ liveTipTime: live.start_time }); } const username = this.data.username; const timestamp = Math.floor(Date.now()/1000/60/10); const token = `gz.${timestamp}.${username}`; const socket = io( `${socketHost}/chat?id=${this.data.liveId}&token=${token}`); socket.on('connect', () => { this.setData({ socketError: '' }); console.log('connection created.') }); socket.on('join', user => { let { danmulist } = this.data; danmulist.push({ nickName: user, content: '加入了房間', system: true }); this.setData({ danmulist, onlineUserCount: this.data.onlineUserCount + 1 }); }); socket.on('message', msg => { let { danmulist } = this.data; danmulist.push({ nickName: msg.user, content: msg.content, color: msg.color || '#fff' }); this.videoContext.sendDanmu({ text: msg.content, color: msg.color || '#fff' }) this.setData({ danmulist }); console.log(msg) }); socket.on('alluser', users => { //console.log('alluser', users); this.setData({ onlineUserCount: users.length }); }); socket.on('logout', users => { console.log('alluser', users) this.setData({ onlineUserCount: this.data.onlineUserCount - 1 }); }); socket.on('getAlluser', ({ type, users }) => { console.log('getAlluser', type, users); if(this.data.isAdmin) { app.api.lottery_start(type, users).then(x=>{ if(!x.length) { return wx.showModal({ content: '當(dāng)前已無(wú)符合條件的中獎(jiǎng)候選名單,請(qǐng)稍后再試' }); } wx.showToast({ title: '抽獎(jiǎng)成功' }); this.setData({ activeTab: 0 }); this.socket.emit('lotteryStart', type); this.lottery_result_summary(); }).catch(e=>{ wx.showModal({ title: '抽獎(jiǎng)失敗: '+e, showCancel: false }); }); } }); socket.on('setScore', score => { const liveIndex = this.data.swiperList.findIndex(x=>x.id == this.data.liveId); if(this.data.swiperList[liveIndex]) { this.setData({ [`swiperList[${liveIndex}].score`]: score }); } console.log('setScore', score) }); socket.on('lotteryStart', type => { console.log('lotteryStart', type) if(this.data.lotteryStatus == 1) { app.api.lottery_result(type).then(lotteryResult=>{ this.setData({ lotteryStatus: 2, lotteryResult, time2: 10 }); this.countdown(); }); } }); socket.on('setliveStep', step => { console.log('setliveStep', step) }); socket.on('error', e => { console.error('socket error', e); wx.showToast({ title: '連接彈幕服務(wù)失敗', icon: 'none' }); this.setData({ socketError: e + '' }); }) this.socket = socket; this.setData({ liveTipTime: '' }); },
想了解