备忘录弹出层函数

发布于 2025-04-25 浏览 64 人次

封装一个美观、实用的备忘录弹出层函数,包含动画效果、样式隔离、快捷键保存等功能。以下是完整的实现:

/**
 * 备忘录弹出层函数
 * @param {string} [initialContent=''] - 初始文本内容
 * @param {function} [onSave=null] - 保存回调函数
 * @returns {object} 返回包含关闭方法的对象
 */
function createMemoPopup(initialContent = '', onSave = null) {
  // 生成随机ID用于样式隔离
  const memoId = 'memo-popup-' + Math.random().toString(36).substr(2, 9);
  
  // 创建DOM元素
  const overlay = document.createElement('div');
  const popup = document.createElement('div');
  const textarea = document.createElement('textarea');
  const closeBtn = document.createElement('button');
  const saveBtn = document.createElement('button');
  const hintText = document.createElement('div');
  const header = document.createElement('div');
  
  // 设置元素属性
  textarea.value = initialContent;
  textarea.placeholder = '记录您的想法或待办事项...';
  closeBtn.innerHTML = '×';
  saveBtn.textContent = '保存';
  hintText.textContent = '提示: Ctrl+S 保存';
  
  // 构建DOM结构
  header.appendChild(closeBtn);
  header.appendChild(hintText);
  popup.appendChild(header);
  popup.appendChild(textarea);
  popup.appendChild(saveBtn);
  overlay.appendChild(popup);
  
  // 添加到body
  document.body.appendChild(overlay);
  
  // 添加样式
  const style = document.createElement('style');
  style.textContent = `
    .${memoId}-overlay {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: rgba(0, 0, 0, 0.5);
      display: flex;
      justify-content: center;
      align-items: center;
      z-index: 1000;
      opacity: 0;
      transition: opacity 0.3s ease;
      backdrop-filter: blur(3px);
    }
    
    .${memoId}-popup {
      width: 90%;
      max-width: 600px;
      background: linear-gradient(135deg, #f5f7fa 0%, #e4e8eb 100%);
      border-radius: 12px;
      box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
      overflow: hidden;
      transform: translateY(-20px);
      transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
      border: 1px solid rgba(255, 255, 255, 0.3);
    }
    
    .${memoId}-popup-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 15px 20px;
      background: linear-gradient(to right, #6a11cb 0%, #2575fc 100%);
      color: white;
    }
    
    .${memoId}-close-btn {
      background: none;
      border: none;
      color: white;
      font-size: 24px;
      cursor: pointer;
      transition: transform 0.2s;
      padding: 0 10px;
    }
    
    .${memoId}-close-btn:hover {
      transform: scale(1.2);
    }
    
    .${memoId}-hint {
      font-size: 13px;
      opacity: 0.8;
    }
    
    .${memoId}-textarea {
      width: 100%;
      height: 300px;
      padding: 20px;
      border: none;
      resize: none;
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      font-size: 16px;
      line-height: 1.6;
      background-color: rgba(255, 255, 255, 0.8);
      color: #333;
      box-sizing: border-box;
      transition: background-color 0.3s;
    }
    
    .${memoId}-textarea:focus {
      outline: none;
      background-color: white;
    }
    
    .${memoId}-save-btn {
      display: block;
      width: 100%;
      padding: 12px;
      background: linear-gradient(to right, #4facfe 0%, #00f2fe 100%);
      color: white;
      border: none;
      font-size: 16px;
      font-weight: bold;
      cursor: pointer;
      transition: all 0.3s;
    }
    
    .${memoId}-save-btn:hover {
      background: linear-gradient(to right, #3a7bd5 0%, #00d2ff 100%);
    }
    
    @media (max-width: 600px) {
      .${memoId}-popup {
        width: 95%;
      }
      
      .${memoId}-textarea {
        height: 200px;
      }
    }
  `;
  
  document.head.appendChild(style);
  
  // 添加类名
  overlay.className = `${memoId}-overlay`;
  popup.className = `${memoId}-popup`;
  header.className = `${memoId}-popup-header`;
  closeBtn.className = `${memoId}-close-btn`;
  hintText.className = `${memoId}-hint`;
  textarea.className = `${memoId}-textarea`;
  saveBtn.className = `${memoId}-save-btn`;
  
  // 显示动画
  setTimeout(() => {
    overlay.style.opacity = '1';
    popup.style.transform = 'translateY(0)';
  }, 10);
  
  // 关闭函数
  function close() {
    overlay.style.opacity = '0';
    popup.style.transform = 'translateY(-20px)';
    
    setTimeout(() => {
      document.body.removeChild(overlay);
      document.head.removeChild(style);
    }, 300);
  }
  
  // 保存函数
  function save() {
    if (typeof onSave === 'function') {
      onSave(textarea.value);
    }
    
    // 添加保存动画反馈
    saveBtn.textContent = '✓ 已保存';
    setTimeout(() => {
      saveBtn.textContent = '保存';
    }, 1500);
  }
  
  // 事件监听
  closeBtn.addEventListener('click', close);
  saveBtn.addEventListener('click', save);
  
  // 快捷键保存
  textarea.addEventListener('keydown', (e) => {
    if ((e.ctrlKey || e.metaKey) && e.key === 's') {
      e.preventDefault();
      save();
    }
  });
  
  // 点击遮罩层关闭
  overlay.addEventListener('click', (e) => {
    if (e.target === overlay) {
      close();
    }
  });
  
  // 自动聚焦到文本域
  setTimeout(() => {
    textarea.focus();
  }, 350);
  
  // 返回关闭方法
  return {
    close: close,
    getContent: () => textarea.value,
    setContent: (content) => { textarea.value = content; }
  };
}

// 使用示例
// const memo = createMemoPopup('初始内容', (content) => {
//   console.log('保存的内容:', content);
//   // 这里可以添加保存到本地存储或其他逻辑
// });

功能特点:

  1. 样式隔离:使用随机生成的类名前缀,确保样式不会与其他元素冲突
  2. 响应式设计:适配不同屏幕尺寸,在手机上自动调整高度
  3. 动画效果

    • 淡入淡出的遮罩层
    • 弹窗滑入动画
    • 保存按钮的反馈动画
  4. 快捷键支持:支持 Ctrl+S 保存内容
  5. 美观UI

    • 渐变色标题栏
    • 毛玻璃遮罩效果
    • 精心设计的间距和字体
  6. 完整API

    • 可以获取/设置内容
    • 可以手动关闭弹窗
    • 支持保存回调
  7. 用户体验优化

    • 自动聚焦到文本域
    • 清晰的提示信息
    • 合理的过渡效果

您可以通过调用 createMemoPopup() 函数来使用这个弹窗,传入初始内容和保存回调函数即可。