샘플코드

[프론트엔드] 유튜브 페이지 코드 샘플

jinwanseo 2021. 2. 17. 19:57
728x90

FrontEnd Youtube Html, Css, Javascript Code Sample (반응형)

 

프론트 엔드 연습을 위해 유튜브 페이지를 만들어보았다.

오랜시간에 걸쳐서 만든 페이지가 아니라 허접하다.

필요한 사람은 잘 다듬어서 사용하면 좋을 것같다.

출력화면, 소스코드 순서대로 기재해 두었으니 참고바란다.

 

 

구동 로직은 

header에 css 파일 을 추가하고 body에 script만 추가하면

해당 페이지에 데이터 베이스 또는 사용자가 미리 설정한 데이터를 토대로 

페이지 내 마크업 언어가 작성되는 방식이다.

파일은 가장 하단에 첨부해 놓았으니 참고바람.

 

[CSS]

 

:root {
    /* color */
    --headerColor : #252525;
    --fontColor : #252525;
    --logoColor : #df2928;
    --videoBackColor : #000000;
    --headerIcon : #fefefe;
    --infoIcon : #909090;
    --borderColor : #e0e0e0;
    --blueColor :#3656c7;
}

body { margin : 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;}
button,button:focus {
    cursor : pointer;
    outline: none;
    border :none;
    background-color: transparent;
}


header {
    display : flex;
    justify-content:space-between;
    align-items: center;
    padding : 10px 10px;
    font-size : 20px;
    background : var(--headerColor);
    color : var(--headerIcon);
}
    header>.logo>i {
        color : var(--logoColor);
    }
    header > .icon {
        font-size : 16px;
    }
    
.player {
    display : flex;
    justify-content: center;
    align-items: center;
    width : 100%;
    height: 45vw;
    max-width : 1000px;
    background : var(--videoBackColor);
}

    .player video {
        height: 100%;
    }

.info {
    display : flex;
    margin : 15px;
    flex-direction: column;
}
    .info > .hash {
        display : flex;
        justify-content: flex-start;
        padding : 0;
        margin-top : 0;
        margin-bottom : 5px;
        list-style: none;
        color : var(--blueColor);
    }
        .info > .hash > li {
           margin : auto 4px;
        }

    .info > .title {
        display : flex;
        justify-content: space-between;
    }

        .info > .title > .title-simple.clamp {
            display: -webkit-box;
            -webkit-box-orient: vertical;
            -webkit-line-clamp: 2;
            overflow: hidden;
        }

        .info>.title > .title-icon.clicked {
            transform: rotate(180deg);
        }

        .info > .title > .title-icon > i {
            height: 100%;
        }

    .info > .info-detail {
        color : var(--infoIcon);
        font-size : 12px;
        margin : 5px 0;
    }

    .info > .buttons {
        display : flex;
        justify-content: space-around;
        padding-top : 18px;
        padding-bottom : 18px;
    }

        .info > .buttons > .icon {
            display : flex;
            flex-direction: column;
            align-items: center;
        }

        .info > .buttons > .icon.clicked {
            color : var(--blueColor);
        }

        .info > .buttons > .icon > i {
            margin-bottom : 5px;
        }

    .info > .sub-info {
        display : flex;
        justify-content: space-between;
        align-items: center;
        border-top : 1px solid var(--borderColor);
        border-bottom : 1px solid var(--borderColor);
        margin : 5px 10px;
        padding-top : 18px;
        padding-bottom : 18px;
    }

    
        .info > .sub-info > .channel {
            display : flex;
            align-items: center;
            font-size : 14px;
        }
            .info > .sub-info > .channel > img {
                width : 45px;
                height: 45px;
                border-radius: 50%;
                margin-right: 10px;
            }
            .info > .sub-info > .channel > .channel-title {
                font-weight: bolder;
            }

            .info > .sub-info > .channel >  .channel-title >.channel-info {
                font-weight: lighter;
            }

        .info > .sub-info > .subscribe {
            text-transform: uppercase;
            user-select: none;
            padding : 5px;
            border : 1px solid var(--logoColor);
            background-color: transparent;
            color : var(--logoColor);
        }
        .info > .sub-info > .subscribe:hover {
            cursor: pointer;
        }
        .info > .sub-info > .subscribe.clicked {
            background-color: var(--logoColor);
            color : var(--headerIcon);
        }


.upNext {
    margin : 15px;
    display : flex;
    flex-direction: column;
}

    .upNext > .nextList {
        display : flex;
        flex-direction: column;
        list-style: none;
        padding : 0;
    }
    .upNext > .nextList li {
        display : flex;
        justify-content: space-between;
    }

    .upNext > .nextList li .imgAndTitle {
        display : flex;
        flex-direction: row;
    }

        .upNext > .nextList li .imgAndTitle .img img{
            cursor : pointer;
            width : 168px;
            height: 94px;
        }

        .upNext > .nextList li .imgAndTitle .title {
            cursor : pointer;
            font-size : 15px;
            margin : 0px 15px;
        }

        .upNext > .nextList li .title .title-by,
        .upNext > .nextList li .title .title-views {
            font-weight: lighter;
        }

.infoAndUpnext {
    display : flex;
    flex-direction: row;
    max-width : 1000px;
}

@media screen and (max-width : 768px){
    .infoAndUpnext {
        flex-direction: column;
    }
}

 

[Javascript]

 

//데이터 SET
const dataList = {
    siteName : 'YouTube',   //사이트명
    siteLogo : '<i class="fab fa-youtube"></i>',    //사이트 로고 (현재 유튜브로고)
    channelName : 'ChannelName',    //채널이름
    subscribe : '9999', //구독
    hash : [
        '#신짱구','#짱구는못말려','#귀여운짱구'
    ],
    video : {//동영상 url, 제목, 조회수, 지난날짜, 좋아요, 싫어요
        videoUrl : './video/videoplayback.mp4',  //동영상 url (경로내 파일 없을시 재생안됨)
        videoTitle : '짱구는 못말려 짱구 아바타 이미지 짱구는 못말려 19기 먹방 리보터를 하고 싶어요 짱구가 졸업하고 칭찬 받아요 짱구 아빠 머릿결이 찰랑찰랑 해요',
        videoView : '9999',
        videoDate : '1',
        videoLike : '1K',
        videoDisLike : '0'
    },
    othervideoList : [  //동영상 재생 목록
        {
            thumbNailImg : 'https://img.insight.co.kr/static/2020/08/26/700/um01e66fr9c3b1x3yax7.jpg',
            videoTitle : '재생목록 내 타이틀',
            channelName : 'ChannelName',
            videoView : '9999'
        },
    ],
};

//태그 생성
//header
const haederElement = document.createElement('header');
haederElement.innerHTML = `
        <div class="logo">
            ${dataList.siteLogo}
            <span class="title">${dataList.siteName}</span>
        </div>
        <div class="icon">
            <i class="fas fa-search"></i>
            <i class="fas fa-ellipsis-v"></i>
        </div>
`;

//.player
const playerElement = document.createElement('section');
playerElement.classList.add('player');
playerElement.innerHTML = `
    <video controls src="${dataList.video.videoUrl}"></video>
`;

//.infoAndUpnext
const infoAndNextElement = document.createElement('section');
infoAndNextElement.classList.add('infoAndUpnext');

//.infoAndUpnext > .info
const infoElement = document.createElement('section');
infoElement.classList.add('info');
let hashTags = '';
dataList.hash.forEach(hash => hashTags+= `<li>${hash}</li>`);
infoElement.innerHTML = `
            <ul class="hash">
               ${hashTags}
            </ul>
            <div class="title">
                <div class="title-simple clamp">
                    ${dataList.video.videoTitle}
                </div>
                <button class="title-icon">
                    <i class="fas fa-caret-down"></i>
                </button>
            </div>
            <div class="info-detail">${dataList.video.videoView} views ${dataList.video.videoDate} month ago</div>
            <div class="buttons">
                <button class="icon">
                    <i class="fas fa-thumbs-up"></i>
                    ${dataList.video.videoLike}
                </button>
                <button class="icon">
                    <i class="fas fa-thumbs-down"></i>
                    ${dataList.video.videoDisLike}
                </button>
                <button class="icon">
                    <i class="fas fa-share"></i>
                    Share
                </button>
                <button class="icon">
                    <i class="fas fa-plus"></i>
                    Save
                </button>
                <button class="icon">
                    <i class="fab fa-font-awesome-flag"></i>
                    Report
                </button>
            </div>
            <div class="sub-info">
                <div class="channel">
                    <img src="http://img.lifestyler.co.kr/uploads/program/1/1765/menu/2/html/f131755988183457049(0).jpg" alt="" class="thumbnail">
                    <div class="channel-title">
                        ${dataList.channelName}
                        <div class="channel-info">${dataList.subscribe} subscribers</div>
                    </div>
                    
                </div>
                <span class="subscribe">subscribe</span>
            </div>
`;

//.infoAndUpnext > .upNext
const upNextElement = document.createElement('section');
const upNextElement_titleElement = document.createElement('div');
const upNextElement_nextListElement = document.createElement('ul');
upNextElement.classList.add('upNext');
upNextElement_titleElement.classList.add('title');
upNextElement_titleElement.innerText = 'Up next';
upNextElement_nextListElement.classList.add('nextList');
upNextElement.append(upNextElement_titleElement,upNextElement_nextListElement);

dataList.othervideoList.forEach(video => {
    upNextElement_nextListElement.innerHTML += `
        <li>
            <div class="imgAndTitle">
                <div class="img">
                    <img src="${video.thumbNailImg}" class="title-img">
                </div>
                <div class="title">
                    <div class="title-text">
                        ${video.videoTitle}
                    </div>
                    <div class="title-by">${video.channelName}</div>
                    <div class="title-views">${video.videoView} views</div>
                </div>
            </div>
            <div class="detail">
                <button class="detail-btn">
                    <i class="fas fa-ellipsis-v"></i>
                </button>
            </div>
        </li>
    `;
});

infoAndNextElement.append(infoElement,upNextElement);

//Html 작성
document.querySelector('body').append(haederElement,playerElement,infoAndNextElement);

//FontAwesome 추가
const fontawesome = document.createElement('script');
fontawesome.src = 'https://use.fontawesome.com/releases/v5.2.0/js/all.js';

document.querySelector('body').append(fontawesome);


//------------------- 기능 스크립트 영역------------------------

//타이틀 2줄만 보기 / 모두 보기
document.querySelector('.title-icon').addEventListener('click',e=>{
    document.querySelector('.title-simple').classList.toggle('clamp');
   document.querySelector('.title-icon').classList.toggle('clicked');
});

//좋아요 싫어요 클릭시 색상 변경
document.querySelector('.info>.buttons').addEventListener('click',e=>{
    if(e.target.nodeName === 'I'){
        console.log(e.target.parentElement);
        e.target.parentElement.classList.toggle('clicked');
    }
});

//구독버튼 클릭시 색상변경
document.querySelector('.sub-info>.subscribe').addEventListener('click',e=>{
    e.target.classList.toggle('clicked');
});

 

 

 

[소스파일]

script.js
0.01MB
style.css
0.00MB

728x90