View Transition API does not work with document.createElement

49 views Asked by At

I am trying to create transition between pages using transition API. The transition works correctly when using elements defined using HTML, but the elements disappear on transition when using document.createElement to create the elements.

There is no point in providing JSFiddle link as it is necessary to add these files to a folder, start web server, open parent.html and click the image to navigate to child.html. Sorry for a lot of code, but I needed to provide everything as I am not sure where the problem is. Thanks!

parent.html

<script src="transition/utils.js"></script>
<script src="transition/script.js"></script>
<body>

<script>
    function add(){
        let a = document.createElement("a");
        a.setAttribute("href", "child.html");
        let img = document.createElement("img");
        img.setAttribute("src", "https://media.cnn.com/api/v1/images/stellar/prod/ap24002766263400.jpg?c=original");
        img.style.width = "300px";
        img.setAttribute("class", "img");
        a.appendChild(img);
        document.body.appendChild(a);
    }

    add();
</script>
</div>

<script src="transition/trans.js"></script>
</body>

child.html

<link rel="stylesheet" href="transition/style.css">
<script src="transition/utils.js"></script>
<script src="transition/script.js"></script>

<body>
    <div>
        <script>
            function add() {
                let a = document.createElement("a");
                a.setAttribute("href", "child.html");

                let img = document.createElement("img");
                img.setAttribute("src", "https://media.cnn.com/api/v1/images/stellar/prod/ap24002766263400.jpg?c=original");
                img.style.width = "700px";
                img.setAttribute("class", "img");
                a.appendChild(img);

                document.body.appendChild(a);
            }

            add();
        </script>
    </div>
    <script src="transition/trans.js"></script>
</body>

Here is my onLinkNavigate function that works when static elements are used:

script.js


onLinkNavigate(async ({ fromPath, toPath }) => {
  console.log(toPath);
  console.log(fromPath);

  const navType = 'gallery-to-teacher';
  const content = await getPageContent(toPath);

  let targetThumbnail;

  let targetHeader;


  if (navType === "gallery-to-teacher") { 
    targetThumbnail = document.querySelector(".img");
    targetThumbnail.style.viewTransformName = "banner-img";
  }

  const transition = transitionHelper({
    updateDOM() {
      document.body.innerHTML = content;
    }
  });

  transition.finished.finally(() => {
    if (targetThumbnail) {
      targetThumbnail.style.viewTransitionName = "";
    }

    if (targetHeader) {
      targetHeader.style.viewTransitionName = "";
    }

  });
});

utils.js

 async function getPageContent(url) {
    // This is a really scrappy way to do this.
    // Don't do this in production!
    const response = await fetch(url);
    const text = await response.text();
    // Particularly as it uses regexp
    return /<body[^>]*>([\w\W]*)<\/body>/.exec(text)[1];
  }
  
  function isBackNavigation(navigateEvent) {
    if (navigateEvent.navigationType === 'push' || navigateEvent.navigationType === 'replace') {
      return false;
    }
    if (
      navigateEvent.destination.index !== -1 &&
      navigateEvent.destination.index < navigation.currentEntry.index
    ) {
      return true;
    }
    return false;
  }
  
  // Intercept navigations
  // https://developer.chrome.com/docs/web-platform/navigation-api/
  // This is a naive usage of the navigation API, to keep things simple.
   async function onLinkNavigate(callback) {

    // not called on click!!!
      navigation.addEventListener('navigate', (event) => {
        const toUrl = new URL(event.destination.url);
        
        if (location.origin !== toUrl.origin) return;
        
        const fromPath = location.pathname;
        const isBack = isBackNavigation(event);
        
        event.intercept({
          handler() {
            if (event.info === 'ignore') return;
            
            callback({
              toPath: toUrl.pathname,
              fromPath,
              isBack,
            });
          },
        });
      });


   


  }
  
   function getLink(href) {
    console.warn(href);
    const fullLink = new URL(href, location.href).href;
    
    return [...document.querySelectorAll('a')].find((link) =>
      link.href === fullLink
    );
  }
  
  // This helper function returns a View-Transition-like object, even for browsers that don't support view transitions.
  // It won't do the transition in unsupported browsers, it'll act as if the transition is skipped.
  // It also makes it easier to add class names to the document element.
   function transitionHelper({
    skipTransition = false,
    classNames = '',
    updateDOM,
  }) {
    if (skipTransition || !document.startViewTransition) {
      const updateCallbackDone = Promise.resolve(updateDOM()).then(() => undefined);
  
      return {
        ready: Promise.reject(Error('View transitions unsupported')),
        domUpdated: updateCallbackDone,
        updateCallbackDone,
        finished: updateCallbackDone,
      };
    }
  
    const classNamesArray = classNames.split(/\s+/g).filter(Boolean);
  
    document.documentElement.classList.add(...classNamesArray);
  
    const transition = document.startViewTransition(updateDOM);
  
    transition.finished.finally(() =>
      document.documentElement.classList.remove(...classNamesArray)
    );
  
    return transition;
  }

trans.js

const el = document.querySelector('.img');
el.style.transition = 'view-transition-name img';
el.style.contain = 'layout';
0

There are 0 answers