티스토리 뷰

HTML/콤포넌트 모음

모음1

트라이에이스 2024. 7. 9. 20:06

observer를 이용한스크롤

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>observer를 이용한스크롤</title>
<style>
.box { border: 1px solid #000;}
.show { border-color: red;}
</style>
</head>
<body>
    <div>
        <div class="box" style="height: 500px;"></div>
        <div class="box" style="height: 500px;"></div>
        <div class="box" style="height: 500px;"></div>
        <div class="box" style="height: 500px;"></div>
        <div class="box" style="height: 500px;"></div>
        <div class="box" style="height: 300px;"></div>
        <div class="box" style="height: 300px;"></div>
        <div class="box" style="height: 300px;"></div>
        <div class="box" style="height: 300px;"></div>
        <div class="box" style="height: 300px;"></div>
    </div>

    <script>
        let option = {
            threshold: 1 /* 보이는 영역 비율 0 ~ 1 */
        }
        let observer = new IntersectionObserver(entries => {
            entries.forEach(entry => {
                if(entry.isIntersecting) {
                    entry.target.classList.add('show');
                } else {
                    entry.target.classList.remove('show');
                }
            });
        }, option);
        const boxElemList = document.querySelectorAll('.box');
        boxElemList.forEach(elem => observer.observe(elem));
    </script>
</body>
</html>

observer를 이용한 Lazy load 이미지

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>observer를 이용한 Lazy load 이미지</title>
<style>
.box { border: 2px solid #000;}
.show { border-color: red;}
</style>
</head>
<body>
    <div>
        <div class="box" style="height: 500px;"></div>
        <div class="box" style="height: 500px;"></div>
        <div class="box" style="height: 500px;"></div>
        <div class="box" style="height: 500px;"></div>
        <div class="box images" style="height: 300px; border-color: blue;">
            <div class="img"></div>
        </div>
        <div class="box" style="height: 500px;"></div>
        <div class="box" style="height: 300px;"></div>
        <div class="box" style="height: 300px;"></div>
        <div class="box" style="height: 300px;"></div>
        <div class="box" style="height: 300px;"></div>
        <div class="box images" style="height: 300px; border-color: blue;">
            <div class="img"></div>
        </div>
        <div class="box" style="height: 300px;"></div>
    </div>

    <script>
        let option = {
            threshold: 0 /* 보이는 영역 비율 0 ~ 1 */
        }
        let observer = new IntersectionObserver((entries, observer) => {
            entries.forEach(entry => {
                if(!entry.isIntersecting) return;
                const target = entry.target;
                const src = target.dataset.src;
                target.querySelector('.img').style.backgroundImage = `url(https://image/${src}.com)`;
                // 로드가 완료되면 더 이상 로딩 관리를 할 필요가 없기 때문에
                // 해당 요소에 한해 관측을 해지
                observer.unobserve(target);
                //해당 요소에 한해 관측을 종료
                // observer.disconnect(target);
            });
        }, option);
        document.querySelectorAll('.images').forEach(elem => observer.observe(elem));
    </script>
</body>
</html>

찹쌀떡효과

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>찹쌀떡효과</title>
<style>
.svg { position: absolute; left: calc(50% - 200px); top: calc(50% - 150px); width: 400px; height: 300px; margin: auto; filter: url(#gooey);}
.circle { position: absolute; left: 50%; top: 50%; width: 100px; height: 100px; margin: -50px 0 0 -50px; background-color: #60cb60; border-radius: 100%;}
.circle:last-child { width: 50px; height: 50px; background-color: red; animation: circle-right ease-in-out 20s infinite alternate;}
@keyframes circle-right {
    0% { transform: translate(-10px, -60px);}
    40% { transform: translate(57px, 120px);}
    60% { transform: translate(-20px, 120px);}
    100% { transform: translate(57px, -60px);}
}
</style>
</head>
<body>
    <div class="svg">
        <div class="circle"></div>
        <div class="circle"></div>
    </div>

    <svg>
        <defs>
            <filter id="gooey">
                <!-- feGaussianBlur in="효과적용대상" stdDeviation="블러수치" result="결과를변수에저장" -->
                <feGaussianBlur in="SourceGraphic" stdDeviation="12" result="blur" />
                <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 70 -9" result="goo" />
                <feComposite in="SourceGraphic" in2="goo" operator="atop" />
            </filter>
        </defs>
    </svg>
</body>
</html>

스와이프 샘플

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"/>
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
<title>스와이퍼 샘플</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box;}
.swiper-slide { height: 150px; border: 1px dashed #000;}
.control { border: 1px dashed #000;}
</style>
</head>
<body>
    <div class="swiper">
        <div class="swiper-container">
            <div class="swiper-wrapper">
                <div class="swiper-slide">
                    <a href="#" role="button"><p>첫번째</p></a>
                </div>
                <div class="swiper-slide">
                    <a href="#" role="button"><p>두번째</p></a>
                </div>
            </div>
        </div>

        <div class="position">
            <div class="fraction">
                <span class="fraction__active">1</span> / <span class="fraction__total">2</span>
            </div>
            <a href="#" class="control" role="button"><span class="blind">정지</span></a>
        </div>
    </div>
    <script>
        $(function() {
            var swiper = new Swiper('.swiper .swiper-container', {
                autoplay: {
                    disableOnInteraction: false,
                },
                loop: true,
                observer: true,
                observeParents: true,
                on: {
                    slideChangeTransitionEnd: function() {
                        var totalSlides = $('.swiper-slide:not(.swiper-slide-duplicate)').length;
                        var $slideActive = $('.swiper-slide-active');
                        var realIndex = $slideActive.data('swiper-slide-index');
                        if(typeof realIndex === 'undefined') {
                            realIndex = $slideActive.index();
                        }
                        $('.fraction__active').html(realIndex + 1);
                        $('.fraction__total').html(totalSlides);
                    }
                }
            });
            $('.control').on('click', function() {
                if(!$(this).hasClass('play')) {
                    swiper.autoplay.stop();
                    $(this).children('span').html('재생');
                    $(this).addClass('play');
                } else {
                    swiper.autoplay.start();
                    $(this).children('span').html('정지');
                    $(this).removeClass('play');
                }
            })
        });
    </script>
</html>

토스트팝업

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>토스트팝업</title>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box;}
.toast { position: fixed; left: 10px; right: 10px; bottom: 10px; z-index: 100; background-color: #fff;}
.dimmed--toast { position: fixed; left: 0; right: 0; top: 0; bottom: 0; z-index: 99; background-color: rgba(0, 0, 0, .4);}

</style>
</head>
<body>
    <div id="Wrap">
        <a href="#" class="btn" data-message="0">토스트 팝업1</a>
        <a href="#" class="btn" data-message="1">토스트 팝업2</a>
    </div>

    <script>
        $(function() {
            $('.btn').on('click', function() {
                var messageIndex = $(this).data('message');
                var left = {
                    p0: '첫번째 토스트팝업 메세지',
                    p1: '두번째 토스트팝업 메세지',
                }
                $.toast({
                    message: left['p'+messageIndex]
                });
            });
            $.toast({
                message: '새로고침시 나타나는 메세지',
            });
        });
    </script>
    <script>
        var toastConfig = {
            autoDismiss: true,
            autoDismissDelay: 2400,
            transitionDuration: 200,
        }
        $.toast = function(config) {
            config = {
                message: config.message,
                btn: event.currentTarget,
                type: event.type,
            }
            return new toast(config);
        }
        var toast = function(config) {
            config = $.extend({}, toastConfig, config);
            var toast = $([
                '<div class="toast" role="status" aria-live="polite" tabindex="0">',
                '<p class="toast__titi">'+ config.message +'</p>',
                '<button type="button">테스트 버튼</button>',
                '<a href="#">테스트 앵커</a>',
                '<button type="button" class="toast__close">닫기</button>',
                '</div>',
            ].join(''));

            if(config.type === 'click') {
                config.btn.focus();
            }
            toast.find('.toast__close').on('click', function() {
                var toast = $(this).closest('.toast');
                toast.remove();
                $('.dimmed--toast').remove();
                $('#Wrap').removeAttr('aria-hidden');

                setTimeout(function() {
                    toast.remove();
                    if(config.type === 'click') {
                        config.btn.focus();
                    }
                }, config.transitionDuration);
            });
            toast.appendTo(document.body);
            toast.before('<div class="dimmed--toast"></div>')
            $('#Wrap').attr('aria-hidden', 'true');
            setTimeout(function() {
                toast.addClass('show');
                goFocus($('.toast'));
                focusRotation($('.toast'));
            }, config.transitionDuration);

            if(config.autoDismiss) {
                setTimeout(function() {
                    toast.find('.toast__close').click();
                }, config.autoDismissDelay)
            }
            return this;
        }

        goFocus = function(tgEl) {
            var $tgEl = $(tgEl);
            $tgEl.focus();
        }

        focusRotation = function(tgEl) {
            var $tgWrap = $(tgEl),
                tabbableEl = '[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])',
                focusTg = $tgWrap.find(tabbableEl),
                $firstFocusEl = focusTg.first(),
                $lastFocusEl = focusTg.last();

            $lastFocusEl.on({
                'click': function() {
                    $tgWrap.find('.toast__close').click();
                },
                'keydown': function(e) {
                    var _keycode = e.keyCode || e.which;
                    if(_keycode === 9 && !e.shiftKey) {
                        e.preventDefault();
                        goFocus($firstFocusEl);
                    }
                },
            });
        }
    </script>
</body>
</html>

프레스 효과

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>프레스 효과</title>
<script  src="http://code.jquery.com/jquery-latest.min.js"></script>
<style>
.list { display: flex;}
a { display: block; width: 150px; height: 150px; border: 1px solid #000; transition: transform .2s ease-out;}
a.press { background-color: #eee; transform: scale(0.93);}
</style>
</head>
<body>
    <div class="list">
        <a href="#">눌러주세요1</a>
        <a href="#">눌러주세요2</a>
    </div>

    <script>
        const touchConf = {};
        $('.list a').on('touchstart touchmove touchend', function(e) {
            switch(e.type) {
                case 'touchstart':
                    touchConf.y = e.originalEvent.changedTouches[0].pageY;
                    touchConf.scrolled = false;
                    e.currentTarget.classList.add('press');
                break;
                case 'touchmove':
                    if(e.originalEvent.changedTouches[0].pageY != touchConf.y) {
                        touchConf.scrolled = true;
                        e.currentTarget.classList.remove('press');
                    }
                break;
                case 'touchend':
                    if(touchConf.scrolled == false) {
                        e.currentTarget.classList.remove('press');
                    }
                break;
            }
        });
    </script>
</body>
</html>

스크롤이동콤포넌트

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>스크롤이동콤포넌트</title>
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box;}
.flexGroup { display: flex; flex-direction: column; position: fixed; left: 0; right: 0; top: 0; bottom: 0;}
.btnGroup { position: relative; height: 42px;}
.btns { overflow-x: auto; overflow-y: hidden; display: flex; padding: 10px 10px 10px 0; white-space: nowrap;}
.btn { margin-left: 10px;}
.btn.on { color: #fff; background-color: red;}
.boxGroup { overflow: auto; flex: 1; padding: 10px;}
.box { position: relative;}
.box li { border: 1px solid black;}
.box li.on { border: 2px solid red;}
</style>
</head>
<body>
    <div class="flexGroup">
        <div class="btnGroup">
            <div class="btns">
                <button type="button" class="btn on">버튼111</button>
                <button type="button" class="btn">버튼2222</button>
                <button type="button" class="btn">버튼3333</button>
                <button type="button" class="btn">버튼444444444</button>
                <button type="button" class="btn">버튼555555</button>
                <button type="button" class="btn">버튼6666</button>
                <button type="button" class="btn">버튼7777777</button>
            </div>
        </div>

        <div class="boxGroup">
            <ul class="box">
                <li class="on" style="height: 600px;">박스1</li>
                <li style="height: 400px;">박스2</li>
                <li style="height: 500px;">박스3</li>
                <li style="height: 600px;">박스4</li>
                <li style="height: 300px;">박스5</li>
                <li style="height: 500px;">박스6</li>
                <li style="height: 400px;">박스7</li>
            </ul>
        </div>
    </div>

    <script>
        class overTab {
            constructor(idx) {
                this.idx = idx;
            }
            tabClick() {
                $('.btn').removeClass('on').eq(this.idx).addClass('on');
                let wid = $('.btn.on').outerWidth() / 2;
                let sLft = $('.btns').scrollLeft();
                let lft = $('.btn.on').position().left;
                let boxWid = $('.btns').outerWidth() / 2;
                let resLft = (lft + sLft) - (boxWid - wid - 10);
                $('.btns').stop().animate({scrollLeft: resLft}, 200);
            }
            overScroll() {
                $('.box li').each(function(idx, elm) {
                    let elmTop = $(elm).position().top;
                    let boxScrollTop = $('.boxGroup').scrollTop();
                    let boxHeight = $(elm).height();
                    if(elmTop <= boxScrollTop + 100 && elmTop + boxHeight > boxScrollTop + 100) {
                        $(elm).addClass('on');
                    } else {
                        $(elm).removeClass('on');
                    }
                });
                /* 바닥체크 */
                const liLength = $('.box li').length;
                let sTop = $('.boxGroup').scrollTop();
                let sinnerHeight = $('.boxGroup').innerHeight();
                let sHeight = $('.boxGroup').prop('scrollHeight');
                if(sTop + sinnerHeight >= sHeight) {
                    this.idx = liLength - 1;
                    $('.box li').removeClass('on').last().addClass('on');
                } else {
                    this.idx = $('.box li.on').index();
                }
                this.tabClick();
            }
        }
        $('.btn').on('click', function() {
            let idx = $(this).index();
            let boxTop = $('.box li').eq(idx).position().top;
            $('.boxGroup').stop().animate({scrollTop: boxTop}, 300);
            const playEvent = new overTab(idx);
            playEvent.tabClick();
        });
        $('.boxGroup').scroll(function() {
            const playEvent = new overTab();
            playEvent.overScroll();
        });
    </script>
</body>
</html>

'HTML > 콤포넌트 모음' 카테고리의 다른 글

라디오 체크  (0) 2023.07.28
기타 등등 모음  (0) 2023.07.03
인풋 속성 정리  (0) 2023.03.28
원형차트  (0) 2021.12.28
웹접근성을 지키는 Swiper  (0) 2021.11.25
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함