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 API Portals đề xuất có thể cải thiện trải nghiệm người dùng khi đi theo chỉ dẫn của bạn.

Nguyễn Tuyết Anh
Yusuke Utsunomiya

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

Đề xuất API nền tảng web mới có tên Cổng nhằm giúp bạn làm việc 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ổng hoạt động:

Nhúng và di chuyển liền mạch bằng Portal. Tạo bởi Adam Argyle.

Những gì mà Cổng sẽ bật

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

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

Nhìn là tin vào điều: trước tiên, hãy xem những gì chúng tôi đã trình bày 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 đợi màn hình trống cho đến khi trình duyệt hoàn tất việc hiển thị đích đến. Với Portals, người dùng có thể trải nghiệm ảnh động, trong khi <portal> kết xuất trước nội dung và tạo ra trải nghiệm điều hướng liền mạch.

Trước Portals, 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 chuyển đến nội dung của ứng dụng. Cổng thông tin thu hẹp khoảng cách này, tạo ra các trường hợp sử dụng thú vị.

Dùng thử Cổng thông tin

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

Hãy dùng thử Portal trong Chrome 85 trở lên bằng cách lật cờ thử nghiệm:

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

Trong giai đoạn đầu này của thử nghiệm Portal, 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 kiểm thử bằng cách thiết lập cờ dòng lệnh --user-data-dir. Sau khi bật Cổng, hãy xác nhận trong Công cụ cho nhà phát triển rằng bạn có HTMLPortalElement mới nhất.

Ảnh chụp màn hình bảng điều khiển Công cụ cho nhà phát triển cho thấy HTMLPortalElement

Triển khai cổng thông tin

Hãy cùng 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 Công cụ cho nhà phát triển, trang wikipedia sẽ mở ra.

Ảnh GIF cho thấy bản minh hoạ kiểu cổng xem trước

Nếu bạn muốn xây dựng một cái gì đó giống như chúng tôi đã trình bày tại Hội nghị Nhà phát triển Chrome, hoạt động giống như bản minh hoạ ở trên, bạn có thể 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 để từng bước cải thiện trang web bằng cách sử dụng Cổng.

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 cảm nhận của Portal, hãy thử sử dụng uskay-cổngs-demo.glitch.me. Hãy đảm bảo bạn truy cập công cụ này với phiên bản Chrome 85 trở lên và bật cờ thử nghiệm!

  1. Nhập URL bạn muốn xem trước.
  2. Sau đó, trang này 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 ảnh động.

Ảnh GIF minh hoạ cách sử dụng Portals

Xem thông số kỹ thuật

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

  • Phần tử <portal>: Chính phần tử HTML. API này rất đơn giản. Phương thức này bao gồm thuộc tính src, hàm activate và một giao diện để nhắn tin (postMessage). activate lấy 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. Điều này giúp bạn kiểm tra xem trang có được nhúng dưới dạng phần tử <portal> hay không. Ứng dụng này cũng cung cấp một giao diện để nhắn tin (postMessage) lại cho máy chủ.
  • Giao diện PortalKích hoạtEvent: Một sự kiện sẽ kích hoạt khi <portal> được kích hoạt. Có một hàm đơn giản tên là adoptPredecessor, bạn có thể dùng hàm này để 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ó bố cục giữa hai trang.

Hãy cùng xem xét bên ngoài mô hình sử dụng cơ bản. Dưới đây là danh sách chưa đầy đủ về những gì bạn có thể đạt được với Cổng cùng với mã mẫu.

Tuỳ chỉnh kiểu khi được 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
}

Thông điệp 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 phiên bản 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 trang của bạn được sử dụng như một phiên bản 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ả tính năng mà Portal hỗ trợ, bạn có thể xây dựng những trải nghiệm người dùng thực sự bắt mắt. 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 người dùng liền mạch giữa một trang web và nội dung được nhúng của bên thứ ba.

Trường hợp sử dụng và gói dịch vụ

Chúng tôi hy vọng bạn thích chuyến tham quan ngắn này về Portals! Chúng tôi rất mong chờ những gì bạn có thể nghĩ ra. Ví dụ: có thể bạn muốn bắt đầu sử dụng Cổng thông tin cho các thao tác không quan trọng như: hiển thị trước trang về sản phẩm bán chạy nhất của bạn trên 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à Cổng thông tin có thể được dù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 bạn có nhiều trang web tham chiếu chéo nhau, bạn cũng có thể sử dụng Cổng để tạo đ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 khác biệt đối với Portal và thậm chí còn có thể giúp 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

Cổng đã sẵn sàng để thử nghiệm trong Chrome 85 trở lê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ó bất kỳ yêu cầu hoặc ý kiến phản hồi nào về tính năng, vui lòng chuyển đến kho lưu trữ GitHub về WICG.