Skip to content

marpple/FxDOM

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

145 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

FxDOM

HTML DOM Bindings for the FxJS

Selector

<div class="container div1" active="true">
  <ul class="list1">
    <li class="item1">1</li>
    <li class="item2">2</li>
    <li class="item3">3</li>
  </ul>
  <div class="div2" active="true">
    <ul class="list2">
      <li class="item4">4</li>
      <li class="item5">5</li>
    </ul>
  </div>
</div>

$, $.all

$λŠ” document.querySelectorλ₯Ό μ‚¬μš©ν•˜κ³  $.all은 document.querySelectorAll을 μ‚¬μš©ν•©λ‹ˆλ‹€.

console.log($(".container li"));
// li.item1

console.log($.all(".container li"));
// NodeList(5)Β [li.item1, li.item2, li.item3, li.item4, li.item5]

$.find, $.findAll

$.findλŠ” el.querySelectorλ₯Ό μ‚¬μš©ν•˜κ³  $.findAll은 el.querySelectorAll을 μ‚¬μš©ν•©λ‹ˆλ‹€.

console.log($.find("li", $(".container div")));
// li.item4

console.log($.findAll("li", $(".container div")));
// NodeList(2)Β [li.item4, li.item5]

console.log($.find("li", $(".container")));
// li.item1

console.log($.findAll("li", $(".container")));
// NodeList(5)Β [li.item1, li.item2, li.item3, li.item4, li.item5]

console.log($.findAll("ul li", $(".container")));
// NodeList(5)Β [li.item1, li.item2, li.item3, li.item4, li.item5]

el.querySelectorλ‚˜ el.querySelectorAll의 μ•„μ‰¬μš΄μ 

el.querySelectorλ‚˜ el.querySelectorAll의 κ²½μš°λŠ” μ…€λ ‰ν„°μ˜ μ‹œμž‘μœΌλ‘œ >λ₯Ό μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

try {
  document.querySelector(".container").querySelectorAll("> ul li");
} catch (e) {
  console.log(e);
  // DOMException: Failed to execute 'querySelectorAll' on 'Element': '> ul li' is not a valid selector.
}

el.querySelectorλ‚˜ el.querySelectorAll의 κ²½μš°λŠ” μ…€λ ‰ν„°μ˜ μ‹œμž‘μ΄ λΆ€λͺ¨λ„ ν¬ν•¨ν•˜κ³ , μžμ‹μš”μ†Œλ„ ν¬ν•¨ν•œλ‹€λŠ” 점을 μœ μ˜ν•΄μ•Όν•©λ‹ˆλ‹€.

console.log(
  document.querySelector(".container").querySelectorAll("[active=true] > ul li")
);
// NodeList(5)Β [li.item1, li.item2, li.item3, li.item4, li.item5]

with >, with &

μ•„λž˜ μ˜ˆμ œλŠ” $.find, $.findAll와 el.querySelectorλ‚˜ el.querySelectorAll의 차이λ₯Ό λ³΄μ—¬μ€λ‹ˆλ‹€.

  • $.find, $.findAll은 >λ₯Ό μ…€λ ‰ν„°μ˜ μ‹œμž‘μœΌλ‘œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • &λ₯Ό 톡해 λΆ€λͺ¨ element에 λŒ€ν•΄μ„œλ§Œ μΆ”κ°€ 쑰건을 뢙일 수 μžˆμŠ΅λ‹ˆλ‹€.
console.log($.findAll("> ul li", $(".container")));
// NodeList(5)Β [li.item1, li.item2, li.item3]

console.log($.findAll('&[active="true"] li', $(".container")));
// NodeList(5)Β [li.item1, li.item2, li.item3, li.item4, li.item5]

console.log($.findAll('&[active="true"] > ul li', $(".container")));
// NodeList(5)Β [li.item1, li.item2, li.item3]

console.log($.findAll('&[active="false"] li', $(".container")));
// NodeList()Β []

$.closest

μžμ‹ μ„ ν¬ν•¨ν•˜μ—¬ 셀렉터와 λ§€μΉ­λ˜λŠ” λΆ€λͺ¨ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€.

console.log($.closest("li", $(".item4")));
// li.item4

console.log($.closest("ul", $(".item4")));
// ul.list2

console.log($.closest("div", $(".item4")));
// div.div2

console.log($.closest("div.container", $(".item4")));
// div.container.div1

$.children

$.prevAll

$.nextAll

$.prev

$.next

$.siblings

$.is

첫 번째 μΈμžμ— μ „λ‹¬λœ 셀렉터와 맀칭이 λ˜λŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€.

console.log($.is(".item1", $("li:nth-child(1)")));
// true

console.log($.is(".item1", $("li:nth-child(2)")));
// true

$.contains

Create

$.els

console.log($.els('<span class="s1">1</span>'));
// HTMLCollection(2)Β [span.s1]

console.log($.els('<span class="s1">1</span><span class="s2">2</span>'));
// HTMLCollection(2)Β [span.s1, span.s2]

$.el

console.log($.el('<span class="s1">1</span>'));
// span.s1

console.log($.el('<span class="s1">1</span><span class="s2">2</span>'));
// span.s1

Manipulation

$.appendTo

$.appendTo($(".comments"), $.el('<div class="comment">μƒˆ λŒ“κΈ€</div>'));

$.prependTo

$.prependTo($(".posts"), $.el('<div class="post">μƒˆ κΈ€</div>'));

$.append

$.append($.el('<div class="comment">μƒˆ λŒ“κΈ€</div>'), $(".comments"));

$.prepend

$.prepend($.el('<div class="post">μƒˆ κΈ€</div>'), $(".posts"));

$.before

$.insertBefore

$.after

$.insertAfter

$.replaceAll

$.replaceWith

$.remove

$.remove($(".post"));

$.text

console.log($.text($.el("<div>hi</div>")));
// "hi"

$.setText

console.log($.setText("ho", $.el("<div></div>")));
// HTMLDivElement <div>ho</div>

$.html

console.log($.html($.el("<div><span>hi</span></div>")));
// "<span>hi</span>"

$.setHTML

console.log($.setHTML("<span>ho</span>", $.el("<div></div>")));
// HTMLDivElement <div><span>ho</span></div>

$.outerHTML

console.log($.outerHTML($.el("<div><span>hi</span></div>")));
// "<div><span>hi</span></div>"

$.setOuterHTML

let el = $("#div1");
$.setOuterHTML('<div id="div1" class="hi2"></div>', el);
console.log($("#div1"));
// HTMLDivElement <div id="div1" class="hi2"></div>

$.val

console.log($.val($.el('<input type="text" value="hoho">')));
// "hoho"

$.setVal

console.log($.setVal("hoho", $.el('<input type="text">')).value);
// "hoho"

$.attr

console.log($.attr("type", $.el('<input type="text" value="hoho">')));
// "text"

$.setAttr

console.log($.setAttr({ status: "ho" }, $.el('<div status="hi">')));
// HTMLDivElement <div status="ho"></div>
console.log(
  $.setAttr({ status: "ho", class: "ye" }, $.el('<div status="hi">'))
);
// HTMLDivElement <div status="ho" class="ye"></div>
console.log($.setAttr(["status", "ho"], $.el('<div status="hi">')));
// HTMLDivElement <div status="ho"></div>
console.log($.setAttr({ status: "" }, $.el('<div status="hi">')));
// HTMLDivElement <div status></div>

$.removeAttr

console.log($.removeAttr("status", $.el('<div status="hi">')));
// HTMLDivElement <div></div>

$.prop

$.setProp

$.removeProp

CSS

$.addClass

console.log($.addClass("selected", $.el("div")));
// HTMLDivElement <div class="selected"></div>
console.log($.addClass("hi ho", $.el("div")));
// HTMLDivElement <div class="hi ho"></div>
console.log($.addClass("hi", $.el('<div class="ye">')));
// HTMLDivElement <div class="ye hi"></div>

$.removeClass

console.log($.removeClass("selected", $.el('<div class="selected"></div>')));
// HTMLDivElement <div class></div>
console.log($.removeClass("hi ho", $.el('<div class="hi ho"></div>')));
// HTMLDivElement <div class></div>
console.log($.removeClass("hi", $.el('<div class="ye hi">')));
// HTMLDivElement <div class="ye"></div>

$.toggleClass

console.log($.toggleClass("selected", $.el('<div class="selected"></div>')));
// HTMLDivElement <div class></div>

console.log($.toggleClass("selected", $.el("<div></div>")));
// HTMLDivElement <div class="selected"></div>

$.hasClass

console.log($.hasClass("selected", $.el('<div class="selected"></div>')));
// true

console.log($.hasClass("a", $.el('<div class="b"></div>')));
// false

$.css

$.setCss

$.show

$.hide

$.toggle

$.offset

console.log(
  $.offset(
    $.append(
      $("body"),
      $.setCss(
        {
          position: "absolute",
          top: "20px",
          left: "30px",
          "margin-top": "50px",
        },
        $.el("div")
      )
    )
  )
);
// { top: 70, left: 30 }

$.offsetParent

$.position

$.width

width

$.height

height

$.innerWidth

width + paddingLeft + paddingRight + borderLeft + borderRight

$.innerHeight

height + paddingTop + paddingBottom + borderTop + borderBottom

$.outerWidth

innerWidth + marginLeft + marginRight

$.outerHeight

innerHeight + marginTop + marginBottom

$.scrollTop

$.scrollLeft

$.setScrollTop

$.setScrollLeft

Event

$.on

$.on은 el.addEventListenerλ₯Ό λŒ€μ‹ ν•©λ‹ˆλ‹€. $.on은 이벀트λ₯Ό 등둝할 ν•¨μˆ˜λ₯Ό λ¦¬ν„΄ν•˜λ©°, 컀링 λ°©μ‹μœΌλ‘œλ§Œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • 인자둜 받은 ν•¨μˆ˜λ₯Ό μ‘°μž‘ν•˜μ§€ μ•Šκ³  el.addEventListener에 κ·ΈλŒ€λ‘œ μ μš©ν•˜μ—¬, 같은 μ—˜λ¦¬λ¨ΌνŠΈμ— 같은 μ΄λ²€νŠΈμ™€ 같은 ν•¨μˆ˜λ₯Ό 등둝이 λ˜μ§€ μ•ŠλŠ” el.addEventListener의 νŠΉμ§•μ„ κ·ΈλŒ€λ‘œ μœ μ§€ν–ˆμŠ΅λ‹ˆλ‹€.
  • el.addEventListener의 capture, passive λ“±μ˜ μ˜΅μ…˜μ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • e.preventDefault, e.stopPropagation을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • el.removeEventListener와 $.offλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
<button type="button" id="btn1">
  <span>btn1</span>
</button>
const addClickEvent = $.on("click", function (e) {
  console.log(e.currentTarget); // #btn1
  console.log(e.target); // span
});

addClickEvent($("#btn1"));
addClickEvent($("#btn1")); // 두 번 등둝해도 μΆ”κ°€λ‘œ λ“±λ‘λ˜μ§€ μ•ŠμŒ.
$.trigger("click", $("#btn1 span"));
// #btn1
// span

$.on의 두 번째 μΈμžμ— μ…€λ ‰ν„°λ₯Ό μ „λ‹¬ν•˜λ©΄ λ§€μΉ­λ˜λŠ” μžμ‹μš”μ†Œμ— 이벀트λ₯Ό λ“±λ‘ν•©λ‹ˆλ‹€. 이 방식은 μœ„μž„ 방식이 μ•„λ‹ˆλ©°, μ—­μ‹œ el.addEventListener의 μ£Όμš” νŠΉμ§•κ³Ό κΈ°λŠ₯을 λͺ¨λ‘ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

<div class="articles">
  <div class="article">
    <button type="button" class="remove"><span>μ‚­μ œ</span></button>
  </div>
  <div class="article">
    <button type="button" class="remove"><span>μ‚­μ œ</span></button>
  </div>
</div>
const Articles = {
  addEvents: pipe(
    $.on("click", ".article:nth-child(1)", function (e) {
      console.log(e.currentTarget);
    }),
    $.on(
      "click",
      ".article",
      function (e) {
        console.log(e.currentTarget);
      },
      { capture: true }
    ),
    $.on("click", ".remove", function (e) {
      console.log("other_data:", e.other_data);
      console.log(e.currentTarget);
    })
  ),
};

Articles.addEvents($(".articles"));

$.trigger("click", $(".articles .article:nth-child(1) .remove")); // ν•œ 번만 μ‹€ν–‰
// other_data: undefined
// button.remove
// div.article

$.trigger("click", $(".articles .article:nth-child(2) .remove"));
// div.article
// other_data: undefined
// button.remove

$.append(
  $(".articles"),
  $.el(`
  <div class="article new">
    <button type="button" class="remove"><span>μ‚­μ œ</span></button>
  </div>
`)
);

Articles.addEvents($(".articles"));

$.trigger("click", $(".articles .article:nth-child(1) .remove")); // ν•œ 번만 μ‹€ν–‰
// other_data: undefined
// button.remove
// div.article

$.trigger("click", $(".articles .article:nth-child(3) .remove"));
// div.article.new
// other_data: undefined
// button.remove

$.trigger(
  "click",
  { other_data: "hi" },
  $(".articles .article:nth-child(3) .remove")
);
// div.article.new
// other_data: hi
// button.remove

$.off

$.on에 μ „λ‹¬ν•œ λͺ¨λ“  인자λ₯Ό λ™μΌν•˜κ²Œ μ „λ‹¬ν•˜μ—¬ 이벀트λ₯Ό μ§€μšΈ 수 μžˆμŠ΅λ‹ˆλ‹€.

<button type="button" id="btn2"></button>
const eventArgs = [
  "click",
  function () {
    console.log("hi~");
  },
];
$.on(...eventArgs)($("#btn2"));
$.off(...eventArgs)($("#btn2"));
$.trigger("click", $("#btn2"));
// nothing

$.delegate

이벀트 μœ„μž„ λ°©μ‹μœΌλ‘œ 이벀트λ₯Ό λ“±λ‘ν•©λ‹ˆλ‹€. 이벀트λ₯Ό λ“±λ‘ν•˜κ³ μž ν•˜λŠ” μ—˜λ¦¬λ¨ΌνŠΈκ°€ λ™μ μœΌλ‘œ κ°„νŽΈν•˜κ²Œ 이벀트λ₯Ό λ“±λ‘ν•΄λ‘˜ 수 μžˆμŠ΅λ‹ˆλ‹€.

<div class="users"></div>
go(
  $(".users"),
  $.delegate("click", ".remove", function () {
    console.log("remove user");
  })
);

$.append(
  $(".users"),
  $.el(`
  <div class="user new">
    <button type="button" class="remove"><span>μ‚­μ œ</span></button>
  </div>
`)
);

$.trigger("click", $(".users .remove"));
// remove user

이벀트 μœ„μž„ 방식은 μ•„λž˜μ™€ 같은 μ˜΅μ…˜λ“€μ„ μ‚¬μš©ν•  ν•„μš”κ°€ μ—†λŠ” 상황에 ν•œν•˜μ—¬ μ‚¬μš©ν•˜λŠ” 것을 ꢌμž₯ν•©λ‹ˆλ‹€.

  • el.addEventListener의 capture, passive λ“±μ˜ μ˜΅μ…˜μ„ μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.
  • e.preventDefault, e.stopPropagation을 μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.
  • el.removeEventListener와 $.offλ₯Ό μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.
  • mouseleave, mouseenterλŠ” 정상 λ™μž‘ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

don.jsμ—μ„œλŠ” 이벀트 μœ„μž„ λ°©μ‹μ—μ„œ μœ„ κΈ°λŠ₯듀을 λͺ¨λ‘ κ΅¬ν˜„ν•˜μ—¬ μ œκ³΅ν–ˆμ§€λ§Œ, 사싀상 λΈŒλΌμš°μ €μ˜ μ΄λ²€νŠΈμ— λŒ€ν•œ λͺ¨λ“  λ™μž‘μ„ 라이브러리 μœ„μ— λ‹€μ‹œ κ΅¬ν˜„ν•˜λŠ” μž₯ν™©ν•œ μ½”λ“œλ“€μ΄ ν•„μš”ν•˜λ©°, κ²½ν—˜μƒ κ·Έ μ‹€μš©μ„±μ΄ λ–¨μ–΄μ§„λ‹€κ³  μƒκ°ν•˜μ—¬ FxDOM은 ν•΄λ‹Ή κΈ°λŠ₯을 κ΅¬ν˜„ν•˜μ§€ μ•ŠλŠ” μ»¨μ…‰μœΌλ‘œ κ°€κ³ μž ν•©λ‹ˆλ‹€.

$.delegate + & μ‘μš©

<div class="signup" agree="false">
  <input type="checkbox" />
  <button type="button">κ°€μž…</button>
</div>
go(
  $(".signup"),
  $.delegate("change", "input", function (e) {
    $.setAttr({ agree: e.currentTarget.checked }, e.delegateTarget);
  }),
  $.delegate("click", '&[agree="false"] button', function () {
    console.log("λ™μ˜ν•΄μ£Όμ„Έμš”!");
  }),
  $.delegate("click", '&[agree="true"] button', function () {
    console.log("κ°μ‚¬ν•©λ‹ˆλ‹€!");
  })
);

$.trigger("click", $(".signup button"));
// λ™μ˜ν•΄μ£Όμ„Έμš”!
$.trigger("click", $(".signup input"));
$.trigger("click", $(".signup button"));
// κ°μ‚¬ν•©λ‹ˆλ‹€!

$.ready

Data

$.data, $.setData

<div class="item" data-fx-json='{"id": 1, "active": true}'></div>
<div class="item2"></div>
const { id, active } = $.data($(".item"));
console.log(id, active);
// 1 true

const data = $.data($.setData({ id: 1, active: false }, $(".item")));
console.log(data.active);
// false
data.active = true;
console.log($.data($(".item")).active);
// true

$.dataStr

const data = { id: 1, active: true };
const item = document.createElement(
  `<div class="item" data-fx-json="${$.dataStr(data)}">`
);

const { id, active } = $.data(item);
console.log(id, active);
// 1 true

Fetch

$.get, $.post, $.put, $.delete의 Content-Type은 application/json으둜 μ„€μ •λ˜μ–΄μžˆμœΌλ©° 응닡이 였면 JSON 객체λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. 4개 ν•¨μˆ˜ λͺ¨λ‘ ν•„μš” μΈμžλŠ” 2개 이상이며, 인자λ₯Ό 1개만 μ „λ‹¬ν•˜λ©΄ ν•¨μˆ˜λ₯Ό λ¦¬ν„΄ν•©λ‹ˆλ‹€.

$.get

$.get("/api/posts", { offset: 0, limit: 10 }); // GET '/api/posts?offset=0&limit10'
// Promise [{id: 1, ...}, {id: 2, ...}, ...]

$.post

$.post("/api/posts", { content: "ho~" }); // POST /api/posts, BODY { content: 'ho~' }
// Promise {id:1, content: 'ho', created_at: ... }

$.put

$.put(`/api/posts/${post.id}`, post); // PUT /api/posts/1, BODY { id: 1, ... }
// Promise {id:1, content: 'ho', updated_at: ... }

$.delete

$.delete(`/api/posts/${post.id}`, undefined); // DELETE /api/posts/1

About

HTML DOM Bindings for the Functional Extensions for Javascript

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors