Install & Download:
Description:
The vue-quick-chat component allows you to insert a custom live chat on web applications.
Key Features:
- Handle on type event and on message submit
- Chat with multiple participants
- Support for async actions like message uploaded status
- Send images
- Support for profile pictures
How to use it:
1. Import the component and stylesheet into your project.
import { Chat } from 'vue-quick-chat'
import '/path/to/vue-quick-chat.css';2. Add the chat component to your template.
<template>
<div id="app">
<div class="content">
<div class="chat-container">
<Chat v-if="visible"
:participants="participants"
:myself="myself"
:messages="messages"
:chat-title="chatTitle"
:placeholder="placeholder"
:colors="colors"
:border-style="borderStyle"
:hide-close-button="hideCloseButton"
:close-button-icon-size="closeButtonIconSize"
:submit-icon-size="submitIconSize"
:submit-image-icon-size="submitImageIconSize"
:load-more-messages="toLoad.length > 0 ? loadMoreMessages : null"
:async-mode="asyncMode"
:scroll-bottom="scrollBottom"
:display-header="true"
:send-images="true"
:profile-picture-config="profilePictureConfig"
@onImageClicked="onImageClicked"
@onImageSelected="onImageSelected"
@onMessageSubmit="onMessageSubmit"
@onType="onType"
@onClose="onClose('param value')"/>
</div>
<div class="external-controller">
<div class="controller-btn-container">
<button class="btn-message" @click="addMessage">Add menssage</button>
<button class="btn-participant" @click="addParticipant">Add participant</button>
<button class="btn-participant" @click="changeAllProps">Change All Props</button>
</div>
<div class="message-list">
<ol>
<li v-for="(message, index) in messages" :key="index">
{{message.content}}
</li>
</ol>
</div>
</div>
</div>
</div>
</template>3. Register the component and initialize your data as follows:
export default {
name: 'app',
components: {
Chat
},
data() {
return {
visible: true,
participants: [
{
name: 'Arnaldo',
id: 1,
profilePicture: 'https://upload.wikimedia.org/wikipedia/en/thumb/a/a1/NafSadh_Profile.jpg/768px-NafSadh_Profile.jpg'
},
{
name: 'Adam',
id: 2,
profilePicture: 'https://lh3.googleusercontent.com/-G1d4-a7d_TY/AAAAAAAAAAI/AAAAAAAAAAA/AAKWJJPez_wX5UCJztzEUeCxOd7HBK7-jA.CMID/s83-c/photo.jpg'
}
],
myself: {
name: 'John Doe',
id: 3,
profilePicture: 'https://lh3.googleusercontent.com/-G1d4-a7d_TY/AAAAAAAAAAI/AAAAAAAAAAA/AAKWJJPez_wX5UCJztzEUeCxOd7HBK7-jA.CMID/s83-c/photo.jpg'
},
messages: [
{
content: "Really?! I don't care! Haha",
participantId: 1,
timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
uploaded: true,
viewed: true,
type: 'text'
},
{
content: "Really?! I don't care! Haha",
participantId: 1,
timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
uploaded: true,
viewed: true,
type: 'text'
},
{
content: "Really?! I don't care! Haha",
participantId: 1,
timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
uploaded: true,
viewed: true,
type: 'text'
},
{
content: "Hey, Jhon Doe! How are you today",
participantId: 1,
timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
uploaded: true,
viewed: true,
type: 'text'
},
{
content: "Hey, Adam! I'm felling really fine this evening.",
participantId: 3,
timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
uploaded: true,
viewed: true,
type: 'text'
},
{
content: "Really?! I don't care! Haha",
participantId: 1,
timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
uploaded: true,
viewed: true,
type: 'text'
},
],
chatTitle: 'My chat title',
placeholder: 'send your message',
colors: {
header: {
bg: '#d30303',
text: '#fff'
},
message: {
myself: {
bg: '#fff',
text: '#525252'
},
others: {
bg: '#fb4141',
text: '#fff'
},
messagesDisplay: {
//bg: 'rgb(247, 243, 243)',
//bg: '#f7f3f3'
bg: '#f7f3f3'
}
},
submitIcon: '#b91010',
submitImageIcon: '#b91010',
},
borderStyle: {
topLeft: "10px",
topRight: "10px",
bottomLeft: "10px",
bottomRight: "10px",
},
hideCloseButton: false,
submitIconSize: 24,
submitImageIconSize: 24,
closeButtonIconSize: "20px",
asyncMode: true,
toLoad: [
{
content: 'Hey, John Doe! How are you today?',
participantId: 2,
timestamp: { year: 2016, month: 3, day: 5, hour: 10, minute: 10, second: 3, millisecond: 123 },
uploaded: true,
viewed: true
},
{
content: "Hey, Adam! I'm feeling really fine this evening.",
participantId: 3,
timestamp: { year: 2016, month: 1, day: 5, hour: 19, minute: 10, second: 3, millisecond:123 },
uploaded: true,
viewed: true
},
],
scrollBottom: {
messageSent: true,
messageReceived: false
},
profilePictureConfig: {
others: true,
myself: true,
styles: {
width: '30px',
height: '30px',
borderRadius: '50%'
}
}
}
},
methods: {
// eslint-disable-next-line
onType: function (e) {
// eslint-disable-next-line
console.log('typing');
},
loadMoreMessages(resolve) {
setTimeout(() => {
resolve(this.toLoad);
//Make sure the loaded messages are also added to our local messages copy or they will be lost
this.messages.unshift(...this.toLoad);
this.toLoad = [];
}, 1000);
},
onMessageSubmit(message) {
/*
* example simulating an upload callback.
* It's important to notice that even when your message wasn't send
* yet to the server you have to add the message into the array
*/
this.messages.push(message);
/*
* you can update message state after the server response
*/
// timeout simulating the request
setTimeout(() => {
message.uploaded = true
message.viewed = true
}, 2000)
},
onClose(param) {
console.log(param)
this.visible = false;
},
addMessage() {
/* this.messages.push(
{
content: "Update state",
// myself: false,
participantId: 1,
timestamp: {year: 2014, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
uploaded: true,
viewed: true
}
) */
this.messages.push(
{
type: 'image',
preview: null,
src: 'https://149364066.v2.pressablecdn.com/wp-content/uploads/2017/03/vue.jpg',
content: 'image',
participantId: 1,
timestamp: {year: 2014, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
uploaded: true,
viewed: false
}
)
},
addParticipant() {
let participant = {
name: 'Karl',
id: 4
};
this.participants.push(participant)
},
changeAllProps() {
this.myself = {
name: 'I Qanah',
id: 3
};
this.participants = [
{
name: 'Ibrahim',
id: 5
},
{
name: 'Ana',
id: 6
}
];
this.messages = [
{
content: "Really?! I don't care! Haha",
participantId: 5,
timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
uploaded: true,
viewed: true
},
{
content: "Really?! I don't care! Haha",
participantId: 6,
timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
uploaded: true,
viewed: true
},
{
content: "Really?! I don't care! Haha",
participantId: 3,
timestamp: {year: 2012, month: 3, day: 5, hour: 20, minute: 10, second: 3, millisecond: 123},
uploaded: true,
viewed: true
}
];
this.toLoad = [
{
content: 'Hey, John Doe! How are you today?',
participantId: 6,
timestamp: { year: 2016, month: 3, day: 5, hour: 10, minute: 10, second: 3, millisecond: 123 },
uploaded: true,
viewed: true
},
{
content: "Hey, Adam! I'm feeling really fine this evening.",
participantId: 3,
timestamp: { year: 2016, month: 10, day: 5, hour: 19, minute: 10, second: 3, millisecond:123 },
uploaded: true,
viewed: true
},
];
this.chatTitle = 'Change All Participants';
this.placeholder = 'اكتب رسالتك هنا';
},
onImageSelected({file, message}){
let src = 'https://149364066.v2.pressablecdn.com/wp-content/uploads/2017/03/vue.jpg'
this.messages.push(message);
/**
* This timeout simulates a requisition that uploads the image file to the server.
* It's up to you implement the request and deal with the response in order to
* update the message status and the message URL
*/
setTimeout((res) => {
message.uploaded = true
message.src = res.src
}, 3000, {src});
},
onImageClicked(message){
/**
* This is the callback function that is going to be executed when some image is clicked.
* You can add your code here to do whatever you need with the image clicked. A common situation is to display the image clicked in full screen.
*/
console.log('Image clicked', message.src)
}
}
}4. All possible props.
participants: {
type: Array,
required: true
},
messages: {
type: Array,
required: true
},
myself: {
type: Object,
required: true
},
chatTitle: {
type: String,
required: false,
default: ''
},
placeholder: {
type: String,
required: false,
default: 'type your message here'
},
colors: {
type: Object,
required: true
},
borderStyle: {
type: Object,
required: false,
default: () => {
return {
topLeft: "10px",
topRight: "10px",
bottomLeft: "10px",
bottomRight: "10px",
}
}
},
hideCloseButton: {
type: Boolean,
required: false,
default: false
},
submitIconSize: {
type: Number,
required: false,
default: 24
},
submitImageIconSize: {
type: Number,
required: false,
default: 24
},
closeButtonIconSize: {
type: String,
required: false,
default: "15px"
},
asyncMode: {
type: Boolean,
required: false,
default: false
},
loadMoreMessages: {
type: Function,
required: false,
default: null
},
scrollBottom:{
type: Object,
required: false,
default: () => {
return {
messageSent: true,
messageReceived: false
}
}
},
displayHeader: {
type: Boolean,
required: false,
default: true
},
sendImages: {
type: Boolean,
required: false,
default: true
},
profilePictureConfig: {
type: Object,
required: false,
default: () => {
return {
others: true,
myself: false,
styles: {
width: '25px',
height: '25px',
borderRadius: '50%'
}
}
}
}Preview:

Changelog:
v1.2.8 (02/07/2021)
- Fix setMessages
v1.2.7 (01/16/2021)
- Remove package-lock and Fix null timestamps to current time
v1.2.6 (09/12/2020)
- Add verification regex to avoid empty messages
v1.2.5 (08/01/2020)
- Implement acceptImageTypes prop


