Home > other >  Responsive reorganizing of divs in DOM
Responsive reorganizing of divs in DOM

Time:04-30

My project uses Tailwind Vue 2. I'm using Vue to iterate through a list and show multiple rows. Each row starts collapsed and has the option to be expanded.

There are 3 visible and 1 hidden div element in each collapsed row. When expanded, the hidden div is made visible. I'm looking to take 2 of the visible div elements from each row and move them into the hidden dropdown div when on mobile. When expanded on mobile, I expect the moved elements to be visible. I also want them to move back when switching from mobile to desktop view.

The expected behavior is as follows:

  • On desktop, collapsed, the toggle switch and message are displayed.

  • On desktop, expanded, the toggle switch and message are displayed, does not change location.

  • On mobile, collapsed, the toggle switch and message are NOT displayed, and are instead moved into the collapsed (hidden) div.

  • On mobile, expanded, the toggle switch and message are displayed.

This photo demonstrates what I'm looking to achieve.

demo

These have been my attempts so far:

  1. CSS / Duplicate - Duplicate the element. Make one hidden on mobile and visible on desktop, and the other visible on mobile and hidden on desktop. Although not a clean way of doing this, it appears to work -- until I use the toggle switch. It loses functionality (I assume since it's being repeated).
  2. Tailwind/CSS order - As the utility name suggests, the order on the page will indeed change, but this will not move the desired elements into a hidden element; rather move it above/below the hidden element.
  3. Vue Teleport - This is for Vue 3, but there are packages available for Vue 2, such as portal-vue. I tried it, and since the rows are being iterated, all of the elements end up shoved in the last row's expanded view. I would prefer not to use a package.
  4. Javascript - Similar to teleport/portal: tag divs "move-from" and "move-to" and find them with getElementsByClassName. Iterate through each move-me and dropdown tag (there are 2 move-me tags for every single dropdown tag). Add event listener for window resize and check to see if page width is < 768. The problem with this is, like teleport/portal, it also stuffs all the elements into the last row's expanded view.
if (this.width < 768) {
  const moveMeParent = document.getElementsByClassName('move-me') // there are 20 of these
  const dropdownParent = document.getElementsByClassName('dropdown') // there are 10 of these
  for (let i = 0; i < dropdownParent.length; i  ) {
    for (let j = 0; j < 2; j  ) {
      dropdownParent[i].appendChild(moveMeParent[0])
    }
  }
}

CodePudding user response:

Just to provide an anwser in order to mark this as solved:

When you need a different layout (i.e. html markup) between desktop & mobile, there are a few solutions there:

  1. Duplicating the elements so they are in both the desktop & mobile position in the DOM. Use CSS to hide one or the other with media queries.

Pros: easy to setup, works great for SSR, no js needed.
- Cons: adds additional markup to the DOM, which can slow down the page render if done too many times.

That's the solution I advise in OP's case

  1. Using javascript to dynamically render the components on a place or another. In vue, that means using v-if="isMobile".

Pros: avoid ghost markup in the DOM as in solution 1.
- Cons: causes flickering on SSR (it renders as desktop or mobile on the server, then updates to another layout when hydrated).

  1. On some cases, use css only to move your element. Like flex-direction: row-reverse or order: n.

Pros: easy to setup, no js needed.
- Cons: Only works for siblings elements.

  • Related