Đến nội dung chính

Menu nhấn giữ

Dành cho ba bốn hành động thuộc riêng một dòng, mở ngay tại chỗ thay vì trên một màn hình riêng.

Nút và hành động

Xem trước trực tiếp

Nguồn

<div class="dc-lp">
  <details class="dc-lp__box">
    <summary class="dc-lp__item">
      <span class="dc-lp__name">현장 점검 보고서.pdf</span>
      <span class="dc-lp__meta">2.4MB · 어제 오후 5:12</span>
    </summary>
    <div class="dc-lp__menu" role="group" aria-label="파일 동작">
      <button class="dc-lp__act" type="button">이름 바꾸기</button>
      <button class="dc-lp__act" type="button">공유</button>
      <button class="dc-lp__act dc-lp__act--danger" type="button">삭제</button>
    </div>
  </details>
  <p class="dc-lp__hint">길게 누르면 열립니다. 짧게 눌러도 같은 메뉴가 열려 누구나 닿을 수 있습니다.</p>
</div>
.dc-lp {
  padding: var(--dc-4);
  background: var(--dc-bg);
  font-family: var(--dc-font);
}
.dc-lp__box {
  border: 1px solid var(--dc-line);
  border-radius: var(--dc-r-md);
  background: var(--dc-surface);
  box-shadow: var(--dc-sh-1);
}
.dc-lp__item {
  display: flex;
  flex-direction: column;
  gap: var(--dc-1);
  min-height: 44px;
  padding: var(--dc-3) var(--dc-4);
  border-radius: var(--dc-r-md);
  list-style: none;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.dc-lp__item::-webkit-details-marker { display: none; }
.dc-lp__item::marker { content: ""; }
.dc-lp__box[open] .dc-lp__item {
  border-bottom: 1px solid var(--dc-line);
  border-radius: var(--dc-r-md) var(--dc-r-md) 0 0;
  background: var(--dc-sunken);
}
.dc-lp__name {
  font-size: 15px;
  font-weight: 600;
  color: var(--dc-text);
}
.dc-lp__meta {
  font-size: 12px;
  color: var(--dc-text-mute);
}
.dc-lp__menu {
  display: flex;
  flex-direction: column;
  padding: var(--dc-1);
}
.dc-lp__act {
  display: flex;
  align-items: center;
  gap: var(--dc-3);
  min-height: 48px;
  padding: 0 var(--dc-3);
  border: 0;
  border-radius: var(--dc-r-sm);
  background: none;
  color: var(--dc-text);
  font-family: var(--dc-font);
  font-size: 15px;
  text-align: left;
  cursor: pointer;
  transition: background var(--dc-fast);
}
.dc-lp__act:hover { background: var(--dc-sunken); }
.dc-lp__act--danger { color: var(--dc-danger); }
.dc-lp__ico {
  width: 20px;
  height: 20px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.dc-lp__hint {
  margin: var(--dc-3) 0 0;
  font-size: 12px;
  line-height: 1.6;
  color: var(--dc-text-mute);
}
document.querySelectorAll('.dc-lp__box').forEach(function (box) {
  var item = box.querySelector('.dc-lp__item');
  if (!item) return;
  var timer = null;
  function clear() {
    if (timer) { clearTimeout(timer); timer = null; }
  }
  item.addEventListener('pointerdown', function () {
    clear();
    timer = setTimeout(function () {
      timer = null;
      box.open = true;
    }, 450);
  });
  ['pointerup', 'pointercancel', 'pointerleave'].forEach(function (name) {
    item.addEventListener(name, clear);
  });
});

Cách dùng

  • Chỉ gom hành động thuộc đúng mục đó; hành động cho cả màn hình thì đặt ở thanh trên
  • Đặt hành động nguy hiểm cuối cùng và tô khác màu để ngón tay không chạm nhầm
  • Giữ chính mục đó hiện trên menu để không nhầm hành động đang áp cho cái gì

Điểm cần lưu ý

  • Nhấn giữ là thao tác vô hình: hãy cho nhấn ngắn cũng mở, hoặc kèm nút xem thêm
  • Dựng trên details/summary thì menu vẫn mở khi script lỗi — script chỉ thêm phần nhấn giữ
  • Cho mỗi dòng menu cao khoảng 48px; dòng sát nhau rất dễ nhấn lệch

Tiếp theo