# 준비사항
앱을 실행하기 위한 필수 라이브러리와 프로젝트 구조를 알아보자
# 프로젝트의 폴더 구조
프로젝트
├─index.html
├─css
├─img
│ ├─emoji
│ ├─help
│ ├─intro
│ └─profile
└─js
├─count.js
├─draw.js
├─emoji.js
├─errMsg.js
├─login.js
├─popup.js
└─vchatcloud.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 필수 변경사항
iframe을 과 데모소스 를 다운로드하여 사용할 때에는 channelKey 값을 변경해야 합니다.
하단의 설명을 통해서 변경 부분을 확인하여 따라해준다.
데모소스의 폴더 구성은 프로젝트의 폴더 구조를 참고해 주세요.
데모화면 사이트(opens new window) 에서 유튜브(PC)형, 유튜브(Mobile)형, 라이브커머스형, 카카오톡형
4개의 종류 중선택하여 우측 사단의소스코드 복사버튼 클릭- 소스코드 복사 후 아래와 같이 작성해준다.
- 작성된 소스코드에서 CMS 화면에서 개설한 채팅방의
Channel Key를 복사한다.?channelKey=뒤에 수정해준다.
- iframe 사용방법은
퀵 스타트에서 사용방법이 작성되었습니다.
<!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=VBrhzLZgGG-nAFo5CS7jp-20210802120142"
frameborder="no"
scrolling="no"
marginwidth="0"
marginheight="0"
width="396"
height="736"
></iframe>
</div>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
유튜브(PC)형 💾 유튜브(Mobile)형 💾 라이브커머스형 💾 카카오톡형 💾
- CMS 화면에서 개설한 채팅방의
Channel Key를 복사한다. - 4개의 종류 중 한가지 선택하여 다운로드 한다.
- 파일을 압축을 해제하여
js폴더 안에login.js파일의 내용중 channelKey라는 변수 명의 값에 1번에서 복사한 key 값을 붙여 넣어준다.
- 유튜브(PC형), 유튜브(mobile형), 라이브커머스 소스는 유튜브 동영상 링크를
youtubeId 변수값에 넣어주면 유튜브 동영상이 변경된다.
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 = 'VBrhzLZgGG-nAFo5CS7jp-20210802120142';
$(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");
}
....
}
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
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
# vchatcloud 객체
# vchatcloud 클래스 선언
vchatcloud.js는 변수를 선언하여 인스턴스를 생성해야 합니다.
생성된 인스턴스를 이용하여 channel 메소드 인스턴스를 생성할수 있습니다.
var vChatCloud = new VChatCloud();
1
# channel 메소드 선언
channel는 vchatCloud 인스턴스에 구현된 메소드입니다.
channel 메소드를 이용하여 채팅방에 진입하고, 메시지 이벤트들을 컨트롤할 수 있습니다.
아래 코드는 채팅방 진입만 다루고 있고, 메시지 전송, 공지등은 자세한 이벤트 설명은 좌측 메뉴를 확인해 주세요.
var channel = vChatCloud.joinChannel(
{
roomId: 'e7works',
clientKey: 'chatSample',
nickName: '홍길동',
},
function(error, history) {
if (error) {
// {"code":10102,"type":"RECIPIENT_FAILURE","message":"CHANNEL_NOT_EXISTED"}
return confirm(error.message);
}
// [{"logType":"message","roomId":"e7works","clientKey":"8cf65163","message":"로컬이당","mimeType":"text","messageType":null,"nickName":"로컬","date":"2020-08-31 17:54:09","grade":"user"},{"logType":"message","roomId":"e7works","clientKey":"sweeter198dfb667","message":"12","mimeType":"text","messageType":null,"nickName":"운영자","date":"2020-08-31 15:31:43","grade":"user"}, ... ]
console.log('히스토리 목록', JSON.stringify(history));
}
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
파라미터 값
값 식별자 설명 roomId String CMS 가입 후에 발급받은 Channel Key clientKey String 접속 단말 설정 고유키 nickName String 채팅방 입장 유저의 별명 결과 값
- error
값 식별자 설명 code String 에러 코드 type String 에러 타입 message String 에러 메시지 - history
값 식별자 설명 logType String 로그타입 roomId String CMS 가입 후에 발급받은 Channel Key clientKey String 접속 단말 설정 고유키 message String 메시지내용 mimeType String 메시지형태 (text: 일반텍스트, emoji: 이모지) messageType String 빈값이면 일반 메시지, 공지일경우 : "notice" nickName String 채팅방 입장 유저의 별명 date String 전송시간 grade String 유저등급
# 스크립트 영역 작성
스크립트 영역은 실제 앱을 동작을 위한 코드로 채팅방으로 입장을 시작하며,
채팅 / 귓속말 / 전체공지 / 추방 / 글쓰기 제한 으로 구성되어 있습니다.
입장 시에 채팅방 번호 및 별칭을 입력하는 로그인 팝업으로 진행하오니 이점 참고해 주세요.
아래에는 각각 이벤트를 컨트롤하는 js 코드 부분입니다.
css 로 비활성화 되어있는 로그인 팝업창을 활성화 상태로 변경하는 코드입니다.
로그인창을 통해 채팅방 정보와 닉네임 정보를 받아서 채널 객체로 값을 넘기도록 되어있으며,
채널 객체를 통해 채팅방으로 입장할 수 있도록 코딩되어 있습니다.
로그인 팝업창 js 코드보기
<script type="text/javascript">
const vChatCloud = new VChatCloud();
const dhd = 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 = 'VBrhzLZgGG-nAFo5CS7jp-20210802120142';
$(function() {
// 파라미터로 "youtubeId" 값이 빈값이 아닐경우 영상 교체
// 비디오 영역을 보여주며, 빈값일때는 채팅 채팅화면 영역만 보여준다.(채팅영역은 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) {
// vchatcloud 객체
channel = vChatCloud.joinChannel({
roomId: roomId,
clientKey: clientKey,
nickName: nickName
}, function(error, history) {
$('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');
})
}
</script>
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
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
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
채팅영역에 글쓰기 js 코드보기
<script type="text/javascript">
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());
}
</script>
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
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
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
이모티콘 창 노출 js 코드보기
<script type="text/javascript">
$(function() {
// 이모지콘 넣기위해 기능이 있는지 확인
if (!String.fromCodePoint)(function(stringFromCharCode) {
var fromCodePoint = function(_) {
var codeUnits = [],
codeLen = 0,
result = "";
for (var index = 0, len = arguments.length; index !== len; ++index) {
var codePoint = +arguments[index];
// correctly handles all cases including `NaN`, `-Infinity`, `+Infinity`
// The surrounding `!(...)` is required to correctly handle `NaN` cases
// The (codePoint>>>0) === codePoint clause handles decimals and negatives
if (!(codePoint < 0x10FFFF && (codePoint >>> 0) === codePoint))
throw RangeError("Invalid code point: " + codePoint);
if (codePoint <= 0xFFFF) { // BMP code point
codeLen = codeUnits.push(codePoint);
} else { // Astral code point; split in surrogate halves
// https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
codePoint -= 0x10000;
codeLen = codeUnits.push(
(codePoint >> 10) + 0xD800, // highSurrogate
(codePoint % 0x400) + 0xDC00 // lowSurrogate
);
}
if (codeLen >= 0x3fff) {
result += stringFromCharCode.apply(null, codeUnits);
codeUnits.length = 0;
}
}
return result + stringFromCharCode.apply(null, codeUnits);
};
try { // IE 8 only supports `Object.defineProperty` on DOM elements
Object.defineProperty(String, "fromCodePoint", {
"value": fromCodePoint,
"configurable": true,
"writable": true
});
} catch (e) {
String.fromCodePoint = fromCodePoint;
}
}(String.fromCharCode));
// 이모지콘 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");
})
});
</script>
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
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
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
글자 수 세기 js 코드보기
<script type="text/javascript">
$(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();
});
function likeInif() {
var url = "https://vchatcloud.com/api/openapi/getLike";
var param = {
"room_id": channel.roomId
};
$.post(url, param, function(data) {
if (data.result_cd == 1) {
$('#likeCounter').html(data.like_cnt);
} else {
console.log("조회 실패")
}
}, "json");
$('#sendLike').click(function(e) {
var url = "https://vchatcloud.com/api/openapi/like";
var param = {
"room_id": channel.roomId,
"log_cnt": 1
};
$.post(url, param, function(data) {
if (data.result_cd == 1) {
$('#likeCounter').html(data.like_cnt);
} else {
console.log("조회 실패")
}
}, "json");
})
}
</script>
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
33
34
35
36
37
38
39
40
41
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
귓속말 팝업창 js 코드보기
<script type="text/javascript">
$(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;
}
// 레이어 위치를 바꾸었더니 상단기준점(0,0) 밖으로 벗어난다면 상단기준점(0,0)에 배치하자.
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();
}
});
});
</script>
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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