{"id":26064504,"url":"https://github.com/marpple/fxdom","last_synced_at":"2025-04-11T13:37:32.952Z","repository":{"id":33015481,"uuid":"149845007","full_name":"marpple/FxDOM","owner":"marpple","description":"HTML DOM Bindings for the Functional Extensions for Javascript","archived":false,"fork":false,"pushed_at":"2024-04-15T08:36:12.000Z","size":1599,"stargazers_count":57,"open_issues_count":6,"forks_count":6,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-09T20:07:05.237Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marpple.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-09-22T04:25:30.000Z","updated_at":"2025-03-15T14:41:49.000Z","dependencies_parsed_at":"2024-01-14T05:00:15.174Z","dependency_job_id":"342f6bd4-111e-472c-90f5-de40d7efe85a","html_url":"https://github.com/marpple/FxDOM","commit_stats":null,"previous_names":["marpple/fxjs-dom"],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marpple%2FFxDOM","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marpple%2FFxDOM/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marpple%2FFxDOM/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marpple%2FFxDOM/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marpple","download_url":"https://codeload.github.com/marpple/FxDOM/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248410303,"owners_count":21098774,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-08T18:13:25.673Z","updated_at":"2025-04-11T13:37:32.931Z","avatar_url":"https://github.com/marpple.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FxDOM\n\nHTML DOM Bindings for the [FxJS](https://github.com/marpple/FxJS)\n\n- [Selector](#selector)\n- [Create](#create)\n- [Manipulation](#manipulation)\n- [CSS](#css)\n- [Event](#event)\n- [Data](#data)\n- [Fetch](#fetch)\n\n## Selector\n\n```html\n\u003cdiv class=\"container div1\" active=\"true\"\u003e\n  \u003cul class=\"list1\"\u003e\n    \u003cli class=\"item1\"\u003e1\u003c/li\u003e\n    \u003cli class=\"item2\"\u003e2\u003c/li\u003e\n    \u003cli class=\"item3\"\u003e3\u003c/li\u003e\n  \u003c/ul\u003e\n  \u003cdiv class=\"div2\" active=\"true\"\u003e\n    \u003cul class=\"list2\"\u003e\n      \u003cli class=\"item4\"\u003e4\u003c/li\u003e\n      \u003cli class=\"item5\"\u003e5\u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n### $, $.all\n\n`$`는 `document.querySelector`를 사용하고 `$.all`은 `document.querySelectorAll`을 사용합니다.\n\n```javascript\nconsole.log($(\".container li\"));\n// li.item1\n\nconsole.log($.all(\".container li\"));\n// NodeList(5) [li.item1, li.item2, li.item3, li.item4, li.item5]\n```\n\n### $.find, $.findAll\n\n`$.find`는 `el.querySelector`를 사용하고 `$.findAll`은 `el.querySelectorAll`을 사용합니다.\n\n```javascript\nconsole.log($.find(\"li\", $(\".container div\")));\n// li.item4\n\nconsole.log($.findAll(\"li\", $(\".container div\")));\n// NodeList(2) [li.item4, li.item5]\n\nconsole.log($.find(\"li\", $(\".container\")));\n// li.item1\n\nconsole.log($.findAll(\"li\", $(\".container\")));\n// NodeList(5) [li.item1, li.item2, li.item3, li.item4, li.item5]\n\nconsole.log($.findAll(\"ul li\", $(\".container\")));\n// NodeList(5) [li.item1, li.item2, li.item3, li.item4, li.item5]\n```\n\n#### `el.querySelector`나 `el.querySelectorAll`의 아쉬운점\n\n`el.querySelector`나 `el.querySelectorAll`의 경우는 셀렉터의 시작으로 `\u003e`를 사용할 수 없습니다.\n\n```javascript\ntry {\n  document.querySelector(\".container\").querySelectorAll(\"\u003e ul li\");\n} catch (e) {\n  console.log(e);\n  // DOMException: Failed to execute 'querySelectorAll' on 'Element': '\u003e ul li' is not a valid selector.\n}\n```\n\n`el.querySelector`나 `el.querySelectorAll`의 경우는 셀렉터의 시작이 부모도 포함하고, 자식요소도 포함한다는 점을 유의해야합니다.\n\n```javascript\nconsole.log(\n  document.querySelector(\".container\").querySelectorAll(\"[active=true] \u003e ul li\")\n);\n// NodeList(5) [li.item1, li.item2, li.item3, li.item4, li.item5]\n```\n\n#### with \u003e, with \u0026\n\n아래 예제는 `$.find`, `$.findAll`와 `el.querySelector`나 `el.querySelectorAll`의 차이를 보여줍니다.\n\n- `$.find, $.findAll`은 `\u003e`를 셀렉터의 시작으로 사용할 수 있습니다.\n- `\u0026`를 통해 부모 element에 대해서만 추가 조건을 붙일 수 있습니다.\n\n```javascript\nconsole.log($.findAll(\"\u003e ul li\", $(\".container\")));\n// NodeList(5) [li.item1, li.item2, li.item3]\n\nconsole.log($.findAll('\u0026[active=\"true\"] li', $(\".container\")));\n// NodeList(5) [li.item1, li.item2, li.item3, li.item4, li.item5]\n\nconsole.log($.findAll('\u0026[active=\"true\"] \u003e ul li', $(\".container\")));\n// NodeList(5) [li.item1, li.item2, li.item3]\n\nconsole.log($.findAll('\u0026[active=\"false\"] li', $(\".container\")));\n// NodeList() []\n```\n\n### \\$.closest\n\n자신을 포함하여 셀렉터와 매칭되는 부모 엘리먼트를 찾습니다.\n\n```javascript\nconsole.log($.closest(\"li\", $(\".item4\")));\n// li.item4\n\nconsole.log($.closest(\"ul\", $(\".item4\")));\n// ul.list2\n\nconsole.log($.closest(\"div\", $(\".item4\")));\n// div.div2\n\nconsole.log($.closest(\"div.container\", $(\".item4\")));\n// div.container.div1\n```\n\n### \\$.children\n\n### \\$.prevAll\n\n### \\$.nextAll\n\n### \\$.prev\n\n### \\$.next\n\n### \\$.siblings\n\n### \\$.is\n\n첫 번째 인자에 전달된 셀렉터와 매칭이 되는지 확인합니다.\n\n```javascript\nconsole.log($.is(\".item1\", $(\"li:nth-child(1)\")));\n// true\n\nconsole.log($.is(\".item1\", $(\"li:nth-child(2)\")));\n// true\n```\n\n### \\$.contains\n\n## Create\n\n### \\$.els\n\n```javascript\nconsole.log($.els('\u003cspan class=\"s1\"\u003e1\u003c/span\u003e'));\n// HTMLCollection(2) [span.s1]\n\nconsole.log($.els('\u003cspan class=\"s1\"\u003e1\u003c/span\u003e\u003cspan class=\"s2\"\u003e2\u003c/span\u003e'));\n// HTMLCollection(2) [span.s1, span.s2]\n```\n\n### \\$.el\n\n```javascript\nconsole.log($.el('\u003cspan class=\"s1\"\u003e1\u003c/span\u003e'));\n// span.s1\n\nconsole.log($.el('\u003cspan class=\"s1\"\u003e1\u003c/span\u003e\u003cspan class=\"s2\"\u003e2\u003c/span\u003e'));\n// span.s1\n```\n\n## Manipulation\n\n### \\$.appendTo\n\n```javascript\n$.appendTo($(\".comments\"), $.el('\u003cdiv class=\"comment\"\u003e새 댓글\u003c/div\u003e'));\n```\n\n### \\$.prependTo\n\n```javascript\n$.prependTo($(\".posts\"), $.el('\u003cdiv class=\"post\"\u003e새 글\u003c/div\u003e'));\n```\n\n### \\$.append\n\n```javascript\n$.append($.el('\u003cdiv class=\"comment\"\u003e새 댓글\u003c/div\u003e'), $(\".comments\"));\n```\n\n### \\$.prepend\n\n```javascript\n$.prepend($.el('\u003cdiv class=\"post\"\u003e새 글\u003c/div\u003e'), $(\".posts\"));\n```\n\n### \\$.before\n\n### \\$.insertBefore\n\n### \\$.after\n\n### \\$.insertAfter\n\n### \\$.replaceAll\n\n### \\$.replaceWith\n\n### \\$.remove\n\n```javascript\n$.remove($(\".post\"));\n```\n\n### \\$.text\n\n```javascript\nconsole.log($.text($.el(\"\u003cdiv\u003ehi\u003c/div\u003e\")));\n// \"hi\"\n```\n\n### \\$.setText\n\n```javascript\nconsole.log($.setText(\"ho\", $.el(\"\u003cdiv\u003e\u003c/div\u003e\")));\n// HTMLDivElement \u003cdiv\u003eho\u003c/div\u003e\n```\n\n### \\$.html\n\n```javascript\nconsole.log($.html($.el(\"\u003cdiv\u003e\u003cspan\u003ehi\u003c/span\u003e\u003c/div\u003e\")));\n// \"\u003cspan\u003ehi\u003c/span\u003e\"\n```\n\n### \\$.setHTML\n\n```javascript\nconsole.log($.setHTML(\"\u003cspan\u003eho\u003c/span\u003e\", $.el(\"\u003cdiv\u003e\u003c/div\u003e\")));\n// HTMLDivElement \u003cdiv\u003e\u003cspan\u003eho\u003c/span\u003e\u003c/div\u003e\n```\n\n### \\$.outerHTML\n\n```javascript\nconsole.log($.outerHTML($.el(\"\u003cdiv\u003e\u003cspan\u003ehi\u003c/span\u003e\u003c/div\u003e\")));\n// \"\u003cdiv\u003e\u003cspan\u003ehi\u003c/span\u003e\u003c/div\u003e\"\n```\n\n### \\$.setOuterHTML\n\n\u003cdiv id=\"div1\"\u003e\u003c/div\u003e\n\n```javascript\nlet el = $(\"#div1\");\n$.setOuterHTML('\u003cdiv id=\"div1\" class=\"hi2\"\u003e\u003c/div\u003e', el);\nconsole.log($(\"#div1\"));\n// HTMLDivElement \u003cdiv id=\"div1\" class=\"hi2\"\u003e\u003c/div\u003e\n```\n\n### \\$.val\n\n```javascript\nconsole.log($.val($.el('\u003cinput type=\"text\" value=\"hoho\"\u003e')));\n// \"hoho\"\n```\n\n### \\$.setVal\n\n```javascript\nconsole.log($.setVal(\"hoho\", $.el('\u003cinput type=\"text\"\u003e')).value);\n// \"hoho\"\n```\n\n### \\$.attr\n\n```javascript\nconsole.log($.attr(\"type\", $.el('\u003cinput type=\"text\" value=\"hoho\"\u003e')));\n// \"text\"\n```\n\n### \\$.setAttr\n\n```javascript\nconsole.log($.setAttr({ status: \"ho\" }, $.el('\u003cdiv status=\"hi\"\u003e')));\n// HTMLDivElement \u003cdiv status=\"ho\"\u003e\u003c/div\u003e\nconsole.log(\n  $.setAttr({ status: \"ho\", class: \"ye\" }, $.el('\u003cdiv status=\"hi\"\u003e'))\n);\n// HTMLDivElement \u003cdiv status=\"ho\" class=\"ye\"\u003e\u003c/div\u003e\nconsole.log($.setAttr([\"status\", \"ho\"], $.el('\u003cdiv status=\"hi\"\u003e')));\n// HTMLDivElement \u003cdiv status=\"ho\"\u003e\u003c/div\u003e\nconsole.log($.setAttr({ status: \"\" }, $.el('\u003cdiv status=\"hi\"\u003e')));\n// HTMLDivElement \u003cdiv status\u003e\u003c/div\u003e\n```\n\n### \\$.removeAttr\n\n```javascript\nconsole.log($.removeAttr(\"status\", $.el('\u003cdiv status=\"hi\"\u003e')));\n// HTMLDivElement \u003cdiv\u003e\u003c/div\u003e\n```\n\n### \\$.prop\n\n### \\$.setProp\n\n### \\$.removeProp\n\n## CSS\n\n### \\$.addClass\n\n```javascript\nconsole.log($.addClass(\"selected\", $.el(\"div\")));\n// HTMLDivElement \u003cdiv class=\"selected\"\u003e\u003c/div\u003e\nconsole.log($.addClass(\"hi ho\", $.el(\"div\")));\n// HTMLDivElement \u003cdiv class=\"hi ho\"\u003e\u003c/div\u003e\nconsole.log($.addClass(\"hi\", $.el('\u003cdiv class=\"ye\"\u003e')));\n// HTMLDivElement \u003cdiv class=\"ye hi\"\u003e\u003c/div\u003e\n```\n\n### \\$.removeClass\n\n```javascript\nconsole.log($.removeClass(\"selected\", $.el('\u003cdiv class=\"selected\"\u003e\u003c/div\u003e')));\n// HTMLDivElement \u003cdiv class\u003e\u003c/div\u003e\nconsole.log($.removeClass(\"hi ho\", $.el('\u003cdiv class=\"hi ho\"\u003e\u003c/div\u003e')));\n// HTMLDivElement \u003cdiv class\u003e\u003c/div\u003e\nconsole.log($.removeClass(\"hi\", $.el('\u003cdiv class=\"ye hi\"\u003e')));\n// HTMLDivElement \u003cdiv class=\"ye\"\u003e\u003c/div\u003e\n```\n\n### \\$.toggleClass\n\n```javascript\nconsole.log($.toggleClass(\"selected\", $.el('\u003cdiv class=\"selected\"\u003e\u003c/div\u003e')));\n// HTMLDivElement \u003cdiv class\u003e\u003c/div\u003e\n\nconsole.log($.toggleClass(\"selected\", $.el(\"\u003cdiv\u003e\u003c/div\u003e\")));\n// HTMLDivElement \u003cdiv class=\"selected\"\u003e\u003c/div\u003e\n```\n\n### \\$.hasClass\n\n```javascript\nconsole.log($.hasClass(\"selected\", $.el('\u003cdiv class=\"selected\"\u003e\u003c/div\u003e')));\n// true\n\nconsole.log($.hasClass(\"a\", $.el('\u003cdiv class=\"b\"\u003e\u003c/div\u003e')));\n// false\n```\n\n### \\$.css\n\n### \\$.setCss\n\n### \\$.show\n\n### \\$.hide\n\n### \\$.toggle\n\n### \\$.offset\n\n```javascript\nconsole.log(\n  $.offset(\n    $.append(\n      $(\"body\"),\n      $.setCss(\n        {\n          position: \"absolute\",\n          top: \"20px\",\n          left: \"30px\",\n          \"margin-top\": \"50px\",\n        },\n        $.el(\"div\")\n      )\n    )\n  )\n);\n// { top: 70, left: 30 }\n```\n\n### \\$.offsetParent\n\n### \\$.position\n\n### \\$.width\n\nwidth\n\n### \\$.height\n\nheight\n\n### \\$.innerWidth\n\nwidth + paddingLeft + paddingRight + borderLeft + borderRight\n\n### \\$.innerHeight\n\nheight + paddingTop + paddingBottom + borderTop + borderBottom\n\n### \\$.outerWidth\n\ninnerWidth + marginLeft + marginRight\n\n### \\$.outerHeight\n\ninnerHeight + marginTop + marginBottom\n\n### \\$.scrollTop\n\n### \\$.scrollLeft\n\n### \\$.setScrollTop\n\n### \\$.setScrollLeft\n\n## Event\n\n### \\$.on\n\n`$.on`은 `el.addEventListener`를 대신합니다. `$.on`은 이벤트를 등록할 함수를 리턴하며, 커링 방식으로만 사용할 수 있습니다.\n\n- 인자로 받은 함수를 조작하지 않고 `el.addEventListener`에 그대로 적용하여, 같은 엘리먼트에 같은 이벤트와 같은 함수를 등록이 되지 않는 `el.addEventListener`의 특징을 그대로 유지했습니다.\n- `el.addEventListener`의 `capture`, `passive` 등의 옵션을 사용할 수 있습니다.\n- `e.preventDefault`, `e.stopPropagation`을 사용할 수 있습니다.\n- `el.removeEventListener`와 `$.off`를 사용할 수 있습니다.\n\n```html\n\u003cbutton type=\"button\" id=\"btn1\"\u003e\n  \u003cspan\u003ebtn1\u003c/span\u003e\n\u003c/button\u003e\n```\n\n```javascript\nconst addClickEvent = $.on(\"click\", function (e) {\n  console.log(e.currentTarget); // #btn1\n  console.log(e.target); // span\n});\n\naddClickEvent($(\"#btn1\"));\naddClickEvent($(\"#btn1\")); // 두 번 등록해도 추가로 등록되지 않음.\n$.trigger(\"click\", $(\"#btn1 span\"));\n// #btn1\n// span\n```\n\n`$.on`의 두 번째 인자에 셀렉터를 전달하면 매칭되는 자식요소에 이벤트를 등록합니다. 이 방식은 위임 방식이 아니며, 역시 `el.addEventListener`의 주요 특징과 기능을 모두 사용할 수 있습니다.\n\n```html\n\u003cdiv class=\"articles\"\u003e\n  \u003cdiv class=\"article\"\u003e\n    \u003cbutton type=\"button\" class=\"remove\"\u003e\u003cspan\u003e삭제\u003c/span\u003e\u003c/button\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"article\"\u003e\n    \u003cbutton type=\"button\" class=\"remove\"\u003e\u003cspan\u003e삭제\u003c/span\u003e\u003c/button\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n```javascript\nconst Articles = {\n  addEvents: pipe(\n    $.on(\"click\", \".article:nth-child(1)\", function (e) {\n      console.log(e.currentTarget);\n    }),\n    $.on(\n      \"click\",\n      \".article\",\n      function (e) {\n        console.log(e.currentTarget);\n      },\n      { capture: true }\n    ),\n    $.on(\"click\", \".remove\", function (e) {\n      console.log(\"other_data:\", e.other_data);\n      console.log(e.currentTarget);\n    })\n  ),\n};\n\nArticles.addEvents($(\".articles\"));\n\n$.trigger(\"click\", $(\".articles .article:nth-child(1) .remove\")); // 한 번만 실행\n// other_data: undefined\n// button.remove\n// div.article\n\n$.trigger(\"click\", $(\".articles .article:nth-child(2) .remove\"));\n// div.article\n// other_data: undefined\n// button.remove\n\n$.append(\n  $(\".articles\"),\n  $.el(`\n  \u003cdiv class=\"article new\"\u003e\n    \u003cbutton type=\"button\" class=\"remove\"\u003e\u003cspan\u003e삭제\u003c/span\u003e\u003c/button\u003e\n  \u003c/div\u003e\n`)\n);\n\nArticles.addEvents($(\".articles\"));\n\n$.trigger(\"click\", $(\".articles .article:nth-child(1) .remove\")); // 한 번만 실행\n// other_data: undefined\n// button.remove\n// div.article\n\n$.trigger(\"click\", $(\".articles .article:nth-child(3) .remove\"));\n// div.article.new\n// other_data: undefined\n// button.remove\n\n$.trigger(\n  \"click\",\n  { other_data: \"hi\" },\n  $(\".articles .article:nth-child(3) .remove\")\n);\n// div.article.new\n// other_data: hi\n// button.remove\n```\n\n### \\$.off\n\n`$.on`에 전달한 모든 인자를 동일하게 전달하여 이벤트를 지울 수 있습니다.\n\n```html\n\u003cbutton type=\"button\" id=\"btn2\"\u003e\u003c/button\u003e\n```\n\n```javascript\nconst eventArgs = [\n  \"click\",\n  function () {\n    console.log(\"hi~\");\n  },\n];\n$.on(...eventArgs)($(\"#btn2\"));\n$.off(...eventArgs)($(\"#btn2\"));\n$.trigger(\"click\", $(\"#btn2\"));\n// nothing\n```\n\n### \\$.delegate\n\n이벤트 위임 방식으로 이벤트를 등록합니다. 이벤트를 등록하고자 하는 엘리먼트가 동적으로 간편하게 이벤트를 등록해둘 수 있습니다.\n\n```html\n\u003cdiv class=\"users\"\u003e\u003c/div\u003e\n```\n\n```javascript\ngo(\n  $(\".users\"),\n  $.delegate(\"click\", \".remove\", function () {\n    console.log(\"remove user\");\n  })\n);\n\n$.append(\n  $(\".users\"),\n  $.el(`\n  \u003cdiv class=\"user new\"\u003e\n    \u003cbutton type=\"button\" class=\"remove\"\u003e\u003cspan\u003e삭제\u003c/span\u003e\u003c/button\u003e\n  \u003c/div\u003e\n`)\n);\n\n$.trigger(\"click\", $(\".users .remove\"));\n// remove user\n```\n\n이벤트 위임 방식은 아래와 같은 옵션들을 사용할 필요가 없는 상황에 한하여 사용하는 것을 권장합니다.\n\n- `el.addEventListener`의 `capture`, `passive` 등의 옵션을 사용할 수 없습니다.\n- `e.preventDefault`, `e.stopPropagation`을 사용할 수 없습니다.\n- `el.removeEventListener`와 `$.off`를 사용할 수 없습니다.\n- `mouseleave`, `mouseenter`는 정상 동작하지 않습니다.\n\n[don.js](https://github.com/marpple/don.js)에서는 이벤트 위임 방식에서 위 기능들을 모두 구현하여 제공했지만, 사실상 브라우저의 이벤트에 대한 모든 동작을 라이브러리 위에 다시 구현하는 장황한 코드들이 필요하며, 경험상 그 실용성이 떨어진다고 생각하여 FxDOM은 해당 기능을 구현하지 않는 컨셉으로 가고자 합니다.\n\n### \\$.delegate + \u0026 응용\n\n```html\n\u003cdiv class=\"signup\" agree=\"false\"\u003e\n  \u003cinput type=\"checkbox\" /\u003e\n  \u003cbutton type=\"button\"\u003e가입\u003c/button\u003e\n\u003c/div\u003e\n```\n\n```javascript\ngo(\n  $(\".signup\"),\n  $.delegate(\"change\", \"input\", function (e) {\n    $.setAttr({ agree: e.currentTarget.checked }, e.delegateTarget);\n  }),\n  $.delegate(\"click\", '\u0026[agree=\"false\"] button', function () {\n    console.log(\"동의해주세요!\");\n  }),\n  $.delegate(\"click\", '\u0026[agree=\"true\"] button', function () {\n    console.log(\"감사합니다!\");\n  })\n);\n\n$.trigger(\"click\", $(\".signup button\"));\n// 동의해주세요!\n$.trigger(\"click\", $(\".signup input\"));\n$.trigger(\"click\", $(\".signup button\"));\n// 감사합니다!\n```\n\n### \\$.ready\n\n## Data\n\n### $.data, $.setData\n\n```html\n\u003cdiv class=\"item\" data-fx-json='{\"id\": 1, \"active\": true}'\u003e\u003c/div\u003e\n\u003cdiv class=\"item2\"\u003e\u003c/div\u003e\n```\n\n```javascript\nconst { id, active } = $.data($(\".item\"));\nconsole.log(id, active);\n// 1 true\n\nconst data = $.data($.setData({ id: 1, active: false }, $(\".item\")));\nconsole.log(data.active);\n// false\ndata.active = true;\nconsole.log($.data($(\".item\")).active);\n// true\n```\n\n### \\$.dataStr\n\n```javascript\nconst data = { id: 1, active: true };\nconst item = document.createElement(\n  `\u003cdiv class=\"item\" data-fx-json=\"${$.dataStr(data)}\"\u003e`\n);\n\nconst { id, active } = $.data(item);\nconsole.log(id, active);\n// 1 true\n```\n\n## Fetch\n\n`$.get, $.post, $.put, $.delete`의 `Content-Type`은 `application/json`으로 설정되어있으며 응답이 오면 JSON 객체를 반환합니다. 4개 함수 모두 필요 인자는 2개 이상이며, 인자를 1개만 전달하면 함수를 리턴합니다.\n\n### \\$.get\n\n```javascript\n$.get(\"/api/posts\", { offset: 0, limit: 10 }); // GET '/api/posts?offset=0\u0026limit10'\n// Promise [{id: 1, ...}, {id: 2, ...}, ...]\n```\n\n### \\$.post\n\n```javascript\n$.post(\"/api/posts\", { content: \"ho~\" }); // POST /api/posts, BODY { content: 'ho~' }\n// Promise {id:1, content: 'ho', created_at: ... }\n```\n\n### \\$.put\n\n```javascript\n$.put(`/api/posts/${post.id}`, post); // PUT /api/posts/1, BODY { id: 1, ... }\n// Promise {id:1, content: 'ho', updated_at: ... }\n```\n\n### \\$.delete\n\n```javascript\n$.delete(`/api/posts/${post.id}`, undefined); // DELETE /api/posts/1\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarpple%2Ffxdom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarpple%2Ffxdom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarpple%2Ffxdom/lists"}