基于HTML的悬窗可拖动记事本

这款记事本全部使用HTML+CSS+JS实现,可以在浏览器中实现悬浮可拖动的记事本,所有内容存储在浏览器中,清除缓存后将会丢失记事本内容

效果展示

image-78jx.png

image-oprn.png

动画.gif

实现代码

<div id="draggableWindowNote" class="draggableNote">
    <div id="dragHeaderNote" class="drag-headerNote">
        <span>Note</span>
        <div id="addNote" style="font-size: 19px;
        cursor: pointer;
        position: absolute;
        right: 0;
margin-right: 10px;">+</div>
    </div>

    <div id="noteApp">
        <div class="note-header">
        </div>
        <div id="noteList"></div>

        <div id="noteModal" class="modal">
            <div class="modal-content">
                <div class="modal-header">
                    <span class="close" style="float: left;">&times;</span>
                    <div
                        style="position: absolute; right: 0; top: 0; height: 100%; width: 78px; background-color: transparent;">
                    </div>
                </div>
                <textarea id="noteEditor"></textarea>
                <button id="saveNote"
                    style="cursor: pointer;border: none;background: transparent;font-weight: 900;">保存</button>
                <button id="deleteNote" class="delete-btn"
                    style="cursor: pointer;border: none;background: transparent;font-weight: 900;">删除</button>
            </div>
        </div>


    </div>
</div>

<!-- 沂霖博客 https://nanwish.love -->

<script>
    // 拖动逻辑
    const draggableWindow = document.getElementById('draggableWindowNote');
    const dragHeader = document.getElementById('dragHeaderNote');
    let isDragging = false;
    let offsetX, offsetY;
    dragHeader.addEventListener('mousedown', (e) => {
        isDragging = true;
        offsetX = e.clientX - draggableWindow.offsetLeft;
        offsetY = e.clientY - draggableWindow.offsetTop;
    });
    document.addEventListener('mousemove', (e) => {
        if (isDragging) {
            draggableWindow.style.left = (e.clientX - offsetX) + 'px';
            draggableWindow.style.top = (e.clientY - offsetY) + 'px';
        }
    });
    document.addEventListener('mouseup', () => {
        isDragging = false;
    });



</script>


<style>
    body {
        margin: 0;
        padding: 0;
        font-family: Arial, sans-serif;
        background-color: #575757;
        color: #ffffff;
    }

    .draggableNote {
        position: absolute;
        width: 200px;
        background-color: #242424;
        border-radius: 4px;
        box-shadow: 0 2px 10px rgba(168, 168, 168, 0.1);
        z-index: 1000;

    }

    .drag-headerNote {
        background-color: #000000;
        border-bottom: 1px solid #1be409;
        cursor: move;

        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: flex-start;
    }

    .chinaImg {
        width: 100%;
        max-width: 100%;
        max-height: 128px;
    }

    #noteApp {
        max-width: 600px;
        margin: 0 auto;
    }

    .note-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
    }


    .note-item {
        padding: 3px;
        border-bottom: 1px solid #eee;
        cursor: pointer;
    }

    .note-item:hover {
        background-color: #f5f5f5;
    }

    .note-title {
        font-weight: bold;
    }

    .note-content {
        display: none;
        margin-top: 10px;
        padding: 10px;
        background-color: #f9f9f9;
        border-radius: 3px;
    }

    .modal {
        display: none;
        position: fixed;
        z-index: 1;
        left: 0;
        top: 0;
        width: 100%;
        height: 1px;
    }

    .modal-content {
        background-color: transparent;
        margin: 15% auto;
        width: 80%;
        max-width: 500px;
    }

    #noteEditor {
        width: 100%;
        height: 200px;
        margin-bottom: 10px;
        border-radius: 17px;
        border: none;
        padding: 8px;
    }

    .close {
        color: #aaa;
        float: right;
        font-size: 28px;
        font-weight: bold;
        cursor: pointer;
        position: relative;
        z-index: 9;
    }

    .close:hover {
        color: black;
    }

    .delete-btn {
        color: rgb(255, 0, 0);
    }

    .modal-header {
        padding: 10px;
        cursor: move;
        position: relative;
        display: flex;
        flex-direction: row-reverse;
        align-items: center;
        justify-content: flex-start;
    }
</style>
<script>
    let notes = JSON.parse(localStorage.getItem('notes')) || [];
    let currentNoteIndex = -1;
    const noteList = document.getElementById('noteList');
    const noteModal = document.getElementById('noteModal');
    const noteEditor = document.getElementById('noteEditor');
    const addNoteBtn = document.getElementById('addNote');
    const saveNoteBtn = document.getElementById('saveNote');
    const deleteNoteBtn = document.getElementById('deleteNote');
    const closeBtn = document.querySelector('.close');

    function renderNotes() {
        noteList.innerHTML = '';
        notes.forEach((note, index) => {
            const noteItem = document.createElement('div');
            noteItem.className = 'note-item';

            // 截取前10个字符作为标题
            const title = note.content.substring(0, 10);

            noteItem.innerHTML = `
                <div class="note-title">${title}...</div>
                <div class="note-content">${note.content}</div>
            `;


            noteItem.addEventListener('click', () => {
                currentNoteIndex = index;
                noteEditor.value = note.content;
                noteModal.style.display = 'block';
            });

            noteList.appendChild(noteItem);
        });
    }

    // 新增笔记
    addNoteBtn.addEventListener('click', () => {
        currentNoteIndex = -1;
        noteEditor.value = '';
        noteModal.style.display = 'block';
    });

    // 保存笔记
    saveNoteBtn.addEventListener('click', () => {
        const content = noteEditor.value.trim();
        if (content) {
            if (currentNoteIndex === -1) {
                // 新增
                notes.push({ content });
            } else {
                // 编辑
                notes[currentNoteIndex].content = content;
            }

            localStorage.setItem('notes', JSON.stringify(notes));
            renderNotes();
            noteModal.style.display = 'none';
        }
    });

    // 删除笔记
    deleteNoteBtn.addEventListener('click', () => {
        if (currentNoteIndex !== -1) {
            notes.splice(currentNoteIndex, 1);
            localStorage.setItem('notes', JSON.stringify(notes));
            renderNotes();
            noteModal.style.display = 'none';
        }
    });

    // 关闭模态框
    closeBtn.addEventListener('click', () => {
        noteModal.style.display = 'none';
    });
    // 初始化
    renderNotes();


    // 模态框拖动功能
    const modal = document.getElementById('noteModal');
    const modalHeader = document.querySelector('.modal-header');
    let isModalDragging = false;
    let modalOffsetX, modalOffsetY;
    modalHeader.addEventListener('mousedown', (e) => {
        isModalDragging = true;
        modalOffsetX = e.clientX - modal.offsetLeft;
        modalOffsetY = e.clientY - modal.offsetTop;
    });
    document.addEventListener('mousemove', (e) => {
        if (isModalDragging) {
            modal.style.left = (e.clientX - modalOffsetX) + 'px';
            modal.style.top = (e.clientY - modalOffsetY) + 'px';
        }
    });
    document.addEventListener('mouseup', () => {
        isModalDragging = false;
    });
</script>