준비사항
앱을 만들기 전 필요한 라이브러리와 프로젝트 구조를 살펴보고, 데모 소스를 활용하기 위한 필수 설정 변경 사항을 안내합니다.
프로젝트의 폴더 구조
프로젝트
├─index.html
├─css
├─img
│ ├─emoji
│ ├─help
│ ├─intro
│ └─profile
└─js
├─count.js
├─draw.js
├─emoji.js
├─errMsg.js
├─login.js
└─popup.js
2
3
4
5
6
7
8
9
10
11
12
13
14
15
index.html
: 앱의 메인 HTML 파일입니다.css
: 스타일시트 파일들이 위치하는 폴더입니다.img
: 이미지 파일들을 저장하는 폴더이며, 하위 폴더로 이모지, 도움말, 소개, 프로필 관련 이미지들이 있습니다.js
: JavaScript 파일들이 위치하는 폴더입니다.
필수 변경사항
데모 소스를 다운로드하여 사용하거나 iframe
을 사용할 때에는 CMS에서 발급받은 channelKey
값을 정확하게 설정해야 채팅 기능을 이용할 수 있습니다. 데모소스의 폴더 구성은 프로젝트의 폴더 구조
를 참고해 주세요.
iframe을 이용하여 진행
- 데모 화면 사이트에서 원하는 채팅 형태 (유튜브 PC, 유튜브 Mobile, 라이브커머스, 카카오톡)를 선택하고
소스코드 복사
버튼을 클릭합니다. - 복사한 소스코드를 원하는 HTML 파일에 붙여넣습니다.
- CMS 화면에서 해당 채팅방의
Channel Key
를 확인합니다. - 붙여넣은 소스코드의
<iframe>
태그 내src
속성 값에서?channelKey=YOUR_CHANNEL_KEY
부분을 찾아YOUR_CHANNEL_KEY
를 실제Channel Key
값으로 변경합니다.
<!DOCTYPE html>
<html>
<head>
<link href="css/style.css" rel="stylesheet" />
<link href="https://kit-free.fontawesome.com/releases/latest/css/free.min.css" media="all" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1.5.0/dist/sockjs.min.js"></script>
</head>
<body>
<div id="wrap">
<!-- 채팅 영역 -->
<iframe
src="https://www.vchatcloud.com/chat-demo/iframe/iframe_pc/index.html?channelKey=YOUR_CHANNEL_KEY"
frameborder="no"
scrolling="no"
marginwidth="0"
marginheight="0"
width="396"
height="736"
></iframe>
</div>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
iframe
사용에 대한 자세한 내용은Quick Start
문서를 참고하십시오.
데모 소스코드를 다운로드하여 진행
- CMS 화면에서 해당 채팅방의
Channel Key
를 복사합니다. - 원하는 데모 소스를 다운로드하고 압축을 해제합니다.
- 압축 해제된 폴더 내의
js
폴더에 있는login.js
파일을 엽니다. login.js
파일 내용 중에서channelKey
변수를 찾고, 복사한Channel Key
값을 할당합니다.
- 유튜브(PC형), 유튜브(mobile형), 라이브커머스 소스를 사용하는 경우,
js
폴더의login.js
파일에서youtubeId
변수 값을 원하는 유튜브 동영상 링크 ID로 변경하면 채팅 화면에 해당 동영상이 나타납니다.
const vChatCloud = new VChatCloud();
let channel, userNick, userKey, channelKey="", youtubeId;
var getParameters = function (paramName) {
// 리턴값을 위한 변수 선언
var returnValue;
// 현재 URL 가져오기
var url = location.href;
// get 파라미터 값을 가져올 수 있는 '?' 를 기점으로 slice한 후 split으로 분할
var parameters = (url.slice(url.indexOf('?') + 1, url.length)).split('&');
// 나누어진 값의 비교를 통해 paramName 으로 요청된 데이터의 값만 return
for (var i = 0; i < parameters.length; i++) {
var varName = parameters[i].split('=')[0];
if (varName.toUpperCase() == paramName.toUpperCase()) {
returnValue = parameters[i].split('=')[1];
return decodeURIComponent(returnValue);
}
}
};
channelKey = 'YOUR_CHANNEL_KEY';
$(function() {
if (getParameters('youtubeId') != undefined ) {
youtubeId = getParameters('youtubeId');
$("#ytplayer").attr("src","https://www.youtube.com/embed/"+youtubeId+"?autoplay=1&controls=0&mute=1&modestbranding=1&rel=0&loop=1"+youtubeId+"&loop=1");
}
....
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
VChatCloud SDK 활용
VChatCloud 객체 생성
VChatCloud
클래스의 인스턴스를 생성해야 SDK 기능을 사용할 수 있습니다. 생성된 인스턴스를 이용하여 channel 메소드 인스턴스를 생성할 수 있습니다.
var vChatCloud = new VChatCloud();
생성된 vChatCloud
인스턴스를 통해 채팅방 연결 및 이벤트 제어를 위한 channel
메소드 인스턴스를 만들 수 있습니다.
channel
객체를 이용한 채팅방 연결
channel
객체는 vChatCloud
인스턴스에 내장된 함수로, 채팅방 입장 및 메시지 관련 이벤트를 관리하는 데 사용됩니다. 채팅방에 입장한 뒤에는 channel.roomName
속성값을 확인하여 방 제목을 알 수 있습니다.
아래 예제는 채팅방 입장을 처리하는 방법을 보여줍니다. 메시지 전송, 공지 등 다른 이벤트에 대한 자세한 내용은 좌측 메뉴를 참고하십시오.
const vChatCloud = new VChatCloud();
var channel = vChatCloud.joinChannel(
{
roomId: "YOUR_CHANNEL_KEY", // 실제 Channel Key 값으로 변경해야 합니다.
clientKey: "yourUniqueClientKey", // 접속하는 클라이언트의 고유 키
nickName: "사용자 닉네임", // 채팅방에 표시될 사용자 닉네임
},
function (error, history) {
console.log(channel.roomName) // 접속한 채팅방의 이름
if (error) {
// 에러 발생 시 다음과 같은 형테의 데이터를 받습니다.
// {"code":10102,"type":"RECIPIENT_FAILURE","message":"CHANNEL_NOT_EXISTED"}
return confirm(error.message);
}
// 채팅방 접속 성공 시, 이전 채팅 기록(history)을 배열 형태로 받습니다.
// [{"logType":"message","roomId":"e7works","clientKey":"chatSample","message":"메시지","mimeType":"text","messageType":null,"nickName":"홍길동","date":"2020-08-31 18:00:00","grade":"user"},{"logType":"message","roomId":"e7works","clientKey":"administrator","message":"답","mimeType":"text","messageType":null,"nickName":"운영자","date":"2020-08-31 19:00:00","grade":"user"}, ... ]
console.log("히스토리 목록", JSON.stringify(history));
}
);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
joinChannel
메소드의 파라미터값 타입 설명 roomId
String 생성된 채팅방의 고유 키 (Channel Key) clientKey
String 접속하는 클라이언트의 고유 식별자 nickName
String 채팅방에 입장할 사용자의 닉네임 joinChannel
메소드의 콜백 함수 결과 값error
: 에러 발생 시 에러 정보를 담고 있는 객체입니다.값 타입 설명 code
String 에러 코드 type
String 에러 타입 message
String 에러 메시지 history
: 채팅방 접속 시 이전 채팅 기록을 담고 있는 배열입니다. 해당 데이터는 최근 채팅내역이 앞으로 오기 때문에 화면에 과거 채팅내역을 위쪽으로 표시하시려는 경우 역순으로 사용하셔야 합니다.값 타입 설명 logType
String 로그 타입 roomId
String 채팅방 고유 키 (Channel Key) clientKey
String 메시지를 보낸 클라이언트의 고유 키 message
String 메시지 내용 mimeType
String 메시지 형태 ("text": 일반 텍스트, "emoji": 이모지) messageType
String 일반 메시지는 null, 공지 메시지는 "notice" nickName
String 메시지를 보낸 사용자의 닉네임 date
String 메시지 전송 시간 ( yyyy-MM-dd HH:mm:ss
형식)grade
String 사용자의 등급
스크립트 영역 작성
스크립트 영역에서는 실제 앱의 동작을 정의합니다. 여기서는 채팅방 입장, 일반 채팅, 귓속말, 전체 공지, 사용자 추방, 글쓰기 제한 등의 기능을 구현합니다. 사용자는 앱 실행 시 나타나는 로그인 팝업창을 통해 채팅방 정보와 닉네임을 입력하고 입장하게 됩니다.
로그인 팝업창 활성화 및 처리 (login.js
)
기본적으로 CSS에 의해 숨겨진 로그인 팝업창을 화면에 표시하고, 사용자가 입력한 채팅방 정보 (channelKey
)와 닉네임을 가져와 joinRoom
함수를 호출하여 채팅방에 입장하는 로직을 담고 있습니다.
const vChatCloud = new VChatCloud();
let channel, userNick, userKey, channelKey, youtubeId;
var getParameters = function (paramName) {
// 리턴값을 위한 변수 선언
var returnValue;
// 현재 URL 가져오기
var url = location.href;
// get 파라미터 값을 가져올 수 있는 '?' 를 기점으로 slice 한 후 split 으로 분할
var parameters = url.slice(url.indexOf("?") + 1, url.length).split("&");
// 나누어진 값의 비교를 통해 paramName 으로 요청된 데이터의 값만 return
for (var i = 0; i < parameters.length; i++) {
var varName = parameters[i].split("=")[0];
if (varName.toUpperCase() == paramName.toUpperCase()) {
returnValue = parameters[i].split("=")[1];
return decodeURIComponent(returnValue);
}
}
};
channelKey = "YOUR_CHANNEL_KEY"; // 실제 Channel Key 값으로 변경해야 합니다.
$(function () {
/**
* 'youtubeId'값
* 1) 빈 값이 아닌 경우 id에 해당하는 영상으로 교체
* 2) 빈 값인 경우 채팅화면에서 비디오 영역만 제공(영역은 css를 통해 수정 가능)
*/
if (getParameters("youtubeId") != undefined) {
youtubeId = getParameters("youtubeId");
$("#ytube_link").attr(
"src",
"https://www.youtube.com/embed/" +
youtubeId +
"?autoplay=1&controls=0&mute=1&modestbranding=1&rel=0&playlist=" +
youtubeId +
"&loop=1"
);
} else {
$("div .pc").css("width", "380px");
$("div .pc").css("height", "710px");
$(".pc .chat_field").css("height", "570px");
$("div .video").remove();
let html = "";
html += '<ul class="like">';
html +=
'<li><span id="likeCounter" style="margin-right: 7px;"></span></li>';
html += '<li><i id="sendLike" class="fab fa-gratipay"></i></li>';
html += "</ul>";
$("div .btn").append(html);
}
let p = $("div.login").show(), // 로그인 팝업창을 보여줍니다.
c = $("div.chat_field1").hide(); // 채팅 영역을 숨깁니다.
likeInif();
$("button.popupbtn", p).click(function () {
let r = { nick: $("input#name", p).val() };
if (r.nick) {
$("div.chat_input div.name").text(r.nick);
joinRoom(
channelKey,
"xxxxxxxx".replace(/[xy]/g, function (a, b) {
return (
(b = Math.random() * 16),
(a == "y" ? (b & 3) | 8 : b | 0).toString(16)
);
}),
r.nick,
function (err, history) {
if (err) {
openError(err.code, function () {
p.show();
c.hide();
vChatCloud.disconnect();
});
} else {
// 채팅영역에 글쓰기가 활성화 될 시 활성화
let noticeMsgCnt = 0;
if (typeof write == "function")
history &&
history.forEach(function (m) {
if (m.messageType == "notice") {
if (noticeMsgCnt == 0) {
noticeMsgCnt++;
write(m, "notice", true);
}
} else {
write(m, "", true);
}
});
p.hide(); // 로그인 팝업창을 숨깁니다.
c.show(); // 채팅 영역을 보여줍니다.
// 이벤트 바인딩 시작
chatInit(); // 채팅 관련 이벤트 바인딩
personalInit(); // 개인 설정 관련 이벤트 바인딩
msgInit(); // 메시지 관련 이벤트 바인딩
likeInif(); // 좋아요 기능 초기화
}
}
);
}
});
$("div.chat_name a.closebtn").click(function () {
p.show();
c.hide();
vChatCloud.disconnect();
$("#likeCounter").text("0");
});
});
function joinRoom(roomId, clientKey, nickName, callback) {
channel = vChatCloud.joinChannel(
{
roomId: roomId,
clientKey: clientKey,
nickName: nickName,
},
function (error, history) {
console.log(channel.roomName) // 접속한 채팅방의 이름
$(
"div.entery, div.chatout, div.notice, div.whisper, div.content"
).remove();
if (error) {
if (callback) return callback(error, null);
return error;
}
if (callback) callback(null, history);
// 채팅영역에 글쓰기가 활성화될시 활성화
if (typeof write == "function")
write(
"실시간 채팅에 오신 것을 환영합니다. 개인정보를 보호하고 커뮤니티 가이드를 준수하는 것을 잊지 마세요!",
"notice"
);
}
);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
채팅 영역에 메시지 표시 (draw.js
)
write
함수는 서버로부터 수신한 다양한 형태의 메시지 (입장, 퇴장, 일반 메시지, 공지, 귓속말 등)를 채팅 화면에 적절한 UI 형태로 표시하는 역할을 합니다.
function write(msg, tp, pre) {
let cl = $("div.chat div#content1");
let cc = $("<div>", { class: "chat-content" });
switch (tp) {
case "join":
cc = $("<div>", { class: "entery" });
cc.append(
$("<span>").html("<b>" + msg.nickName + "</b>님이 입장하셨습니다.")
);
break;
case "leave":
cc = $("<div>", { class: "chatout" });
cc.append(
$("<span>").html("<b>" + msg.nickName + "</b>님이 나가셨습니다.")
);
break;
case "notice":
cc = $("<div>", { class: "notice" });
cc.append($('<span><i class="fas fa-flag"></i></span>'));
cc.append($("<span>").html(typeof msg == "string" ? msg : msg.message));
break;
case "whisper":
cc = $("<div>", { class: "whisper" });
cc.append($('<span><i class="fas fa-comment-alt"></i></span>'));
cc.append(
$("<ul>")
.append(
$("<li>")
.append(
$('<a href="#!" class="name">')
.html(msg.nickName)
.data(msg)
.on({ click: openLayer })
)
.append(document.createTextNode("님의 귓속말"))
)
.append($('<li class="comment">').text(msg.message))
);
break;
case "whisperto":
cc = $("<div>", { class: "whisper" });
cc.append($('<span><i class="fas fa-comment-alt"></i></span>'));
cc.append(
$("<ul>")
.append(
$("<li>")
.append(
$('<a href="#!" class="name">').html(msg.receivedNickName)
)
.append(document.createTextNode("님에게 귓속말"))
)
.append($('<li class="comment">').text(msg.message))
);
break;
case "allExit":
$("div.login").show();
$("div.chat_field1").hide();
cc = $("<div>", { class: "entery" });
cc.append($("<span>").html("<b>채팅방을 종료합니다..</b>"));
break;
case "userManager":
cc = $("<div>", { class: "content admin" });
if (typeof msg == "string") {
cc.append($('<a class="name" href="#!">').text(""));
cc.append($('<span class="">').html(msg));
} else if (typeof msg == "object" && msg.message) {
if (channel.clientKey != msg.clientKey) {
cc.append(
$('<a class="name" href="#!">')
.text(msg.nickName)
.data(msg)
.on({ click: openLayer })
);
} else {
cc.append($('<a class="name" href="#!">').text(msg.nickName));
}
cc.append($('<span class="">').html(msg.message));
}
break;
default:
cc = $("<div>", { class: "content" });
if (typeof msg == "string") {
cc.append($('<a class="name" href="#!">').text(""));
cc.append($('<span class="comment">').html(msg));
} else if (typeof msg == "object" && msg.message) {
if (channel.clientKey != msg.clientKey) {
cc.append(
$('<a class="name" href="#!">')
.text(msg.nickName)
.data(msg)
.on({ click: openLayer })
);
} else {
cc.append($('<a class="name" href="#!">').text(msg.nickName));
}
cc.append($('<span class="comment">').html(msg.message));
}
}
if (pre) {
cl.prepend(cc);
} else {
cl.append(cc);
}
$("div.chat div.chat_contents").scrollTop(cl.height());
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
이모티콘 창 표시 및 숨김 (emoji.js
)
이 스크립트는 채팅 입력창 하단의 이모티콘 팔레트를 생성하고, 이모티콘 아이콘 클릭 시 팔레트를 보여주거나 숨기는 기능을 구현합니다.
$(function () {
// 이모지콘 div를 동적으로 생성하여 추가
for (var i = 0; i < 18; i++) {
var code = 0x1f600 + i;
$("div.bottom div.emoji").append(
$("<a>", { href: "#none" })
.css({ "font-size": "21px" })
.html(String.fromCodePoint(code))
);
}
// 이모지콘 / 키보드 아이콘 토글
$(".ico_emoji").click(function () {
$("div.emoji").show();
$("a.ico_emoji").removeClass("show");
$("a.ico_keyboard").addClass("show");
$(".middle").addClass("height01");
});
$(".ico_keyboard").click(function () {
$("div.emoji").hide();
$("a.ico_emoji").addClass("show");
$("a.ico_keyboard").removeClass("show");
$(".middle").removeClass("height01");
});
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
채팅 메시지 글자 수 제한 및 카운터 표시 (count.js
)
이 스크립트는 채팅 입력창에 입력되는 글자 수를 실시간으로 세어 제한하고, 현재 글자 수와 최대 글자 수를 사용자에게 보여주는 기능을 합니다.
$(function () {
$("#content").keyup(function (e) {
if ($(this).text().length > 100) {
openError("글자수는 100자로 이내로 제한됩니다.");
$(this).text($(this).text().substring(0, 100));
}
$("#counter").html($(this).text().length + "/100");
});
$("#content").keyup();
});
2
3
4
5
6
7
8
9
10
귓속말 팝업창 표시 및 숨김 (popup.js
)
이 스크립트는 채팅 메시지 작성자 닉네임 클릭 시 귓속말 팝업창을 표시하고, 팝업창 외부 영역을 클릭하면 팝업창을 숨기는 기능을 제공합니다.
$(function () {
$(".content1 .name").click(function (e) {
var sWidth = window.innerWidth;
var sHeight = window.innerHeight;
var oWidth = $(".popupLayer").width();
var oHeight = $(".popupLayer").height();
var fWidth = $("#chat").offset().left;
var fHeight = $("#chat").offset().top;
var cHeight = $("#content1").height();
console.log("cHeight :" + cHeight);
// 팝업창이 나타날 위치 계산
var divLeft = e.clientX - fWidth;
var divTop = e.clientY - fHeight;
// 팝업창이 화면 경계를 벗어나지 않도록 위치 조정
if (divLeft + oWidth > sWidth) divLeft -= oWidth;
if (divTop + oHeight > sHeight) divTop -= oHeight;
if (divTop > cHeight - oHeight) {
divTop = divTop - oHeight;
}
// 팝업창 위치가 화면 상단을 벗어나지 않도록 조정
if (divLeft < 0) divLeft = 0;
if (divTop < 0) divTop = 0;
$(".popupLayer")
.css({
top: divTop,
left: divLeft,
position: "absolute",
"z-index": 1,
})
.show();
});
// 귓속말 팝업
$("#whisper").show();
$(".whisper").click(function () {
$("#whisper").show();
});
// 팝업창 외부 영역 클릭 시 팝업창 숨김
$(document).mouseup(function (e) {
var container = $(".popupLayer");
if (container.has(e.target).length === 0) {
container.hide();
$("#whisper").hide();
}
});
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56