首先,我们先写一下大概的结构和样式,我使用的是taro框架进下小程序的开发,原生或者其他框架也可以参考,没有太大的出入。
.js
componentWillMount(){
let list = []
for (let index = 0; index < 10; index++) {
list.push(index)
}
this.setState({list})
}
handleMessageSubmit(){
}
render() {
let { messageContent, list } = this.state;
return (
<View className='im-page'>
<ScrollView scrollY className='im-page__list'>
{
list.map(item=>{
return <View key={item} className='im-page__item'>
内容:{item}
<Image src='https://pic3.zhimg.com/80/v2-d18fc238468e504504dc6a7ee5f75a12_hd.jpg'></Image>
</View>
})
}
</ScrollView>
<View className='im-page__tool'>
<Input
placeholder='对 Ta 发送消息'
placeholderStyle={{ color: '#cccccc' }}
value={messageContent}
confirmType='send'
onConfirm={this.handleMessageSubmit.bind(this)}
/>
<AtIcon prefixClass='icon' value='x_line' color='#333333' size='25' />
</View>
</View>
);
}
.less
.im-page__tool {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background: #ffffff;
border-top: 1px solid #ececec;
display: flex;
align-items: center;
input {
flex: 1;
margin: 14px 0px 14px 24px;
padding: 15px 24px;
background: #f8f8f8;
border-radius: 36px;
font-size: 28px;
}
at-icon{
padding: 24px;
transform: rotate(45deg);
}
}
接下来考虑底部输入栏,我们想要的效果是输入框聚焦时,底部的输入框上推至键盘上方,微信提供了adjustPosition这个属性,但是开启之后整个页面都会上推,体验非常不好。所以我们采取另一个方法onKeyboardHeightChange,获取到键盘的高度,动态的计算工具栏距离底部的距离。
修改后的代码片段
handleBlur() {
this.setState({
inputBottom: 0
});
}
setInputBottom(e) {
let keyHeight = e.detail.height;
this.setState(
(prev) => {
if (keyHeight !== prev.inputBottom) {
return {
inputBottom: keyHeight + 'px',
};
}
}
);
}
<View className='im-page__tool' style={{ bottom: inputBottom}}>
<Input
placeholder='对 Ta 发送消息'
placeholderStyle={{ color: '#cccccc' }}
value={messageContent}
confirmHold
adjustPosition={false}
confirmType='send'
onKeyboardHeightChange={this.setInputBottom.bind(this)}
onFocus={this.setInputBottom.bind(this)}
onConfirm={this.handleMessageSubmit.bind(this)}
onBlur={this.handleBlur.bind(this)}
/>
<AtIcon prefixClass='icon' value='x_line' color='#333333' size='25' />
</View>
需要注意一点,部分安卓机型在第一次onKeyboardHeightChange触发的时候获取到的高度会不正确,所以可以在onFocus时也添加一个设置inputBottom的计算。
接下来是模拟微信聊天时页面自动滚动到最新聊天位置的效果,这个很简答,可以使用scrollView的 scrollToView 或 scrollTop,在数据加载完成和输入框聚焦时设置滚动到底部就可以了。 但是这里我们还是直接使用设置scrollTop的方法
代码片段如下
constructor() {
super(...arguments);
this.state = {
messageContent: '',
list: [],
inputBottom: 0,
listScrollTop: 10000
};
}
handleMessageSubmit(e){
this.setState(prev=>{
let list = prev.list
list.push(e.detail.value)
return {
list,
messageContent: '',
listScrollTop: list.length * 10000,
}
})
}
render() {
let { messageContent, list, inputBottom, listScrollTop } = this.state;
return (
<View className='im-page'>
<ScrollView scrollY scrollTop={listScrollTop} className='im-page__list'>
{
list.map(item=>{
return <View key={item} className='im-page__item'>
内容:{item}
<Image src='https://pic3.zhimg.com/80/v2-d18fc238468e504504dc6a7ee5f75a12_hd.jpg'></Image>
</View>
})
}
</ScrollView>
<View className='im-page__tool' style={{ bottom: inputBottom}}>
<Input
placeholder='对 Ta 发送消息'
placeholderStyle={{ color: '#cccccc' }}
value={messageContent}
confirmHold
adjustPosition={false}
confirmType='send'
onKeyboardHeightChange={this.setInputBottom.bind(this)}
onFocus={this.setInputBottom.bind(this)}
onConfirm={this.handleMessageSubmit.bind(this)}
onBlur={this.handleBlur.bind(this)}
/>
<AtIcon prefixClass='icon' value='x_line' color='#333333' size='25' />
</View>
</View>
);
}
最后一个比较麻烦的点就是下拉加载更多了,要实现这个功能刚开始思路比较明确,就是在加载完成后滚动到目标位置,微信也提供了相关的api,但是在真机上就是卡顿,闪屏,非常不流畅,后来参考社区内一个回答的思路,终于可以比较流畅的实现这个功能了。
思路: 1.获取下一页数据后,将数据赋值到一个新的变量newList中。 2.在滚动区域外遍历newList,保证每个item的高度和scrollView中的item高度是一样的,设置newList列表为绝对定位,隐藏显示 3.获取newList的列表高度newListHeight。 4.在列表滚动结束后将newList 合并到 list 上,并让列表滚动至 newListHeight 的位置。
其中scrollView的滚动结束可以利用定时器来模拟实现 代码如下:
onListScroll() {
if (this.timeFun) {
clearTimeout(this.timeFun);
this.timeFun = null;
}
let vm = this;
this.timeFun = setTimeout(function() {
console.log(‘滚动结束)
}, 300);
}