body overflow:hidden 이 모바일에서 안 먹을때 javascript로 해결방법

스크린샷 2017-05-09 오후 9.21.17

상황: 모바일에서 사이드 네비게이션이 열린 상태에서 스크롤시 body는 스크롤 되지 않게 하고싶다

Solution A: CSS

html,
body {
    overflow: hidden;
    position: relative;
    height: 100%;
}

PC에선 문제 없이 작동한다. 하지만 iOS 사파리랑 크롬에서는 무용지물.

Solution B: CSS – fix

body {
    position: fixed;
    width: 100%;
    height: 100%;
}

PC, 모바일 모두 되긴 하는데 Side nav를 닫은 후에는 position이 꼬임 -> DOM 클릭해도 이벤트가 활성화 안된다.

Solution C: jQuery

<body>
<div id="side-nav">사이드 네비게이션</div>
<div class="contents">여기에 body의 내용 넣는다</div>
</body>
$(function(){
    $('#side-nav').on('show.bs.offcanvas', function (e) {
      $('#sidenav-overlay').addClass('active');

      /* Disable scroll */
      $('.contents').on('scroll touchmove mousewheel', function(e){
        e.preventDefault();
        e.stopPropagation();
        return false;
      });
    });
    $('#sidenav-overlay').click(function() {
      $('#side-nav').offcanvas('hide');
      $('#sidenav-overlay').removeClass('active');

      /* Enable scroll */
      $('.contents').off('scroll touchmove mousewheel');
    });
  });

jQuery on handler로 스크롤을 막는다.
HTML에서 사이드 네비게이션과 Contents 영역을 분간해두면
사이드 네비게이션 자체에서는 스크롤 가능하게 할 수 있다.

Refer

http://stackoverflow.com/questions/3656592/how-to-programmatically-disable-page-scrolling-with-jquery

Javascript, jQuery로 element의 index 구하기

개요

Google Analytics에서 dataLayer를 사용하는데, 제품 노출을 전달할 때 그 제품의 index를 넘겨야 한다.
하지만 tagmanager를 사용하기 위한 dataLayer는 body여는태그 바로 뒤에 삽입해서 jQuery보다 먼저 호출되고만다.

<ul class="product">
  <li class="product">
    <div class="product">
      <div class="product-image">
        <a href="/13"></a>
      </div>
      <div class="product-content">
      </div>
    </div>
  </li>
  <li class="product">...</li>
  <li class="product">...</li>
</ul>

여기서 상품번호 별 li의 index를 어떻게 가져올까?

jQuery

jQuery로는 간단하다.

var position = $('.product-image a[href='/' + {{ product.id }} + '/']&').closest('li.product').index() + 1;

하지만 jQuery를 못 쓰는게 함정

javascript

스택오버플로우에서 루프를 돌지 않고 요소의 index를 받는 함수를 올려놓은 답변을 찾았다.

function getChildNumber(node) {
  return Array.prototype.indexOf.call(node.parentNode.childNodes, node);
}

하지만 내 코드에선 1, 3, 5, 7로 찍혀 나와서 2로 나누고 반올림 해서 수정했다.

function getChildNumber(node) {
  return Math.ceil(Array.prototype.indexOf.call(node.parentNode.childNodes, node)/2);
}

그래서 완성 코드는 이렇게 되었다.

var position = getChildNumber(document.querySelector('.product-image a[href='/' + {{ product.id }} + '/']').parentNode.parentNode.parentNode);

jQuery의 closest같은 경우는 이렇게 구현할 수도 있는데 짜피 한번 쓸거라 걍 parentNode로 올라갔다.

결과

근데 html dom보다 dataLayer가 먼저 불려서 돔 위치를 파악할 수 없어서 결국 fail. 담에 더 파봐야겠다…

(+)160111 추가 내용

jQuery를 GTM 스니펫 위로 올리고, dom ready이후에 추가되는 것들은

$(function() {
 ...
});

제이쿼리로 dom이 만들어진 후에 불리도록 넣었다.

Refer

http://stackoverflow.com/questions/4649699/is-it-possible-to-get-elements-numerical-index-in-its-parent-node-without-loopi
http://stackoverflow.com/questions/22100853/dom-pure-javascript-solution-to-jquery-closest-implementation

[jquery] 브라우저 시작 지점 바꾸기

jQuery

jquery로 하면 크로스브라우징 할 필요 없이 간단하다.

var app_offset_top = $('.article-apps').offset().top;
$(window).scrollTop(app_offset_top);

javascript

창 위치를 판단하는 크로스 브라우저 코드 (IE, 오페라 vs 파이어폭스, 사파리/크롬은 양쪽 지원)

var leftPos = (typeof window.screenLeft "number") ? window.screenLeft : window.screenX;
var topPos = (typeof window.screenTop "number") ? window.screenTop : window.screenY;

이 짓 하고 있었는데 멘토님이 지나가시다가 “jquery쓰세요”하시며 알려주셨다.

Event delegation (Javascript, jQuery)

Event Delegation

  • child element각각에 이벤트 핸들러를 달지 않고
  • parent element에 단 뒤 이벤트가 발생한 노드를 필터링해 처리.
<JS>
document.getElementById('myTd').addEventListener( 'click', function() {
   //you code goes here...
}, false );

<HTML>
<table id="myTable">
   <tbody>
      <tr>
         <td id="myTd">1, 1</td>
         <td>1, 2</td>
      </tr> 
      <tr>
         <td>2, 1</td>
         <td>2, 2</td>
      </tr>
   </tbody>
</table>

myTd에 클릭이벤트를 달았는데, 다른 td들에도 달고 싶다면
각자 노가다로 달아줄 수 있겠지만, 이럴 땐 이벤트를 위임하는 방법을 쓴다(Event Delegation).

document.getElementById( 'myTable' ).addEventListener( 'click', function( e ) {
      if( e.target && e.target.nodeName == 'TD' ) {
         //you code goes here...
      }
   }, false );

jQuery Event Delegation

  • 이벤트 위임은 이벤트의 bubble 속성을 사용한 것입니다.
  • A 엘리먼트에 이벤트 핸들러를 등록하고 싶을 때 그 엘리먼트에 바로 붙이지 않고 그보다 상위 엘리먼트에 B에 등록합니다.
  • 이벤트가 A에서 발생했어도 B로 bubble 되어 올라가는데 이때 B에 등록된 핸들러에서 A에서 발생한 것인지 살펴보고 맞으면 이벤트 핸들러를 실행하는 방식이 이벤트 위임입니다.
  • .bind(), .live(), .delegate() 메서드 모두 jQuery 내부적으로는 .on() 메서드를 사용하게 소스코드가 바뀌었습니다.
  • 그래서 jQuery 1.7 이상 버전을 사용하신다면 여러 메서드들 중 하나를 선택하실 필요없이 그냥 .on() 메서드를 사용하시면 됩니다.
// Attach a delegated event handler
$( "#list" ).on( "click", "a", function( event ) {
    event.preventDefault();
    console.log( $( this ).text() );
});

Refer

http://regularmotion.kr/javascript-patterns-event-delegate/
http://hersheyweb.blogspot.kr/2013/04/javascript-event-delegation.html
http://codefactory.kr/2011/12/07/jquery-performance-tips-and-tricks/
http://learn.jquery.com/events/event-delegation/

자바스크립트&제이쿼리 (존 두켓 지음, 제이펍 출판) – “세상에서 가장 아름다운 프로그래밍 서적”

진유림_-_휴대폰_업로드

4월 초, 페이스북을 뜨겁게 달군 한 책이 있다.

충격적인 카피 때문일 것이었다.

“지금 여러분은 세상에서 가장 아름다운 프로그래밍 서적을 보고 있습니다!”

라니. 자고로 프로그래밍 서적은 노란책이나 코뿔소책처럼 그림은 존재하지 않는 작은 텍스트 뿐인게 대부분 아닌가.

그러나 이 책은 조금 달랐다.

위 사진의 댓글 분들이 요구하신 것처럼(그리고 모종의 잿밥을 향하여), 간단한 서평을 써보겠다.

S__9166854

(외모가 많이 다르다. 위:자바스크립트 노란책)

이 책이 다른 책들과 다른 점은,

  1. 텍스트로만 이해하기 힘든 부분들은 잘 다듬어 비쥬얼라이제이션 해두었고(책 전체를 아울러서!)

  2. 왼쪽 페이지에 DOMNodeInserted와 같은 개념을 설명한 후엔, 오른쪽엔 그 개념들을 어울러 실용적인 예제들을 만들어둔게 참 좋았다.

그것이이 이해-습득의 작은 루틴을 만들어 공부에 리듬감을 주었다.

S__9166856

(이런 식. 예제는 ‘구매 물품 목록 만들기’의 변형본을 계속 사용하여 익숙한 느낌을 준다)

630페이지를 돌파하는 두꺼운 책이지만, 사실 처음에는 이틀이면 완독할 줄 알았었다.

참 많이 부족하긴 하지만, 그래도 프론트엔드 신입 개발자로 일하고 있는 나였고, 주 언어는 자바스크립트였으니까.

아는 부분은 슬렁 슬렁 넘어가야지 하며 가벼운 마음으로 읽기 시작했는데

얼마 지나지 않아 내가 모르는 부분들이 나오는 것에 당황스러워 하다가,

곧 자세잡고 정독&블로그정리 하며 읽었다.

이는 그 산출물들이다.

https://milooy.wordpress.com/2015/04/03/javascript-dom/

https://milooy.wordpress.com/2015/05/15/javascript-event/

https://milooy.wordpress.com/2015/05/17/jquery/

처음에 자바스크립트를 학교에서 공부한 이후로는, 필요한 기능이 있을때마다 api문서나 스택오버플로우만 찾아보며 닥친 문제를 해결하곤 했는데, 이 책은 실용적인 기능들을 체계적으로 샅샅히 흝어가는 느낌이 참 좋았다.

나는 참 구멍뚫린 곳들이 많았구나….

S__9166851

(예를 들면 이런 것들. before()과 prepend()의 차이.)

자바스크립트나 제이쿼리를 처음 접하는 사람들에게,

아니면 배웠지만 나처럼 빵꾸가 많이 뚫려있는 사람에게,

혹은 유려한 편집디자인의 미를 느끼며 개괄적으로 흝고 싶은 사람에게 추천한다.

(나는 예쁜 것에도 민감하여, 이 책 한장 한장 디자인이 예뻐서 공부할 맛이 났다)

아, 그리고 위에 정리해둔 링크를 보면 알겠지만, 아직 읽어야 할 장들이 좀 남았는데 이는

8. Ajax와 JSON

9. API

10. 오류 처리와 디버깅

등등으로 더더욱 실무적인 내용이 있다. 취약했던 부분을 예쁜걸로 배운다니 마음이 꽁냥하다.

다른 직업도 마찬가지겠지만, 개발자는 정말 끊임없는 공부가 필요하다. 그리고 그것을 즐겨야 큰 개발자가 될 수 있다.

주변에 “아… 일시정지 누르고 ㅇㅇ(swift/go/polymer등등)좀 배우고 다시 일했으면 좋겠다 ㅠㅠ”라며

‘자신이 현재 하는 일 외의 개발’을 취미생활(혹은 사치생활!)로 여기며 배움에 대한 갈망을 내보이는 개발자들이 참 많다.

그런 사람들과 함께할때마다 배가 간질간질해지며 그들이 참 귀엽고 이런 개발자 세계가 좋다.

신기술은 끊임없이 나오고, 스피드웨건같은 블로거님들과 출판사님들 덕분에 참 개발공부하기 좋은 때이다.

이 시기와 환경을 십분 이용해먹어야지 슈퍼개발자가 되어야지 파워블로거도 되어야지 주짓수 챔피언이 되어야지


(p.s HTML CSS가 부족하다면 같은 저자가 집필한 이 책도 추천드려요)

책정보__HTML_CSS___네이버_책

자바스크립트 & 제이쿼리 (jpub) – 7장 jQuery

요소 탐색하기

  • 계층 탐색
    • ancestor descendant
    • p>c: 다른 요소의 하위 요소들
    • p+n: 직접적인 자식 요소들(모든 자식요소 하고싶다면 p>*)
    • p~s: 이전 요소의 모든 이웃 요소
  • 기본 필터
    • :not(selector): 셀렉터에 부합하는 요소를 제외한 나머지 요소들(div:not(‘#summary’))
    • :first: 선택된 요소 중 첫 번째 요소
    • :last, even, odd
    • :eq(index): 선택된 요소 중 매개변수로 지정된 인덱스 번호를 가진 요소
    • :gt(index), :lt(index)
    • :header, :animated, :focus
  • 콘텐츠 필터
    • :contains(‘text’): 매개변수로 지정된 텍스트를 가지고 있는 요소들
    • :empty: 자식 요소가 없는 모든 요소들
    • :parent: 위의 반대
    • :has(selector): 선택된 요소 중 매개변수에 지정된 셀렉터에 부합하는 요소를 최소한 하나 이상 가지고 있는 모든 요소 (ex. div:has(p) p요소를 가진 모든 div요소)
  • 가시성 필터
    • :hidden: 화면에서 숨겨진 모든 요소들
    • :visible: 페이지의 레이아웃에서 공간을 차지하고 있는 모든 요소들.
  • 자식 요소 필터
    • :nth-child(expr): 1부터 시작하는 해당 순번의 요소(ul li:nth-child(2)는 두번째 요소를 의미)
    • :first-child, :last-child, :only-child
  • 특성 필터
    • [attribute]: 지정된 특성 갖고있는 요소들
    • [attribute=’value’]
    • [attribute!=’value’]
    • [attribute^=’value’]: 특성값이 지정된 값으로 시작하는 요소들
    • [attribute$=’value’]: 특성값이 지정된 값으로 끝나는 요소들
    • [attribute*=’value’]: 특성값이 지정된 값으로 포함되는 요소들
    • [attribute][attribute2]: 지정된 특성 중 하나를 가진 모든 요소들
    • :input, :text, :password, :radio…
    • :image, :button
    • :selected: 드롭다운 리스트에서 선택된 모든 요소들
    • :enabled, :disabled, :checked(체크된 요소들을 리턴)

선택된 요소에 필요한 작업 수행

  • 콘텐츠 필터
    • 가져오기/수정하기
      • .html(): 첫 번째 요소들과 그 하위 노드들의 HTML코드를 얻음.
      • .text(): 객체집합 내 모든 요소의 텍스트와 그 하위 요소들의 텍스트 리턴.(input요소나 textarea요소에서 내용 가져오려면 .val()메서드 사용.)
      • .replaceWith(): 일치하는 모든 요소에 새로운 동일한 콘텐츠 추가하고 교체된 요소들을 모두 리턴
      • .remove(): 일치하는 모든 요소들을 제거
    • 요소
      • .before(): 선택한 요소 전에
      • .after(): 선택한 요소 다음에
      • prepend(): 선택한 요소의 여는 태그 다음에
        • a.prepend(b)는 a에 b를 추가한다 / a.prependTo(b)는 b에 a를 추가한다.
      • append(): 선택한 요소의 닫는 태그 다음에
      • remove
      • clone
      • unwrap
      • detach
      • empty
      • add: 매개변수로 지정된 셀렉터에 의해 선택된 요소들을 기존 객체집합에 추가
    • 특성
      • attr
        • 가져오기: $(‘li#one’).attr(‘id’);
        • 수정하기: $(‘li#one’).attr(‘id’, ‘hot’);
      • removeAttr
      • addClass
      • removeClass
      • css
        • 가져오기: bg = $(‘li’).class(‘background-color’);
        • 증감하기: $(‘li’).class(‘padding’, ‘+=20’);
        • 여러 속성: $(‘li’).css({‘color’: ‘#272727’, ‘font-family’: ‘Courier’});
    • 폼 값
      • val: input, select, textarea요소에 주로 사용.
      • isNumeric
  • 요소 탐색
    • 일반
      • find: 현재 객체집합에서 셀렉터와 일치하는 요소들 리턴
      • closest: 셀렉터와 일치하는 가장 근접한 상위요소(직계부모~최상위요소 모두)를 리턴
      • parent: 현재 객체집합의 직계부모요소 리턴
      • parents: 모든 부모요소
      • children: 모든 자식 요소
      • siblings: 모든 이웃 요소
      • next: 다음 이웃 요소
      • nextAll
      • prev
      • prevAll
    • 필터/테스트
      • filter: 두 번째 셀렉터를 이용하여 jQuery객체집합을 필터링
      • not
      • has
      • is: 폼요소가 선택 혹은 체크되어있는지 확인
      • :contains()
    • 객체집합 내 순서 평가
      • eq: 인덱스 번호에 해당하는 요소를 리턴
      • :lt
      • :gt
  • 크기/위치
    • 크기
      • height: 영역의 크기
      • with innerHeight(영역의 높이에 안쪽 여백 더한 값) / innerWidth / outerHeight/ outerWidth
      • $(document).height()
      • $(document).width()
      • $(document).height()
      • $(window).height()
      • $(window).width()
    • 위치
      • offset: document객체의 좌측 상단 모서리에서부터 요소까지의 좌표를 가져오거나 지정(offset().top 이런식으로 쓴다)
      • position: 상위 요소 중 기본 흐름 값을 가진 요소로부터 해당 요소까지의 좌표를 가져오거나 지정
      • scrollLeft
      • scrollTop
  • 효과/애니메이션
    • 기본
      • show: 선택된 아이템을 보이게
      • hide: 숨긴다
      • toggle
    • 흐림 효과
      • fadeIn
      • fadeOut
      • fadeTo: 선택된 요소의 불투명도 조절
      • fadeToggle
    • 슬라이딩 효과
      • slideDown
      • slideUp
      • slideToggle
    • 기타
      • delay: 큐 내의 다음 아이템의 실행을 잠시 지연
      • stop: 현재 실행중인 애니메이션 중단
      • animate: 새로운 임의의 애니메이션 생성
  • 이벤트
    • 문서/파일
      • ready
      • laod
    • 사용자 상호작용
      • on
      • (.click(), .hover(), submit()같은 메서드들도 보게 될것인데, 이벤트 처리를 위한 on()메서드가 나타나며 사라짐)

tips

정보

  • 획득
    • jquery객체집합에 둘 이상 요소 저장되어 있으면 ($(‘li’).html();) 첫번째 요소의 정보만 얻어옴.
    • 다른 요소 참조하려면 탐색메서드나 필터 메서드, 혹은 셀렉터 이용.
    • 모든 요소 콘텐츠 가져오려면 .each()메서드 사용.
  • 수정
    • 둘이상 요소 저장되어있고 수정하면 모든 요소 수정됨.

변수에 캐싱

  • 코드가 동일한 객체집합을 한번 이상 사용할 필요가 있다면 객체에 담아두는게 효과적.
  • $listItems = $(‘li’); 와 같이 변수에 jQuery객체를 저장할 때 이렇게 하면 다른 변수들과 구분하는데 도움된다.

체이닝

  • jQuery객체집합을 수정하기 위한 대부분의 메서드는 체이닝 가능
  • 그러나 DOM/브라우저에서 정보를 조회하는 메서드들은 체이닝으로 연결 불가.

페이지가 준비되었는지 확인

// 이 메서드 내부에 작성하면 코드가 페이지의 다른곳이나 다른 파일에 작성된 경우에도 의도대로 동작한다.
$(document).ready(function() {
    //bla bla
});

// 위 함수의 약식 표현
$(function() {
    //bla bla
});
  • .load()
    • load이벤트가 발생할 때 호출.
    • .on()메서드로 대체되었다.
    • 페이지와 나머지 모든 리소스(이미지, CSS, 스크립트)가 로드된 이후에 발생
    • 스크립트가 반드시 로드되어야 하는 리소스에 의존적일 때 사용.
      • ex. 스크립트가 이미지의 크기를 알아야 할 때
  • .ready()
    • 페이지가 빨리 로드된 것처럼 보이도록 브라우저에 DOM이 로드되자마자 실행.
    • 그러나 최신 브라우저들에서만 지원.(구버전: laod이벤트 되면 시작)

컨텐츠를 수정

현재 선택한 요소들의 콘텐츠를 사용하려는 동시에 수정하려면 함수에 매개변수를 전달하면 된다.

$('li.hot').html(function(){
    return '<em>' + $(this).text() + '</em>';
    })

.each()

$(function() {
    $('li').each(function() {
        var ids = this.id;  //$(this).attr('id')보다 이게 좋다.
        $(this).append('<span class="order">' + ids + '</span>');
    });
});

this

$(this)처럼 this키워드를 이용해 새로운 jQeury 객체집합을 만드는 경우도 볼 수 있는데,
이렇게 하면 현재 요소에 대해서도 jQuery메서드들을 사용할 수 있다.

.on()

  • 매개변수를 2개 받는다. 첫번째는 대응할 이벤트, 두번째는 함수(기명/익명)
  • (*친것들은 onready처럼 작업을 더 쉽게 만들어주는 추가 메서드 제공.)
  • focus, blur, change
  • input, keydown keyup, keypress
  • click, dblclick, mouseup, mousedown, mouseover, mousemove, mouseout, *hover
  • submit, select, change
  • *ready, load, *unload
  • error, resize, scroll
//모바일은 마우스오버가 없으니 클릭도 같이 지정.
$listItems.on('mouseover click', functionn(){
    //~~
});

event객체

$('li').on('click', function(e) {
    eventType = e.type;
});

속성

  • type: 이벤트 종류
  • which: 눌려진 버튼이나 키
  • data
  • target: 이벤트가 발생한 DOM요소
  • pageX, pageY
  • timeStamp
  • .preventDefault(): 기본 동작을 취소(ex. 폼 데이터 전송)
  • .stopPropagation(): 상위 객체로 이벤트가 버블링되는 것을 중단.

.animate()

.animate({
    //변경할 스타일들 나열
    }, [, speed][, easing][, complete]);
// speed: 진행될 시간의 길이 밀리초단위. low/fast도 가능
// easing: linear(일정속도) / swing(중간은 빨리 처음끝은 느리게)
// complete: 애니메이션이 종료시 호출될 함수(콜백함수)를 지정 위함

$(this).animate({
    opacity: 0.0,
    paddingLeft: '+=80'
    }, 500, function() {
        $(this).remove();
    });

오타

303p attribute$=’value’
322p $(‘li’).clss(‘~’)
322p ‘background-color’: ‘#272727’,

jQuery .attr() vs .prop()

왜 .attr()을 .prop()으로 나누었나?

  • 원래 따로 사용해야할 문제였는데 버그 많아져버림
  • attr : HTML의 속성을 취급
  • prop : Javascript프로퍼티 취급

example 1

<a id="to_comments" href="#comments">코멘트 일람</a>
...
var $link = $('#to_comments');
$link.attr('href'); //#to_comment
$link.prop('href'); //#http://example.com/path/to/page#to_comment
  • 속성: HTML으로서 기록되어있는 속성의 내용
  • 프로퍼티: Javascript가 취급하는 정보.

example 2

<checkbox id="private" type="checkbox" checked />
...
var $checkbox = $('#private');
alert($checkbox.attr('checked')); //"checked"
alert($checkbox.prop('checked')); //true
//체크박스 해제하면?
alert($checkbox.attr('checked')); //"checked"
alert($checkbox.prop('checked')); //false

Reference

http://javascriptandjquerydev.blogspot.kr/2012/07/attr-prop.html