...
Tagify js 라이브러리
게시물을 구현할때 빠지지 않는 것이 바로 게시글 # 해시 태그 기능이다. 당장 이 티스토리 게시글에도 태그 기능이 들어 있다.
해시 태그 기능을 만드는 것 자체는 그렇게 어렵지 않다.
적당히 어느 요소에 # 문자를 저장하고 서버에서 문자열 파싱해서 데이터베이스에 저장하면 되기 떄문이다.
다만 UI/UX 적인 요소에서 각 해시 태그를 블럭으로 만들어서 보기 좋게 관리하기에는 쉽지 않은데, 다행히 tagify.js 라는 태그 컴포넌트가 있어 소개해본다.
See the Pen Tags input - vanilla by Yair Even Or (@vsync) on CodePen.
위의 샘플 코드처럼 자동으로 해시 태그 영역을 생성해주고, 태그 문자 추가 애니메이션과 더불어 박스를 더블 클릭하면 수정, 삭제 기능 및 다양한 추가 옵션들을 아주 손쉽게 풍부히 지원해준다.
Tagify.js의 기능을 짧게 요약하자면 다음과 같다.
- Input/Textarea 에 Tag 입력을 지원
- Vanilla, React, Vue, Angular 지원
- 일반 문자열과 혼합 사용 가능
- 더블 클릭해서 기존 입력한 태그 수정
- 자동 완성, 자동 추천
- 여러개의 태그 붙여넣기
- fuzzy 검색을 위해 alias 지정 가능
- Single Value 모드: Select와 비슷하지만 텍스트 입력도 가능
- whitelist / blacklist 리스트 지원
- 다양한 이벤트 지원
- change,add,remove,invalid,input,click,dblclick,keydown,focus,blur
- edit:input, edit:beforeUpdate, edit:updated, edit:start, edit:keydown
- dropdown:show, dropdown:hide, dropdown:select, dropdown:scroll, dropdown:noMatch
Tagify 사용법
Node.js
$ npm i @yaireo/tagify
import Tagify from '@yaireo/tagify'
var tagify = new Tagify(...)
Client
<!-- 소스 다운 -->
<script src="https://unpkg.com/@yaireo/tagify"></script>
<!-- 폴리필 (구버젼 브라우저 지원) -->
<script src="https://unpkg.com/@yaireo/tagify/dist/tagify.polyfills.min.js"></script>
<link href="https://unpkg.com/@yaireo/tagify/dist/tagify.css" rel="stylesheet" type="text/css" />
<!-- 해시 태그 정보를 저장할 input 태그. (textarea도 지원) -->
<input name='basic'>
<script>
const input = document.querySelector('input[name=basic]');
let tagify = new Tagify(input); // initialize Tagify
// 태그가 추가되면 이벤트 발생
tagify.on('add', function() {
console.log(tagify.value); // 입력된 태그 정보 객체
})
</script>
See the Pen tagify연습 by barzz12 (@inpaSkyrim) on CodePen.
Tagify - 입력 옵션
- 허용 목록의 태그만 존재하도록 허용 (블랙리스트 / 화이트리스트)
- 화이트리스트 드롭다운 리스트 메뉴 지원
- 외부 버튼으로 "모든 태그 제거"
- Tagify 전용 이벤트 리스너 : https://github.com/yairEO/tagify#events
- Tagify 전용 메소드 : https://github.com/yairEO/tagify#methods
<input
name='input'
placeholder='write some tags'
value='css, html, javascript, css'
data-blacklist='.NET,PHP'
autofocus
>
<!--
placeholder : 입력 힌트 메세지
value : 미리 값을 집어넣으면 초기 태깅이 되어있다
data-blacklist : 블랙리스트 : 해당 문자는 태그로 추가 불가능
autofocus : 자동 태그입력창으로 포커스
-->
<script>
let inputElm = document.querySelector('input[name=input]');
// 화이트 리스트 : 해당 문자만 태그로 추가 가능
let whitelist = ["puthon","java","pug","react","vue","c","sass"];
// initialize Tagify
var tagify = new Tagify(inputElm, {
enforceWhitelist: true, // 화이트리스트에서 허용된 태그만 사용
whitelist: whitelist // 화이트 리스트 배열. 화이트 리스트를 등록하면 자동으로 드롭다운 메뉴가 생긴다
})
// 만일 모든 태그 지우기 기능 버튼을 구현한다면
document.querySelector('버튼').addEventListener('click', tagify.removeAllTags.bind(tagify));
// tagify 전용 이벤트 리스터. 참조 : https://github.com/yairEO/tagify#events
tagify.on('add', onAddTag) // 태그가 추가되면
.on('remove', onRemoveTag) // 태그가 제거되면
.on('input', onInput) // 태그가 입력되고 있을 경우
.on('invalid', onInvalidTag) // 허용되지 않는 태그일 경우
.on('click', onTagClick) // 해시 태그 블럭을 클릭할 경우
.on('focus', onTagifyFocusBlur) // 포커스 될 경우
.on('blur', onTagifyFocusBlur) // 반대로 포커스를 잃을 경우
.on('edit:start', onTagEdit) // 입력된 태그 수정을 할 경우
.on('dropdown:hide dropdown:show', e => console.log(e.type)) // 드롭다운 메뉴가 사라질경우
.on('dropdown:select', onDropdownSelect) // 드롭다운 메뉴에서 아이템을 선택할 경우
// tagify 전용 이벤트 리스너 제거 할떄
tagify.off('add', onAddTag);
// 이벤트 리스너 콜백 메소드
function onAddTag(e){
console.log("onAddTag: ", e.detail);
console.log("original input value: ", inputElm.value)
}
// tag remvoed callback
function onRemoveTag(e){
console.log("onRemoveTag:", e.detail, "tagify instance value:", tagify.value)
}
function onTagEdit(e){
console.log("onTagEdit: ", e.detail);
}
// invalid tag added callback
function onInvalidTag(e){
console.log("onInvalidTag: ", e.detail);
}
// invalid tag added callback
function onTagClick(e){
console.log(e.detail);
console.log("onTagClick: ", e.detail);
}
function onTagifyFocusBlur(e){
console.log(e.type, "event fired")
}
function onDropdownSelect(e){
console.log("onDropdownSelect: ", e.detail)
}
function onInput(e){
console.log("onInput: ", e.detail);
tagify.loading(true) // 태그 입력하는데 우측에 loader 애니메이션 추가
tagify.loading(false) // loader 애니메이션 제거
tagify.dropdown.show(e.detail.value); // 드롭다운 메뉴 보여주기
tagify.dropdown.hide(); // // 드롭다운 제거
}
</script>
See the Pen Tagify - Text Input Example by Yair Even Or (@vsync) on CodePen.
Tagify - 드롭다운 메뉴 꾸미기
.tagify{
width: 100%;
max-width: 700px;
}
.tags-look .tagify__dropdown__item{
display: inline-block;
border-radius: 3px;
padding: .3em .5em;
border: 1px solid #CCC;
background: #F3F3F3;
margin: .2em;
font-size: .85em;
color: black;
transition: 0s;
}
.tags-look .tagify__dropdown__item--active{
color: black;
}
.tags-look .tagify__dropdown__item:hover{
background: lightyellow;
border-color: gold;
}
var input = document.querySelector('input[name="input-custom-dropdown"]'),
// init Tagify script on the above inputs
tagify = new Tagify(input, {
whitelist: ["..."], // 화이트리스트 배열
maxTags: 10, // 최대 허용 태그 갯수
dropdown: {
maxItems: 20, // 드롭다운 메뉴에서 몇개 정도 항목을 보여줄지
classname: "tags-look", // 드롭다운 메뉴 엘리먼트 클래스 이름. 이걸로 css 선택자로 쓰면 된다.
enabled: 0, // 단어 몇글자 입력했을떄 추천 드롭다운 메뉴가 나타날지
closeOnSelect: false // 드롭다운 메뉴에서 태그 선택하면 자동으로 꺼지는지 안꺼지는지
}
})
See the Pen Tagify - Customized suggestions style by Yair Even Or (@vsync) on CodePen.
Tagify - 입력을 제한
사용자가 키보드로 입력하는것을 제한하고 드롭다운 메뉴에서만 고르게 설정한다.
<input name='tags-disabled-user-input' placeholder='Select tags from the list''>
<script>
var input = document.querySelector('input[name=tags-disabled-user-input]');
new Tagify(input, {
whitelist: [1,2,3,4,5], // 화이트리스트 드롭다운 메뉴 설정
userInput: false // 입력 제한
})
</script>
See the Pen Tagify - Disabled User Input by Yair Even Or (@vsync) on CodePen.
Tagify - 특정 패턴만 태그 등록
pattern 속성과 정규식을 이용해 특정 패턴만 태그에 등록하도록 할 수 있다.
<input name='tags'>
<script>
var input = document.querySelector('input[name=tags]');
var tagify = new Tagify(input, {
// 이메일 패턴만 태그로 등록 가능
pattern: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
})
</script>
Tagify - Outside of the Box
입력창이 아닌 다른 요소에 태그 블럭이 만들어지도록 한다.
<style>
.tagify--outside{
border: 0;
}
.tagify--outside .tagify__input{
order: -1;
flex: 100%;
border: 1px solid var(--tags-border-color);
margin-bottom: 1em;
transition: .1s;
}
.tagify--outside .tagify__input:hover{ border-color:var(--tags-hover-border-color); }
.tagify--outside.tagify--focus .tagify__input{
transition:0s;
border-color: var(--tags-focus-border-color);
}
</style>
<input name='tags-outside' class='tagify--outside' placeholder='write tags to add below'>
<script>
var input = document.querySelector('input[name=tags-outside]')
var tagify = new Tagify(input, {
whitelist: ["foo", "bar", "baz"],
dropdown: {
position: "input",
enabled : 0 // always opens dropdown when input gets focus
}
})
</script>
See the Pen Tagify - Outside-Of-The-Box Example by Yair Even Or (@vsync) on CodePen.
Tagify - Drag & Sort 기능
태그 블록을 마우스로 드래그해서 순서를 변경할 수 있다.
<input name='drag-sort' value='tag 1, tag 2, tag 3, tag 4, tag 5, tag 6' />
<script>
var input = document.querySelector('input[name=drag-sort]'),
tagify = new Tagify(input);
// using 3-party script "dragsort"
// https://github.com/yairEO/dragsort
var dragsort = new DragSort(tagify.DOM.scope, {
selector:'.'+tagify.settings.classNames.tag,
callbacks: {
dragEnd: onDragEnd
}
})
function onDragEnd(elm){
tagify.updateValueByDOMTags()
}
</script>
See the Pen Tagify - Drag & Sort by Yair Even Or (@vsync) on CodePen.
Tagify - 예쁜 태그 스타일
article {
width: 100%;
max-width: 700px;
}
.customLook {
--tag-bg: #0052bf;
--tag-hover: #ce0078;
--tag-text-color: #fff;
--tags-border-color: silver;
--tag-text-color--edit: #111;
--tag-remove-bg: var(--tag-hover);
--tag-pad: 0.6em 1em;
--tag-inset-shadow-size: 1.3em;
--tag-remove-btn-bg--hover: black;
display: inline-block;
min-width: 0;
border: none;
}
.customLook .tagify__tag {
margin-top: 0;
}
.customLook .tagify__tag > div {
border-radius: 25px;
}
/* Do not show the "remove tag" (x) button when only a single tag remains */
.customLook .tagify__tag:only-of-type .tagify__tag__removeBtn {
display: none;
}
.customLook .tagify__tag__removeBtn {
opacity: 0;
transform: translateX(-6px) scale(0.5);
margin-left: -3ch;
transition: 0.12s;
}
.customLook .tagify__tag:hover .tagify__tag__removeBtn {
transform: none;
opacity: 1;
margin-left: -1ch;
}
.customLook + button {
color: #0052bf;
font: bold 1.4em/1.65 Arial;
border: 0;
background: none;
box-shadow: 0 0 0 2px inset currentColor;
border-radius: 50%;
width: 1.65em;
height: 1.65em;
cursor: pointer;
outline: none;
transition: 0.1s ease-out;
margin: 0 0 0 5px;
vertical-align: top;
}
.customLook + button:hover {
box-shadow: 0 0 0 5px inset currentColor;
}
.customLook .tagify__input {
display: none;
}
<article>
<input class='customLook' value='some.name@website.com'>
<button type="button">+</button>
</article>
<script>
</script>
See the Pen tagify연습2 by barzz12 (@inpaSkyrim) on CodePen.
Tagify - ReadOnly
태그를 보여주기만 하는 용도로서, 게시글의 태그를 나열하는데 쓰이면 될것 같다.
<input name='tags' readonly value='tag1, tag 2, another tag'>
<script>
var input = document.querySelector('input[name=tags]')
new Tagify(input)
</script>
See the Pen Tagify - Read-Only Example by Yair Even Or (@vsync) on CodePen.
Tagify - Textarea 요소에서 사용하기
<textarea name='tags2' placeholder='Movie names'>
[{"value":"The Good, the Bad and the Ugly"}, {"value":"The Matrix"}]
</textarea>
<script>
var input = document.querySelector('textarea[name=tags2]'),
tagify = new Tagify(input, {
enforceWhitelist : true,
delimiters : null,
whitelist : ["The Shawshank Redemption", "The Godfather", "The Godfather: Part II", "The Dark Knight"],
callbacks : {
add : console.log, // callback when adding a tag
remove : console.log // callback when removing a tag
}
});
</script>
See the Pen Tagify - Textarea instead of Input Example by Yair Even Or (@vsync) on CodePen.
Tagify - 서버에 태그 정보 전송 (form 과 함께 사용)
ajax로 태그 정보가 들어있는 객체인 tagify.value 를 보내면 되겠지만, 폼 submit으로 서버에 태그 정보를 보내야 할떄 방법을 소개해본다.
<form action="/post" method="post">
<!-- input 태그에 type hidden을 부여 -->
<input name='postTag' placeholder="#해시태그" type="hidden">
</form>
<script>
var input = document.querySelector('input[name=postTag]')
new Tagify(input)
</script>
input 태그에 type="hidden" 속성을 부여하고, tagify를 실행시킨다.
그리고 입력창에 태그를 입력하고 개발자 도구 html에서 input 태그를 보면 다음과 같이 value 속성에 태그 정보 배열이 들어 있다.
이제 폼 sumit을 하고 서버로 해당 배열 문자열이 전송된다.
그러면 서버에서 다음과 같이 받아서 쓰면 된다. 서버는 Node(express) 기준으로 설명한다.
router.post('/', (req, res, next) => {
console.log('\nreq.body : %o\n', req.body);
// req.body.postTag 문자열 배열을 받아 JSON.parse로 객체 자료형으로 만들고 .map() 고차함수로 돌아 value속성의 값을 빼와 배열로 만들어준다.
const hashtags = JSON.parse(req.body.postTag).map((e) => {
return e.value.toLowerCase();
});
});
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.