-
Notifications
You must be signed in to change notification settings - Fork 3
json‐editor for web component
redgoose.eth edited this page Aug 28, 2023
·
1 revision
JSON Editor
에디터를 웹 컴포넌트로 만들어서 사용할 수 있습니다.
에디터 라이브러리를 웹 컴포넌트 클래스 속에 집어넣고 사용하는 것이죠. 웹 컴포넌트로 사용하면 스타일시트를 격리화 시킬 수 있습니다.
파일 하나로 출력하여 사용할 수 있다는점이 매력적이죠.
web-component.js
import JsonEditorCore from '@redgoose/json-editor'
import css from '@redgoose/json-editor/css?inline'
class JsonEditor extends HTMLElement {
constructor()
{
super()
this.attachShadow({ mode: 'open' })
const template = document.createElement('template')
template.innerHTML = `<div id="json-editor"></div>`
const style = new CSSStyleSheet()
style.replaceSync(css)
this.shadowRoot.appendChild(template.content.cloneNode(true))
this.shadowRoot.adoptedStyleSheets = [ style ]
this.root = this.shadowRoot.childNodes[0]
this.ready = false
this.options = {
live: false,
theme: 'system', // system,light,dark
}
}
static get observedAttributes()
{
return [ 'src', 'theme', 'live' ]
}
get props()
{
return {
src: this.getAttribute('src'),
theme: this.getAttribute('theme'),
live: this.getAttribute('live'),
}
}
/**
* change attributes
*/
attributeChangedCallback(name, oldValue, newValue)
{
if (oldValue === newValue) return
switch (name)
{
case 'theme':
this.options.theme = newValue
if (this.core) this.core.options.theme = this.options.theme
break
case 'live':
this.options.live = [ 'true', '1' ].includes(newValue)
if (this.core) this.core.options.live = this.options.live
break
}
}
/**
* mounted component
*/
connectedCallback()
{
this.core = new JsonEditorCore(this.root, this.options)
this.core.replace(JSON.parse(this.props.src), false)
this.root.addEventListener('update', this.#onUpdate.bind(this))
this.root.addEventListener('context', this.#onContext.bind(this))
}
/**
* unmounted component
*/
disconnectedCallback()
{
// destroy core
if (!this.core) return
this.core.destroy()
delete this.core
// clear source
this.root.innerHTML = ''
}
#event(name, src)
{
this.dispatchEvent(new CustomEvent(name, {
detail: src,
}))
}
#onUpdate({ detail })
{
this.setAttribute('src', JSON.stringify(detail))
this.#event('update', detail)
}
#onContext({ detail: { body, node, type, isRoot, $ } })
{
this.#event('context', { body, node, type, isRoot, $ })
}
/**
* change src
* @param {object|array} src
*/
change(src)
{
this.setAttribute('src', JSON.stringify(src))
this.core.replace(src, true)
}
}
export default JsonEditor
먼저 에디터 라이브러리와 스타일시트를 불러온 웹 컴포넌트 클래스를 작성해둡니다.
이 코드로 저장된 파일이 진짜 웹 컴포넌트이며 이것을 불러와서 사용하면 됩니다.
사용 환경은
vite
인점을 알려드립니다.
먼저 패키지를 설치합니다.
npm install @redgoose/json-editor
설치한 후에 html 코드에서 다음과 같이 엘리먼트를 추가해줍니다.
<json-editor id="editor" theme="light" live="true"></json-editor>
기초적으로 웹 컴포넌트를 정의하는 방법은 다음과 같습니다.
import JsonEditor from './web-component.js'
// define component
customElements.define('json-editor', JsonEditor)
만약 자바스크립트로 엘리먼트를 삽입한다면 다음과 같이 코드를 작성하여 사용합니다.
const jsonEditor = document.createElement('json-editor')
jsonEditor.setAttribute('src', '{"foo": "bar"}')
jsonEditor.setAttribute('theme', 'system')
jsonEditor.setAttribute('live', 'true')
document.getElementById('target').append(jsonEditor)
-
src
: JSON.stringify 형태의 데이터 값 (마운트 하는 시점에만 사용합니다!) -
theme
: 다크모드에 대한 값 -
live
: 데이터가 업데이트 될때마다update
이벤트를 실행할지에 대한 여부
src
속성값과 에디터의 내용은 서로 분리되어 있기 때문에src
값이 변한다고 에디터에 자동으로 업데이트 되지 않습니다.
에디터의 내용은 그대로 두고 외부에서 에디터의 내용을 변경하려면change()
메서드를 사용하거나 라이브러리 메서드를 이용하는것을 권장드립니다.
데이터 내용을 변경합니다.
속성과 에디터의 내용을 강제로 변경하기 때문에 주의해주세요.
jsonEditor.change({ foo: 'bar' })
에디터 내용이 업데이트 되면 호출되는 이벤트
editor.addEventListener('update', (e) => {
console.log('update', e.detail)
})
컨텍스트 메뉴가 열릴때 호출되는 이벤트
jsonEditor.addEventListener('context', (e) => {
const { body, node, type, isRoot, $ } = e.detail
console.log('context', node)
})
에디터 코어 메서드나 요소에 접근하여 기능을 사용할 수 있습니다.
const element = document.querySelector('json-editor')
const data = element.core.export(true, 2)
console.log('export data', data)
마지막으로 테스트로 작성한 웹 컴포넌트를 불러오는 데모코드와 프로젝트 디렉토리 압축파일을 첨부로 남겨둡니다.
import JsonEditor from './web-component.js'
// define component
customElements.define('json-editor', JsonEditor)
const editor = document.getElementById('editor')
editor.core.replace({
foo: 'bar',
apple: 'red',
null: null,
bool: false,
})
// event - update
editor.addEventListener('update', ({ detail }) => {
console.log('update', detail)
})
// event - context
editor.addEventListener('context', ({ detail }) => {
const { body, node, type, isRoot, $ } = detail
console.log('context', node)
})
// export
const exportButton = document.getElementById('action-export')
exportButton.addEventListener('click', () => {
const src = editor.core.export(undefined, false)
console.log('export', src)
})