Messages Component
Messages React component represents Messages component.
Messages Components
There are following components included:
**Messages**
/**F7Messages**
- main Messages container**Message**
/**F7Message**
- single message element**MessagesTitle**
/**F7MessagesTitle**
- single messages title element
Messages Properties
Prop | Type | Default | Description |
---|---|---|---|
<Messages> properties | |||
init | boolean | true | Initializes Messages component |
newMessagesFirst | boolean | false | Enable if you want to use new messages on top, instead of having them on bottom |
scrollMessages | boolean | true | Enable/disable messages autoscrolling when adding new message |
scrollMessagesOnEdge | boolean | true | If enabled then messages autoscrolling will happen only when user is on top/bottom of the messages view |
<Message> properties | |||
type | string | sent | Message type: sent (default) or received |
text | string | Message text | |
avatar | string | Message user’s avatar URL | |
name | string | Message user’s name | |
image | string | Message image URL | |
header | string | Message header | |
footer | string | Message footer | |
textHeader | string | Message text header | |
textFooter | string | Message text footer | |
first | boolean | false | Defines that the message is first in the conversation |
last | boolean | false | Defines that the message is last in the conversation |
tail | boolean | false | Defines that the message has visual “tail”. Usually last message in conversation |
sameName | boolean | false | Defines that this message sender name is the same as on previous message |
sameHeader | boolean | false | Defines that this message header text is the same as on previous message |
sameFooter | boolean | false | Defines that this message footer text is the same as on previous message |
sameAvatar | boolean | false | Defines that this message user’s avatar URL is the same as on previous message |
Messages Methods
<Messages> methods | |
---|---|
.scroll(duration, position); | Scroll messages to top/bottom depending on newMessagesFirst parameter
|
.showTyping(message); | Show typing message indicator
|
.hideTyping() | Hide typing message indicator |
Messages Events
Event | Description |
---|---|
<Message> events | |
click | Event will be triggered when user clicks on message bubble |
clickName | Event will be triggered when user clicks on message user’s name |
clickText | Event will be triggered when user clicks on message text |
clickAvatar | Event will be triggered when user clicks on message user’s avatar |
clickHeader | Event will be triggered when user clicks on message header |
clickFooter | Event will be triggered when user clicks on message footer |
clickBubble | Event will be triggered when user clicks on message bubble |
Messages Slots
Single message React component (<Message>
) has additional slots for custom elements:
**default**
- element will be inserted as a child of<div class="message-bubble">
element in the end**start**
- element will be inserted in the beginning and direct child of main message element<div class="message">
**end**
- element will be inserted in the end and direct child of main message element<div class="message">
**content-start**
- element will be inserted in the beginning and direct child of the<div class="message-content">
element**content-end**
- element will be inserted in the end and direct child of the<div class="message-content">
element**bubble-start**
- element will be inserted in the beginning and direct child of the<div class="message-bubble">
element**bubble-end**
- element will be inserted in the end and direct child of the<div class="message-bubble">
element. Same as**default**
slot
The following slots can be used inside of single message instead of same props if you need to pass there more complext layout:
**header**
- element will be inserted in message header**footer**
- element will be inserted in message footer**text**
- element will be inserted in message text**name**
- element will be inserted in message name**image**
- element will be inserted in message image (supposed tp be an<img>
element)**text-header**
- element will be inserted in message text header**text-footer**
- element will be inserted in message text footer
<Message
type="sent"
text="Hello World"
name="John Doe"
avatar="path/to/image.jpg"
>
<div slot="start">Start</div>
<div slot="end">End</div>
<div slot="content-start">Content Start</div>
<div slot="content-end">Content End</div>
<div slot="bubble-start">Bubble Start</div>
<div slot="bubble-end">Bubble End</div>
</Message>
{/* Renders to: */}
<div class="message message-sent">
<div>Start</div>
<div class="message-avatar" style="background-image: url(path/to/image.jpg);"></div>
<div class="message-content">
<div>Content Start</div>
<div class="message-name">John Doe</div>
<div class="message-bubble">
<div>Bubble Start</div>
<div class="message-text">Hello World</div>
<div>Bubble End</div>
</div>
<div>Content End</div>
</div>
<div>End</div>
</div>
Access To Messages Instance
If you use automatic initalization to init Messages (with init={true}
prop) and need to use Messages API you can access its initialized instance by accessing **.f7Messages**
component’s property.
Examples
Here is how the full example of Messages page where it can be used together with Messagebar:
export default class extends React.Component {
constructor(props) {
super(props);
this.state = {
attachments: [],
sheetVisible: false,
typingMessage: null,
messagesData: [
{
type: 'sent',
text: 'Hi, Kate',
},
{
type: 'sent',
text: 'How are you?',
},
{
name: 'Kate',
type: 'received',
text: 'Hi, I am good!',
avatar: 'http://lorempixel.com/100/100/people/9',
},
{
name: 'Blue Ninja',
type: 'received',
text: 'Hi there, I am also fine, thanks! And how are you?',
avatar: 'http://lorempixel.com/100/100/people/7',
},
{
type: 'sent',
text: 'Hey, Blue Ninja! Glad to see you ;)',
},
{
type: 'sent',
text: 'Hey, look, cutest kitten ever!',
},
{
type: 'sent',
image: 'http://lorempixel.com/200/260/cats/4/',
},
{
name: 'Kate',
type: 'received',
text: 'Nice!',
avatar: 'http://lorempixel.com/100/100/people/9',
},
{
name: 'Kate',
type: 'received',
text: 'Like it very much!',
avatar: 'http://lorempixel.com/100/100/people/9',
},
{
name: 'Blue Ninja',
type: 'received',
text: 'Awesome!',
avatar: 'http://lorempixel.com/100/100/people/7',
},
],
images: [
'http://lorempixel.com/300/300/cats/1/',
'http://lorempixel.com/200/300/cats/2/',
'http://lorempixel.com/400/300/cats/3/',
'http://lorempixel.com/300/150/cats/4/',
'http://lorempixel.com/150/300/cats/5/',
'http://lorempixel.com/300/300/cats/6/',
'http://lorempixel.com/300/300/cats/7/',
'http://lorempixel.com/200/300/cats/8/',
'http://lorempixel.com/400/300/cats/9/',
'http://lorempixel.com/300/150/cats/10/',
],
people: [
{
name: 'Kate Johnson',
avatar: 'http://lorempixel.com/100/100/people/9',
},
{
name: 'Blue Ninja',
avatar: 'http://lorempixel.com/100/100/people/7',
},
],
answers: [
'Yes!',
'No',
'Hm...',
'I am not sure',
'And what about you?',
'May be ;)',
'Lorem ipsum dolor sit amet, consectetur',
'What?',
'Are you sure?',
'Of course',
'Need to think about it',
'Amazing!!!',
],
responseInProgress: false,
}
}
render() {
return (
<Page>
<Navbar title="Messsages"></Navbar>
<Messagebar
placeholder={this.placeholder}
ref={(el) => {this.messagebarComponent = el}}
attachmentsVisible={this.attachmentsVisible}
sheetVisible={this.state.sheetVisible}
>
<Link
iconIos="f7:camera_fill"
iconMd="material:camera_alt"
slot="inner-start"
onClick={() => {this.setState({sheetVisible: !this.state.sheetVisible})}}
></Link>
<Link
iconIos="f7:arrow_up_fill"
iconMd="material:send"
slot="inner-end"
onClick={this.sendMessage.bind(this)}
></Link>
<MessagebarAttachments>
{this.state.attachments.map((image, index) => (
<MessagebarAttachment
key={index}
image={image}
onAttachmentDelete={() => this.deleteAttachment(image)}
></MessagebarAttachment>
))}
</MessagebarAttachments>
<MessagebarSheet>
{this.state.images.map((image, index) => (
<MessagebarSheetImage
key={index}
image={image}
checked={this.state.attachments.indexOf(image) >= 0}
onChange={this.handleAttachment.bind(this)}
></MessagebarSheetImage>
))}
</MessagebarSheet>
</Messagebar>
<Messages ref={(el) => {this.messagesComponent = el}}>
<MessagesTitle><b>Sunday, Feb 9,</b> 12:58</MessagesTitle>
{this.state.messagesData.map((message, index) => (
<Message
key={index}
type={message.type}
image={message.image}
name={message.name}
avatar={message.avatar}
first={this.isFirstMessage(message, index)}
last={this.isLastMessage(message, index)}
tail={this.isTailMessage(message, index)}
>
{message.text && (
<span slot="text" dangerouslySetInnerHTML={{__html: message.text}} />
)}
</Message>
))}
{this.state.typingMessage && (
<Message
type="received"
typing={true}
first={true}
last={true}
tail={true}
header={`${this.state.typingMessage.name} is typing`}
avatar={this.state.typingMessage.avatar}
></Message>
)}
</Messages>
</Page>
)
}
get attachmentsVisible() {
const self = this;
return self.state.attachments.length > 0;
}
get placeholder() {
const self = this;
return self.state.attachments.length > 0 ? 'Add comment or Send' : 'Message';
}
componentDidMount() {
const self = this;
self.$f7ready(() => {
self.messagebar = self.messagebarComponent.f7Messagebar;
self.messages = self.messagesComponent.f7Messages;
});
}
isFirstMessage(message, index) {
const self = this;
const previousMessage = self.state.messagesData[index - 1];
if (message.isTitle) return false;
if (!previousMessage || previousMessage.type !== message.type || previousMessage.name !== message.name) return true;
return false;
}
isLastMessage(message, index) {
const self = this;
const nextMessage = self.state.messagesData[index + 1];
if (message.isTitle) return false;
if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
return false;
}
isTailMessage(message, index) {
const self = this;
const nextMessage = self.state.messagesData[index + 1];
if (message.isTitle) return false;
if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
return false;
}
deleteAttachment(image) {
const self = this;
const attachments = self.state.attachments;
const index = attachments.indexOf(image);
attachments.splice(index, 1);
self.setState({ attachments });
}
handleAttachment(e) {
const self = this;
const attachments = self.state.attachments;
const index = self.$$(e.target).parents('label.checkbox').index();
const image = self.state.images[index];
if (e.target.checked) {
// Add to attachments
attachments.unshift(image);
} else {
// Remove from attachments
attachments.splice(attachments.indexOf(image), 1);
}
self.setState({ attachments });
}
sendMessage() {
const self = this;
const text = self.messagebar.getValue().replace(/\n/g, '<br>').trim();
const messagesToSend = [];
self.state.attachments.forEach((attachment) => {
messagesToSend.push({
image: attachment,
});
});
if (text.trim().length) {
messagesToSend.push({
text,
});
}
if (messagesToSend.length === 0) {
return;
}
self.setState({
// Reset attachments
attachments: [],
// Hide sheet
sheetVisible: false,
// Send message
messagesData: [...self.state.messagesData, ...messagesToSend],
});
self.messagebar.clear();
// Focus area
if (text.length) self.messagebar.focus();
// Mock response
if (self.state.responseInProgress) return;
self.setState({
responseInProgress: true,
})
setTimeout(() => {
const answer = self.state.answers[Math.floor(Math.random() * self.state.answers.length)];
const person = self.state.people[Math.floor(Math.random() * self.state.people.length)];
self.setState({
typingMessage: {
name: person.name,
avatar: person.avatar,
},
});
setTimeout(() => {
self.setState({
messagesData: [...self.state.messagesData, {
text: answer,
type: 'received',
name: person.name,
avatar: person.avatar,
}],
typingMessage: null,
responseInProgress: false,
});
}, 4000);
}, 1000);
}
};
当前内容版权归 Framework7 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 Framework7 .