效果图
功能
- 类似朋友圈的评论、回复;
- 点击列表项, 弹出textarea进行文字输入;
- iphone点击发送, android点击自定义发送按钮;
这么看来好像没啥好难的咋写了这老长时间啊😂
一些有的没的
- android键盘不支持confirm-type, 需要在页面onLoad时获取到用户手机型号, 作为textarea出现时的判断条件. IOSconfirm-type为send, Android在输入框右侧自定义“发送”按钮;
- textarea的容器原本设置好的定位bottom, 在键盘弹出后, 除非设置在页面底部, 不然会出现输入框文字行数变化就定位不准确的情况. 可以将textarea中的adjust-position属性设置为false, 不让页面随键盘推起而自动上弹页面, 后面我们将自行设置页面上滑.
键盘一定位于页面底部, 为了使输入框和键盘保持贴合, 需要进行一些计算:
- 如果点击的的单项位于页面上方(高于键盘高度), 需要将输入框定位于紧贴键盘高度, 也就是bottom为keyBoardHeight;
-
如果单项位于键盘高度下的位置, 我们需要给外层容器设置paddingBottom, 然后将页面进行上滑. 思考过程见下图
html 代码 ⬇️
<!--views/commentInput/commentInput.wxml-->
<view class="njx_container">
<view style="padding-bottom: {{paddingBottom}}px;" id="scrollNjx">
<view class="njx_card" wx:for="{{list}}" wx:key="id" id="id-{{item.id}}" bindtap="toComment" data-item="{{item}}" style="margin-bottom: {{index === list.length - 1 ? textHeight : 20}}px;">
{{item.id}}
</view>
</view>
</view>
<view class="comment-view" id="njxCommentTextarea" style="bottom: {{textBottom}}px;opacity: {{textOpacity}};">
<textarea class="textarea" style="margin-right: {{isIos ? 0 : 10}}px;padding: {{isIos ? '0 10px' : '4px 10px'}};" value="{{inputValue}}" placeholder="{{placeholder}}" placeholder-class="textarea-placeholder" focus="{{focus}}" auto-height fixed adjust-position="{{false}}" cursor-spacing="10" show-confirm-bar="{{false}}" confirm-type="send" bindkeyboardheightchange="getKeyBoardHeight" bindblur="onBlur"></textarea>
<view class="njx_button" wx:if="{{!isIos}}">发送</view>
</view>
css 代码 ⬇️ (有一些公共样式放在外面了, 懒得粘贴, 不影响功能)
/* views/commentInput/commentInput.wxss */
.njx_card {
margin-right: 3px;
margin-bottom: 20px;
}
.njx_container {
box-sizing: border-box;
height: 100%;
}
.comment-view {
width: 100vw;
padding: 6px 12px;
display: flex;
justify-content: space-between;
align-items: center;
background: #ededf4;
position: fixed;
}
.textarea {
width: 100%;
background: #fff;
border-radius: 4px;
}
.textarea-placeholder {
color: #666666;
}
.njx_button {
min-width: 54px!important;
}
::-webkit-scrollbar {
display: none;
}
js 代码 ⬇️
// views/commentInput/commentInput.js
let list = [];
for (let i = 0; i <= 20; i++) {
list.push({
id: i
});
}
Page({
data: {
list,
placeholder: "",
inputValue: "",
focus: false,
isIos: false,
pageHeight: 0,
initKeyBoardHeight: false,
keyBoardHeight: 0,
initTextHeight: false,
textHeight: 0,
// 输入框弹出, 页面上滑
paddingBottom: 20,
beforeScrollTop: 0,
// 容器
textBottom: -1000,
elBottom: 0,
},
async toComment(e) {
// 输入框定位于页面上时不重复执行该方法
if (this.data.textBottom > 0) return;
if (!this.data.initTextHeight) {
// 获取输入框高度
// (之前这个方法与获取系统信息一起写在getSystemInfo里, iphone在输入框focus之前获取到的高度比focus后多很多, 我想可能是因为textarea是auto-height吧??)
const {
height: textHeight
} = await this.getDomInfo('njxCommentTextarea');
this.setData({
textHeight,
initTextHeight: true,
})
}
// 通过id获取该项元素底边界
let {
id
} = e.currentTarget.dataset.item;
const idName = 'id-' + id;
const {
bottom: elBottom
} = await this.getDomInfo(idName);
const placeholder = '~~~~我是' + e.currentTarget.dataset.item.id;
this.setData({
focus: true,
elBottom,
placeholder,
})
this.fixTextarea();
},
// 获取键盘高度
getKeyBoardHeight(e) {
const {
height: keyBoardHeight,
} = e.detail;
if (!this.data.initKeyBoardHeight && keyBoardHeight !== 0) {
// 一台设备只获取一次即可
this.setData({
keyBoardHeight,
initKeyBoardHeight: true,
})
this.fixTextarea();
}
},
// 输入框定位
fixTextarea() {
// 还未获取到键盘高度时先不执行此方法
if (this.data.keyBoardHeight < 0) return;
// 容器进行计算前定位 = 页面高度 - 元素的底边界 - 输入框高度
let textBottom = this.data.pageHeight - this.data.elBottom - this.data.textHeight;
let fixPosition = ({
value,
beforeScrollTop
}) => {
this.setData({
textBottom: this.data.isIos ? value : value - 1,
beforeScrollTop
})
}
if (textBottom > this.data.keyBoardHeight) {
fixPosition({
value: this.data.isIos ? this.data.keyBoardHeight : this.data.keyBoardHeight - 1,
beforeScrollTop: 0
});
} else {
this.setData({
paddingBottom: this.data.textHeight + this.data.keyBoardHeight
})
this.createSelectorQuery().select('#scrollNjx').boundingClientRect().selectViewport().scrollOffset().exec(res => {
// 当前页面上滑高度
let beforeScrollTop = res[1].scrollTop;
// 需要页面上滑高度 = 请见截图思考过程哈哈哈哈哈哈
const scrollTop = beforeScrollTop + this.data.keyBoardHeight - textBottom;
wx.pageScrollTo({
scrollTop,
success: () => {
fixPosition({
value: this.data.keyBoardHeight,
beforeScrollTop
});
}
})
})
}
},
onBlur() {
// 这个blur方法在iphone7中好像有bug....但就逮到一次, 后面不知道怎么复现....先这样儿
// 先将页面滑动复原
wx.pageScrollTo({
scrollTop: this.data.beforeScrollTop,
})
// 页面底部的内边距复原、输入框定位于页面下、清空输入框内容
this.setData({
paddingBottom: 20,
textBottom: -this.data.textHeight,
inputValue: "",
})
},
// 通过ID获取元素信息
getDomInfo(domName) {
return new Promise((resolve) => {
this.createSelectorQuery().select('#' + domName).boundingClientRect().exec(function (res) {
resolve(res[0])
})
})
},
// 获取textarea容器高度、设备系统
async initPage() {
const {
system,
windowHeight: pageHeight
} = wx.getSystemInfoSync();
this.setData({
isIos: system.includes('iOS'),
pageHeight,
})
},
onLoad(options) {
this.initPage();
}
})
tada~~~一个适用于android和IOS的评论输入框就完成啦~