# 준비사항
앱을 실행하기 위한 필수 라이브러리와 프로젝트 구조를 알아보자
# 프로젝트의 폴더 구조
프로젝트
├─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