Thực hành với Cổng: điều hướng liền mạch trên web

Tìm hiểu cách Portals API đề xuất có thể cải thiện trải nghiệm người dùng trong việc điều hướng.

Yusuke Utsunomiya
Yusuke Utsunomiya

Đảm bảo trang tải nhanh là yếu tố then chốt để mang đến trải nghiệm tốt cho người dùng. Tuy nhiên, một khía cạnh mà chúng ta thường bỏ qua là hiệu ứng chuyển đổi trang – nội dung mà người dùng nhìn thấy khi di chuyển giữa các trang.

Đề xuất API nền tảng web mới có tên là Cổng nhằm giúp giải quyết vấn đề này bằng cách đơn giản hoá trải nghiệm khi người dùng di chuyển trên trang web của bạn.

Xem cách hoạt động của Cổng thông tin:

Nhúng và điều hướng liền mạch bằng Cổng thông tin. Do Adam Argyle tạo.

Chức năng của Cổng

Ứng dụng một trang (SPA) cung cấp các hiệu ứng chuyển đổi đẹp mắt nhưng chi phí xây dựng lại cao hơn. Ứng dụng nhiều trang (MPA) dễ tạo hơn nhiều, nhưng bạn sẽ thấy màn hình trống giữa các trang.

Cổng cung cấp những ưu điểm tốt nhất của cả hai: độ phức tạp thấp của MPA với khả năng chuyển đổi liền mạch của SPA. Hãy coi chúng như một <iframe> vì chúng cho phép nhúng, nhưng không giống như <iframe>, chúng cũng có các tính năng để điều hướng đến nội dung của mình.

Thấy mới tin: trước tiên, vui lòng xem những nội dung chúng tôi giới thiệu tại Hội nghị nhà phát triển Chrome 2018:

Với các thao tác điều hướng kiểu cũ, người dùng phải chờ trên màn hình trống cho đến khi trình duyệt kết thúc quá trình hiển thị đích đến. Với Cổng thông tin, người dùng có thể trải nghiệm ảnh động, trong khi <portal> hiển thị trước nội dung và tạo trải nghiệm điều hướng liền mạch.

Trước khi có Cổng thông tin, chúng ta có thể hiển thị một trang khác bằng <iframe>. Chúng ta cũng có thể thêm ảnh động để di chuyển khung xung quanh trang. Tuy nhiên, <iframe> sẽ không cho phép bạn điều hướng vào nội dung của nó. Cổng thông tin giúp khắc phục khoảng trống này, cho phép các trường hợp sử dụng thú vị.

Dùng thử Cổng

Bật thông qua about://flags

Dùng thử Cổng thông tin trong Chrome phiên bản 85 trở lên bằng cách bật một cờ thử nghiệm:

  • Bật cờ about://flags/#enable-portals cho các thao tác điều hướng cùng nguồn gốc.
  • Để kiểm thử thao tác điều hướng nhiều nguồn gốc, hãy bật cờ about://flags/#enable-portals-cross-origin.

Trong giai đoạn đầu của thử nghiệm Cổng thông tin, bạn cũng nên sử dụng một thư mục dữ liệu người dùng hoàn toàn riêng biệt cho các chương trình kiểm thử bằng cách đặt cờ dòng lệnh --user-data-dir. Sau khi bật Cổng, hãy xác nhận trong DevTools rằng bạn có HTMLPortalElement mới.

Ảnh chụp màn hình bảng điều khiển DevTools cho thấy HTMLPortalElement

Triển khai Cổng thông tin

Hãy xem một ví dụ triển khai cơ bản.

// Create a portal with the wikipedia page, and embed it
// (like an iframe). You can also use the <portal> tag instead.
portal = document.createElement('portal');
portal.src = 'https://en.wikipedia.org/wiki/World_Wide_Web';
portal.style = '...';
document.body.appendChild(portal);

// When the user touches the preview (embedded portal):
// do fancy animation, e.g. expand …
// and finish by doing the actual transition.
// For the sake of simplicity, this snippet will navigate
// on the `onload` event of the Portals element.
portal.addEventListener('load', (evt) => {
   portal.activate();
});

Thật đơn giản. Hãy thử mã này trong bảng điều khiển DevTools, trang wikipedia sẽ mở ra.

Ảnh gif về bản minh hoạ kiểu cổng xem trước

Nếu bạn muốn tạo một ứng dụng như chúng tôi đã trình bày tại Hội nghị nhà phát triển Chrome và ứng dụng đó hoạt động giống như bản minh hoạ ở trên, thì bạn sẽ quan tâm đến đoạn mã sau.

// Adding some styles with transitions
const style = document.createElement('style');
style.innerHTML = `
  portal {
    position:fixed;
    width: 100%;
    height: 100%;
    opacity: 0;
    box-shadow: 0 0 20px 10px #999;
    transform: scale(0.4);
    transform-origin: bottom left;
    bottom: 20px;
    left: 20px;
    animation-name: fade-in;
    animation-duration: 1s;
    animation-delay: 2s;
    animation-fill-mode: forwards;
  }
  .portal-transition {
    transition: transform 0.4s;
  }
  @media (prefers-reduced-motion: reduce) {
    .portal-transition {
      transition: transform 0.001s;
    }
  }
  .portal-reveal {
    transform: scale(1.0) translateX(-20px) translateY(20px);
  }
  @keyframes fade-in {
    0%   { opacity: 0; }
    100% { opacity: 1; }
  }
`;
const portal = document.createElement('portal');
// Let's navigate into the WICG Portals spec page
portal.src = 'https://wicg.github.io/portals/';
// Add a class that defines the transition. Consider using
// `prefers-reduced-motion` media query to control the animation.
// https://developers.google.com/web/updates/2019/03/prefers-reduced-motion
portal.classList.add('portal-transition');
portal.addEventListener('click', (evt) => {
  // Animate the portal once user interacts
  portal.classList.add('portal-reveal');
});
portal.addEventListener('transitionend', (evt) => {
  if (evt.propertyName == 'transform') {
    // Activate the portal once the transition has completed
    portal.activate();
  }
});
document.body.append(style, portal);

Bạn cũng có thể dễ dàng phát hiện tính năng để cải thiện dần trang web bằng Cổng thông tin.

if ('HTMLPortalElement' in window) {
  // If this is a platform that have Portals...
  const portal = document.createElement('portal');
  ...
}

Nếu bạn muốn nhanh chóng trải nghiệm Portals, hãy thử sử dụng uskay-portals-demo.glitch.me. Hãy nhớ truy cập vào trang này bằng Chrome phiên bản 85 trở lên và bật cờ thử nghiệm!

  1. Nhập URL mà bạn muốn xem trước.
  2. Sau đó, trang sẽ được nhúng dưới dạng phần tử <portal>.
  3. Nhấp vào bản xem trước.
  4. Bản xem trước sẽ được kích hoạt sau một ảnh động.

Ảnh gif minh hoạ cách sử dụng bản minh hoạ lỗi khi sử dụng Cổng

Xem thông số kỹ thuật

Chúng tôi đang tích cực thảo luận về thông số kỹ thuật của Cổng thông tin trong Nhóm cộng đồng ươm tạo web (WICG). Để nhanh chóng nắm bắt, hãy xem một số trường hợp chính. Sau đây là 3 tính năng quan trọng mà bạn cần làm quen:

  • Phần tử <portal>: Chính phần tử HTML. API này rất đơn giản. Thành phần này bao gồm thuộc tính src, hàm activate và giao diện để nhắn tin (postMessage). activate nhận một đối số không bắt buộc để truyền dữ liệu đến <portal> khi kích hoạt.
  • Giao diện portalHost: Thêm đối tượng portalHost vào đối tượng window. Thao tác này cho phép bạn kiểm tra xem trang có được nhúng dưới dạng phần tử <portal> hay không. Lớp này cũng cung cấp giao diện để nhắn tin (postMessage) lại cho máy chủ lưu trữ.
  • Giao diện PortalActivateEvent: Một sự kiện kích hoạt khi <portal> được kích hoạt. Có một hàm gọn gàng tên là adoptPredecessor mà bạn có thể dùng để truy xuất trang trước dưới dạng phần tử <portal>. Điều này cho phép bạn tạo các thao tác điều hướng liền mạch và trải nghiệm được kết hợp giữa hai trang.

Hãy xem xét những mẫu sử dụng cơ bản. Dưới đây là danh sách (không đầy đủ) những việc bạn có thể làm được với Cổng thông tin cùng với mã mẫu.

Tuỳ chỉnh kiểu khi nhúng dưới dạng phần tử <portal>

// Detect whether this page is hosted in a portal
if (window.portalHost) {
  // Customize the UI when being embedded as a portal
}

Gửi tin nhắn giữa phần tử <portal>portalHost

// Send message to the portal element
const portal = document.querySelector('portal');
portal.postMessage({someKey: someValue}, ORIGIN);

// Receive message via window.portalHost
window.portalHost.addEventListener('message', (evt) => {
  const data = evt.data.someKey;
  // handle the event
});

Kích hoạt phần tử <portal> và nhận sự kiện portalactivate

// You can optionally add data to the argument of the activate function
portal.activate({data: {somekey: 'somevalue'}});

// The portal content will receive the portalactivate event
// when the activate happens
window.addEventListener('portalactivate', (evt) => {
  // Data available as evt.data
  const data = evt.data;
});

Truy xuất phần tử trước đó

// Listen to the portalactivate event
window.addEventListener('portalactivate', (evt) => {
  // ... and creatively use the predecessor
  const portal = evt.adoptPredecessor();
  document.querySelector('someElm').appendChild(portal);
});

Biết rằng trang của bạn đã được sử dụng làm trang trước

// The activate function returns a Promise.
// When the promise resolves, it means that the portal has been activated.
// If this document was adopted by it, then window.portalHost will exist.
portal.activate().then(() => {
  // Check if this document was adopted into a portal element.
  if (window.portalHost) {
    // You can start communicating with the portal element
    // i.e. listen to messages
    window.portalHost.addEventListener('message', (evt) => {
      // handle the event
    });
  }
});

Bằng cách kết hợp tất cả các tính năng mà Cổng hỗ trợ, bạn có thể tạo ra trải nghiệm người dùng thực sự hấp dẫn. Ví dụ: bản minh hoạ bên dưới cho thấy cách Cổng có thể mang lại trải nghiệm liền mạch cho người dùng giữa một trang web và nội dung nhúng của bên thứ ba.

Trường hợp sử dụng và kế hoạch

Chúng tôi hy vọng bạn thích phần giới thiệu ngắn gọn về Cổng này! Chúng tôi rất mong được xem những sản phẩm mà bạn tạo ra. Ví dụ: bạn có thể bắt đầu sử dụng Cổng thông tin cho các thao tác điều hướng không quan trọng, chẳng hạn như: kết xuất trước trang cho sản phẩm bán chạy nhất từ trang thông tin danh mục sản phẩm.

Một điều quan trọng khác cần biết là bạn có thể sử dụng Cổng trong các thao tác điều hướng trên nhiều nguồn gốc, giống như <iframe>. Vì vậy, nếu có nhiều trang web tham chiếu chéo lẫn nhau, bạn cũng có thể sử dụng Cổng thông tin để tạo các thao tác điều hướng liền mạch giữa hai trang web khác nhau. Trường hợp sử dụng nhiều nguồn gốc này rất đặc trưng cho Cổng thông tin và thậm chí có thể cải thiện trải nghiệm người dùng của SPA.

Chúng tôi mong nhận được ý kiến phản hồi của bạn

Bạn có thể thử nghiệm Cổng thông tin trong Chrome phiên bản 85 trở lên. Ý kiến phản hồi của cộng đồng rất quan trọng đối với việc thiết kế API mới. Vì vậy, vui lòng dùng thử và cho chúng tôi biết suy nghĩ của bạn! Nếu bạn có yêu cầu về tính năng hoặc ý kiến phản hồi, vui lòng truy cập vào kho lưu trữ GitHub của WICG.