본문 바로가기
JavaScript

[JavaScript] 로컬스토리지 사용해 즐겨찾는 링크 저장하기

by teamnova 2024. 10. 31.
728x90

안녕하세요!

오늘은 로컬 스토리지를 사용해서 즐겨찾는 링크를 저장, 수정, 삭제할 수 있도록 해보겠습니다.

1. 로컬 스토리지란?

로컬 스토리지는 웹 브라우저에 내장된 저장 공간으로, 사용자가 데이터를 브라우저에 저장하고 이를 이후에도 사용할 수 있도록 하는 기능입니다. 로컬 스토리지는 브라우저와 연동된 웹 애플리케이션에서 데이터를 영구적으로 저장할 수 있도록 도와줍니다.

주요 특징

  1. 영구 저장: 로컬 스토리지에 저장된 데이터는 브라우저를 종료하거나 컴퓨터를 재부팅해도 삭제되지 않고 유지됩니다. 따라서 사용자가 다시 해당 웹 페이지를 방문했을 때, 저장된 데이터를 불러올 수 있어요.
  2. 도메인 기반 데이터 저장: 로컬 스토리지에 저장된 데이터는 도메인별로 격리됩니다. 즉, 한 웹 사이트에서 저장한 데이터는 다른 웹 사이트에서 접근할 수 없습니다. 이는 보안을 유지하는 데 중요한 역할을 합니다.
  3. 키-값 쌍(Key-Value Pair) 형식: 로컬 스토리지는 데이터를 키-값 쌍 형태로 저장합니다. 예를 들어, 사용자가 선택한 테마를 theme: "dark" 형태로 저장할 수 있습니다. 키와 값은 모두 문자열이어야 하므로, 객체를 저장하려면 JSON 형식으로 변환해야 합니다.
  4. 저장 용량: 로컬 스토리지는 브라우저별로 약 5~10MB의 저장 공간을 제공하며, 작은 양의 데이터를 저장하기에는 충분합니다. 다만 큰 파일이나 많은 양의 데이터를 저장하기에는 적합하지 않습니다.
  5. JavaScript API를 사용하여 접근 가능: 로컬 스토리지는 JavaScript를 이용해 접근하고 조작할 수 있습니다. 예를 들어, 데이터를 저장할 때는 localStorage.setItem(key, value)를 사용하고, 데이터를 불러올 때는 localStorage.getItem(key)을 사용합니다.

로컬 스토리지 사용 예시

// 데이터 저장하기
localStorage.setItem('username', 'JohnDoe');

// 데이터 불러오기
const username = localStorage.getItem('username');
console.log(username); // 'JohnDoe'

// 데이터 삭제하기
localStorage.removeItem('username');

로컬 스토리지를 사용하는 이유?

로컬 스토리지는 사용자가 설정이나 간단한 데이터를 유지해야 하는 경우에 아주 유용합니다. 예시

  • 사용자가 웹 페이지에서 설정한 테마 색상(다크 모드 등)을 유지하기.
  • 로그인한 사용자 이름을 저장하여 방문할 때마다 다시 입력하지 않도록 하기.
  • 쇼핑몰 사이트에서 장바구니에 담긴 상품 목록을 저장하여 새로고침 후에도 유지하기.

로컬 스토리지는 이런 용도로 간단하고 효과적으로 데이터를 저장할 수 있는 도구입니다


2. 로컬 스토리지를 활용한 웹 애플리케이션 만들기

이제 로컬 스토리지의 개념을 배웠으니, 즐겨찾는 링크를 저장하고 관리할 수 있는 간단한 웹 애플리케이션을 만들어 보겠습니다.

사용자가 즐겨찾고 싶은 웹 사이트의 이름과 URL을 입력하면, 이를 로컬 스토리지에 저장하고 화면에 보여주는 기능을 구현할 것입니다.

2.1 프로젝트 준비

웹 페이지는 HTML, CSS, 그리고 JavaScript를 사용해 구현할 것입니다.

간단한 HTML 폼을 통해 링크 이름과 URL을 입력받고, JavaScript로 로컬 스토리지에 저장합니다. 이를 통해 페이지를 새로고침해도 링크가 유지되도록 할 예정입니다.

2.2 HTML 구성하기

HTML 파일을 작성해 기본적인 구조를 만들어봅시다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>즐겨찾는 링크 저장하기</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>즐겨찾는 링크 저장하기</h1>
    <form id="link-form">
        <input type="text" id="link-name" placeholder="링크 이름" required>
        <input type="url" id="link-url" placeholder="URL 입력" required>
        <button type="submit">추가</button>
    </form>
    <div id="links-list"></div>
    <script src="script.js"></script>
</body>
</html>
  • form 태그를 사용해 사용자가 링크 이름과 URL을 입력할 수 있게 하고, 버튼을 클릭하면 링크를 추가할 수 있도록 합니다.
  • required 속성을 사용해 사용자가 빈칸을 제출하지 못하도록 설정했습니다.

2.3 CSS 스타일 추가하기

다음과 같이 style.css 파일을 만들어, 앱을 더 보기 좋게 만들어 봅시다.

body {
    font-family: Arial, sans-serif;
    background-color: #f9f9f9;
    padding: 20px;
}

#link-form {
    margin-bottom: 20px;
}

input {
    padding: 10px;
    margin-right: 10px;
    border: 1px solid #ccc;
}

button {
    padding: 10px;
    background-color: #28a745;
    color: white;
    border: none;
    cursor: pointer;
}

#links-list a {
    display: block;
    padding: 10px;
    border-bottom: 1px solid #eee;
    text-decoration: none;
    color: #333;
}

.delete-button {
    background-color: #dc3545;
    color: white;
    border: none;
    padding: 5px 10px;
    cursor: pointer;
    margin-left: 10px;
}

.delete-button:hover {
    background-color: #c82333;
}

.edit-button {
    background-color: #ffc107;
    color: white;
    border: none;
    padding: 5px 10px;
    cursor: pointer;
    margin-left: 10px;
}

.edit-button:hover {
    background-color: #e0a800;
}

.link-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    border-bottom: 1px solid #eee;
}

 

2.4 JavaScript로 기능 구현하기

이제 본격적으로 JavaScript를 사용해 로컬 스토리지를 활용하는 기능을 구현해 보겠습니다.

script.js 파일을 생성합니다.

2.4.1 링크 추가하기

사용자가 폼을 제출하면 JavaScript가 실행되어 사용자가 입력한 링크 이름과 URL을 로컬 스토리지에 저장합니다.

document.getElementById('link-form').addEventListener('submit', function (e) {
    e.preventDefault();

    const linkName = document.getElementById('link-name').value;
    const linkURL = document.getElementById('link-url').value;

    if (linkName && linkURL) {
        const newLink = { name: linkName, url: linkURL };
        let links = JSON.parse(localStorage.getItem('links')) || [];
        links.push(newLink);
        localStorage.setItem('links', JSON.stringify(links));
        displayLinks();
        document.getElementById('link-form').reset();
    }
});

 

  • e.preventDefault(): 폼 제출 시 페이지가 새로고침되는 기본 동작을 막습니다.
  • localStorage.getItem('links'): 로컬 스토리지에서 'links' 항목을 가져옵니다. 저장된 것이 없다면 빈 배열을 반환합니다.
  • localStorage.setItem('links', JSON.stringify(links)): 새로운 링크를 로컬 스토리지에 저장합니다. 로컬 스토리지는 문자열만 저장할 수 있으므로 JSON으로 변환합니다.

2.4.2 링크 목록 표시하기

로컬 스토리지에 저장된 링크들을 불러와 화면에 표시합니다. 페이지가 로드될 때마다 이 함수를 호출해 항상 최신 링크 목록을 화면에 보여줄 수 있습니다.

function displayLinks() {
    const linksList = document.getElementById('links-list');
    linksList.innerHTML = '';

    let links = JSON.parse(localStorage.getItem('links')) || [];

    links.forEach(function (link) {
        // 링크 요소 생성
        const linkContainer = document.createElement('div');
        linkContainer.classList.add('link-item');

        const linkElement = document.createElement('a');
        linkElement.href = link.url;
        linkElement.target = '_blank';
        linkElement.textContent = link.name;

        // 요소들 추가
        linkContainer.appendChild(linkElement);
        linksList.appendChild(linkContainer);
    });
}

// 페이지 로드 시 링크 목록 표시하기
document.addEventListener('DOMContentLoaded', displayLinks);

 

 

  • linksList.innerHTML = '': 링크 목록을 업데이트하기 전에 기존 목록을 지웁니다.
  • document.createElement('a'): 링크를 화면에 표시하기 위해 a 요소를 생성합니다.
  • linkElement.href = link.url: 링크의 URL을 설정하고, 새 탭에서 열리도록 target='_blank' 속성을 추가합니다.

2.4.3 링크 수정 기능 추가하기

이제 링크를 수정할 수 있도록 수정 버튼을 추가하고, 수정된 내용을 로컬 스토리지에 반영하겠습니다.

function displayLinks() {
    const linksList = document.getElementById('links-list');
    linksList.innerHTML = '';

    let links = JSON.parse(localStorage.getItem('links')) || [];

    links.forEach(function (link, index) {
        // 링크 요소 생성
        const linkContainer = document.createElement('div');
        linkContainer.classList.add('link-item');

        const linkElement = document.createElement('a');
        linkElement.href = link.url;
        linkElement.target = '_blank';
        linkElement.textContent = link.name;
        
        // 수정 버튼 생성
        const editButton = document.createElement('button');
        editButton.textContent = '수정';
        editButton.classList.add('edit-button');

        // 수정 버튼 클릭 이벤트 처리
        editButton.addEventListener('click', function () {
            const newName = prompt('새로운 링크 이름을 입력하세요:', link.name);
            const newURL = prompt('새로운 링크 URL을 입력하세요:', link.url);
            if (newName && newURL) {
                editLink(index, newName, newURL);
            }
        });

        // 요소들 추가
        linkContainer.appendChild(linkElement);
        linkContainer.appendChild(editButton);
        linksList.appendChild(linkContainer);
    });
}

function editLink(index, newName, newURL) {
    let links = JSON.parse(localStorage.getItem('links')) || [];
    links[index] = { name: newName, url: newURL };  // 링크 정보 수정
    localStorage.setItem('links', JSON.stringify(links));  // 로컬 스토리지에 변경 사항 저장
    displayLinks();  // 변경된 링크 목록 다시 표시
}
  • editButton.addEventListener('click', ...)를 통해 수정 버튼 클릭 시 수정할 내용을 입력받고, 이를 로컬 스토리지에 저장합니다.

2.4.4 링크 삭제 기능 추가하기

링크를 삭제할 수 있도록 삭제 버튼을 추가하고, 삭제된 내용을 로컬 스토리지에 반영합니다.

function displayLinks() {
    const linksList = document.getElementById('links-list');
    linksList.innerHTML = '';

    let links = JSON.parse(localStorage.getItem('links')) || [];

    links.forEach(function (link, index) {
        // 링크 요소 생성
        const linkContainer = document.createElement('div');
        linkContainer.classList.add('link-item');

        const linkElement = document.createElement('a');
        linkElement.href = link.url;
        linkElement.target = '_blank';
        linkElement.textContent = link.name;
        
        // 삭제 버튼 생성
        const deleteButton = document.createElement('button');
        deleteButton.textContent = '삭제';
        deleteButton.classList.add('delete-button');
        
        // 삭제 버튼 클릭 이벤트 처리
        deleteButton.addEventListener('click', function () {
            // 삭제 확인 모달
            if (confirm('정말 삭제하시겠습니까?')) {
                deleteLink(index);
            }
        });

        // 요소들 추가
        linkContainer.appendChild(linkElement);
        linkContainer.appendChild(deleteButton);
        linksList.appendChild(linkContainer);
    });
}

function deleteLink(index) {
    let links = JSON.parse(localStorage.getItem('links')) || [];
    links.splice(index, 1);  // 지정된 인덱스의 링크를 삭제
    localStorage.setItem('links', JSON.stringify(links));  // 로컬 스토리지에 변경 사항 저장
    displayLinks();  // 변경된 링크 목록 다시 표시
}
  • deleteButton.addEventListener('click', ...)를 통해 삭제 버튼 클릭 시 삭제 여부를 확인하고, 삭제 작업을 수행합니다.

3. 전체 코드 보기

아래는 이번에 구현한 즐겨찾기 링크 저장 웹 애플리케이션의 전체 코드입니다. 이 코드를 통해 링크 추가, 수정, 삭제 기능을 한 번에 확인할 수 있습니다.

HTML (index.html)

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>즐겨찾는 링크 저장하기</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>즐겨찾는 링크 저장하기</h1>
    <form id="link-form">
        <input type="text" id="link-name" placeholder="링크 이름" required>
        <input type="url" id="link-url" placeholder="URL 입력" required>
        <button type="submit">추가</button>
    </form>
    <div id="links-list"></div>
    <script src="script.js"></script>
</body>
</html>

 

CSS (style.css)

body {
    font-family: Arial, sans-serif;
    background-color: #f9f9f9;
    padding: 20px;
}

#link-form {
    margin-bottom: 20px;
}

input {
    padding: 10px;
    margin-right: 10px;
    border: 1px solid #ccc;
}

button {
    padding: 10px;
    background-color: #28a745;
    color: white;
    border: none;
    cursor: pointer;
}

#links-list .link-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    border-bottom: 1px solid #eee;
}

.delete-button {
    background-color: #dc3545;
    color: white;
    border: none;
    padding: 5px 10px;
    cursor: pointer;
    margin-left: 10px;
}

.delete-button:hover {
    background-color: #c82333;
}

.edit-button {
    background-color: #ffc107;
    color: white;
    border: none;
    padding: 5px 10px;
    cursor: pointer;
    margin-left: 10px;
}

.edit-button:hover {
    background-color: #e0a800;
}

JavaScript (script.js)

document.getElementById('link-form').addEventListener('submit', function (e) {
    e.preventDefault();

    const linkName = document.getElementById('link-name').value;
    const linkURL = document.getElementById('link-url').value;

    if (linkName && linkURL) {
        const newLink = { name: linkName, url: linkURL };
        let links = JSON.parse(localStorage.getItem('links')) || [];
        links.push(newLink);
        localStorage.setItem('links', JSON.stringify(links));
        displayLinks();
        document.getElementById('link-form').reset();
    }
});

function displayLinks() {
    const linksList = document.getElementById('links-list');
    linksList.innerHTML = '';

    let links = JSON.parse(localStorage.getItem('links')) || [];

    links.forEach(function (link, index) {
        // 링크 요소 생성
        const linkContainer = document.createElement('div');
        linkContainer.classList.add('link-item');

        const linkElement = document.createElement('a');
        linkElement.href = link.url;
        linkElement.target = '_blank';
        linkElement.textContent = link.name;
        
        // 수정 버튼 생성
        const editButton = document.createElement('button');
        editButton.textContent = '수정';
        editButton.classList.add('edit-button');

        // 수정 버튼 클릭 이벤트 처리
        editButton.addEventListener('click', function () {
            const newName = prompt('새로운 링크 이름을 입력하세요:', link.name);
            const newURL = prompt('새로운 링크 URL을 입력하세요:', link.url);
            if (newName && newURL) {
                editLink(index, newName, newURL);
            }
        });
        
        // 삭제 버튼 생성
        const deleteButton = document.createElement('button');
        deleteButton.textContent = '삭제';
        deleteButton.classList.add('delete-button');
        
        // 삭제 버튼 클릭 이벤트 처리
        deleteButton.addEventListener('click', function () {
            // 삭제 확인 모달
            if (confirm('정말 삭제하시겠습니까?')) {
                deleteLink(index);
            }
        });

        // 요소들 추가
        linkContainer.appendChild(linkElement);
        linkContainer.appendChild(editButton);
        linkContainer.appendChild(deleteButton);
        linksList.appendChild(linkContainer);
    });
}

function deleteLink(index) {
    let links = JSON.parse(localStorage.getItem('links')) || [];
    links.splice(index, 1);  // 지정된 인덱스의 링크를 삭제
    localStorage.setItem('links', JSON.stringify(links));  // 로컬 스토리지에 변경 사항 저장
    displayLinks();  // 변경된 링크 목록 다시 표시
}

function editLink(index, newName, newURL) {
    let links = JSON.parse(localStorage.getItem('links')) || [];
    links[index] = { name: newName, url: newURL };  // 링크 정보 수정
    localStorage.setItem('links', JSON.stringify(links));  // 로컬 스토리지에 변경 사항 저장
    displayLinks();  // 변경된 링크 목록 다시 표시
}

// 페이지 로드 시 링크 목록 표시하기
document.addEventListener('DOMContentLoaded', displayLinks);