注意事项
使用页面设置
- 每个元素需要设置id, 便于后面进行取值(单项底边界)
- 如果是有tabBar的主页面, 需要传参告诉组件, 进行tabBar的隐藏设置(不隐藏的话textarea的fixed定位会将tabBar的距离顶出来.....说不清楚了, 请看图片😂)
组件
- 页面滚动容器的paddingBottom需要通过triggerEvent带着数值传出来
- textarea中webkit-scrollbar的消失, 需要将样式写在app.wxss中(组件的wxss中只能使用类名) 报错
- wx.pageScroll可以在组件中使用
代码
组件wxml ⬇️
<view class="comment-view" id="njxCommentTextarea" style="bottom: {{textBottom}}px;">
<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="140" show-confirm-bar="{{false}}" confirm-type="send" bindkeyboardheightchange="getKeyBoardHeight" bindblur="onBlur" bindinput="onInput" bindconfirm="onSend"></textarea>
<view class="njx_button" wx:if="{{!isIos}}" catchtap="onSend">发送</view>
</view>
组件wxss ⬇️
@import "/components/common.wxss";
.comment-view {
width: 100vw;
padding: 6px 12px;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
background: #ededf4;
position: fixed;
}
.textarea {
width: 100%;
background: #fff;
border-radius: 4px;
}
.textarea-placeholder {
color: #666666;
}
.njx_button {
min-width: 54px!important;
}
组件js ⬇️
Component({
properties: {
inputValue: String,
// 滚动容器id(必传参): 用来获取当前scrollTop
scrollContainerId: {
required: true,
type: String,
value: "",
},
// 当前点击元素的id(必传参)
currentElId: {
required: true,
type: String,
value: "",
},
placeholder: String,
// 是否是有tabBar的页面: 如果有, 需要在输入框弹出且定位的过程中将tabBar隐藏
hasTabBar: {
type: Boolean,
value: false,
},
},
data: {
isIos: false,
focus: false,
initPageHeight: false,
pageHeight: 0,
initKeyBoardHeight: false,
keyBoardHeight: 0,
initTextHeight: false,
textHeight: 0,
textBottom: -1000,
elBottom: 0,
beforeScrollTop: 0,
},
methods: {
async getSystem() {
const {
system,
} = wx.getSystemInfoSync();
this.setData({
isIos: system.includes('iOS'),
})
},
getDomInfo({
elId,
isComponent
}) {
// createSelectorQuery用在组件中的元素时用this, 页面中的元素时使用wx
let _this = isComponent ? this : wx;
return new Promise((resolve) => {
_this.createSelectorQuery().select('#' + elId).boundingClientRect().exec(function (res) {
resolve(res[0])
})
})
},
getKeyBoardHeight(e) {
const {
height: keyBoardHeight,
} = e.detail;
if (!this.data.initKeyBoardHeight && keyBoardHeight !== 0) {
this.setData({
keyBoardHeight,
initKeyBoardHeight: true,
})
this.fixTextarea();
}
},
onPageScroll({
scrollTop,
paddingBottom
}) {
this.triggerEvent('padpage', {
paddingBottom,
})
wx.pageScrollTo({
scrollTop,
})
},
async setEl(elId) {
wx.hideTabBar();
// 获取页面高度
if(!this.data.initPageHeight) {
const {screenHeight, windowHeight} = wx.getSystemInfoSync();
this.setData({
pageHeight: this.data.hasTabBar ? screenHeight : windowHeight
})
}
// 获取元素底边距
const {
bottom: elBottom
} = await this.getDomInfo({
elId
});
if (!this.data.initTextHeight) {
const {
height: textHeight
} = await this.getDomInfo({
elId: 'njxCommentTextarea',
isComponent: true
});
this.setData({
textHeight,
initTextHeight: true,
})
}
// 聚焦
this.setData({
focus: true,
elBottom,
})
this.data.keyBoardHeight && this.fixTextarea();
},
fixTextarea() {
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 {
wx.createSelectorQuery().select('#' + this.data.scrollContainerId).boundingClientRect().selectViewport().scrollOffset().exec(res => {
const beforeScrollTop = res[1].scrollTop;
fixPosition({
value: this.data.keyBoardHeight,
beforeScrollTop
});
const scrollTop = beforeScrollTop + this.data.keyBoardHeight - textBottom;
this.onPageScroll({
paddingBottom: this.data.textHeight + this.data.keyBoardHeight,
scrollTop,
});
})
}
},
onBlur() {
this.onPageScroll({
scrollTop: this.data.beforeScrollTop,
paddingBottom: 0
})
this.data.hasTabBar && wx.showTabBar();
this.setData({
textBottom: -this.data.textHeight,
inputValue: "",
})
},
onInput(e) {
const inputValue = e.detail.value;
this.setData({
inputValue,
})
},
onSend(e) {
const {
value
} = e.detail;
this.triggerEvent('sendvalue', {
value: value || this.data.inputValue,
})
},
},
observers: {
currentElId(id) {
id && this.data.textBottom < 0 && this.setEl(id);
},
},
lifetimes: {
attached() {
this.getSystem();
}
}
})
使用页面代码
wxml ⬇️
<view class="njx_container h_100">
<view id="scrollNjx" style="padding-bottom: {{paddingBottom}}px;">
<view class="njx_card" wx:for="{{list}}" wx:key="id" id="id-{{item.id}}" bindtap="toCommentComponent" data-item="{{item}}">
{{item.id}}
</view>
</view>
</view>
<njx-comment-input scrollContainerId="scrollNjx" currentElId="{{currentElId}}" placeholder="{{placeholder}}" hasTabBar bindsendvalue="onSend" bindpadpage="onPadPage"></njx-comment-input>
js ⬇️
let list = [];
for (let i = 0; i <= 20; i++) {
list.push({
id: i
});
}
Page({
data: {
list,
placeholder: "",
paddingBottom: 20,
currentElId: "",
},
toCommentComponent(e) {
const {item} = e.currentTarget.dataset;
this.setData({
currentElId: 'id-' + item.id,
placeholder: '我的评论ID是 ---- ' + item.id,
})
},
onSend(e) {
const {value} = e.detail;
console.log(value, 'VALUE ~~~~~~~~~~~~~~~');
},
onPadPage(e) {
const {paddingBottom} = e.detail;
this.setData({
paddingBottom,
})
},
onLoad(options) {
},
})
最后记得在json中那啥usingComponents呀~~
这篇注释有点少, 都在之前那篇里, 有变化的才写了新的嘿嘿
tada~~~一个评论区的输入框组件就完成啦💃
实际使用时发现了新的问题, 这里的代码懒得改了😂
最好将输入框容器的id也设置为动态, 从使用页面传进来.
网友评论