DOM 中 div 的响应式重组
Responsive reorganizing of divs in DOM
我的项目使用 Tailwind + Vue 2。我使用 Vue 遍历列表并显示多行。每行开始时都是折叠的,并且可以选择展开。
每个折叠的行中有 3 个可见元素和 1 个隐藏元素 div。展开时,隐藏的 div 变为可见。我希望从每行中取出 2 个可见的 div 元素,并在移动设备上将它们移动到隐藏的下拉列表 div 中。在移动设备上展开时,我希望移动的元素可见。我还希望他们在从移动视图切换到桌面视图时向后移动。
预期行为如下:
在桌面上,折叠,显示切换开关和消息。
在桌面上,展开,显示切换开关和消息,不改变位置。
在移动设备上,折叠时,切换开关和消息不会显示,而是移动到折叠(隐藏)中div。
在移动设备上,展开,显示切换开关和消息。
这张照片展示了我想要实现的目标。
到目前为止,这些是我的尝试:
- CSS / Duplicate - 复制元素。使一个在移动设备上隐藏并在桌面上可见,另一个在移动设备上可见并在桌面上隐藏。虽然这不是一个干净的方法,但它似乎可以工作——直到我使用拨动开关。它失去了功能(我想是因为它被重复了)。
- Tailwind/CSS
order
- 正如实用程序名称所暗示的那样,页面上的顺序确实会改变,但这不会将所需的元素移动到一个隐藏元素;而是将其移动 above/below 隐藏元素。
- Vue Teleport - 这适用于 Vue 3,但也有适用于 Vue 2 的软件包,例如
portal-vue
。我试过了,由于行正在迭代,所有元素最终都被推到最后一行的展开视图中。我不想使用包。
- Javascript - 类似于 teleport/portal:标记 divs “move-from”和“move-to”并找到它们
getElementsByClassName
。遍历每个 move-me
和 dropdown
标签(每个 dropdown
标签有 2 个 move-me
标签)。为 window 添加事件侦听器调整大小并检查页面宽度是否 < 768。问题是,像 teleport/portal,它也会将所有元素填充到最后一行的展开视图中。
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])
}
}
}
只是提供一个答案,以便将其标记为已解决:
当您需要在桌面和移动设备之间使用不同的布局(即 html 标记)时,有一些解决方案:
- 复制元素,以便它们在 DOM 中同时位于桌面和移动位置。 使用 CSS 通过媒体查询隐藏一个或另一个。
+ 优点:易于设置,非常适合 SSR,不需要 js。
- 缺点:向 DOM 添加了额外的标记,如果执行太多次,可能会减慢页面呈现速度。
That's the solution I advise in OP's case
- 使用 javascript 动态渲染组件 在一个地方或另一个地方。在 vue 中,这意味着使用
v-if="isMobile"
.
+ 优点:避免 DOM 中的重影标记,如解决方案 1.
- 缺点:导致 SSR 闪烁(它在服务器上呈现为桌面或移动设备,然后在水合时更新为另一个布局)。
- 在某些情况下,仅使用 css 来移动 您的元素。喜欢
flex-direction: row-reverse
或 order: n
.
+ 优点:易于设置,无需 js。
- 缺点:仅适用于兄弟元素。
我的项目使用 Tailwind + Vue 2。我使用 Vue 遍历列表并显示多行。每行开始时都是折叠的,并且可以选择展开。
每个折叠的行中有 3 个可见元素和 1 个隐藏元素 div。展开时,隐藏的 div 变为可见。我希望从每行中取出 2 个可见的 div 元素,并在移动设备上将它们移动到隐藏的下拉列表 div 中。在移动设备上展开时,我希望移动的元素可见。我还希望他们在从移动视图切换到桌面视图时向后移动。
预期行为如下:
在桌面上,折叠,显示切换开关和消息。
在桌面上,展开,显示切换开关和消息,不改变位置。
在移动设备上,折叠时,切换开关和消息不会显示,而是移动到折叠(隐藏)中div。
在移动设备上,展开,显示切换开关和消息。
这张照片展示了我想要实现的目标。
到目前为止,这些是我的尝试:
- CSS / Duplicate - 复制元素。使一个在移动设备上隐藏并在桌面上可见,另一个在移动设备上可见并在桌面上隐藏。虽然这不是一个干净的方法,但它似乎可以工作——直到我使用拨动开关。它失去了功能(我想是因为它被重复了)。
- Tailwind/CSS
order
- 正如实用程序名称所暗示的那样,页面上的顺序确实会改变,但这不会将所需的元素移动到一个隐藏元素;而是将其移动 above/below 隐藏元素。 - Vue Teleport - 这适用于 Vue 3,但也有适用于 Vue 2 的软件包,例如
portal-vue
。我试过了,由于行正在迭代,所有元素最终都被推到最后一行的展开视图中。我不想使用包。 - Javascript - 类似于 teleport/portal:标记 divs “move-from”和“move-to”并找到它们
getElementsByClassName
。遍历每个move-me
和dropdown
标签(每个dropdown
标签有 2 个move-me
标签)。为 window 添加事件侦听器调整大小并检查页面宽度是否 < 768。问题是,像 teleport/portal,它也会将所有元素填充到最后一行的展开视图中。
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])
}
}
}
只是提供一个答案,以便将其标记为已解决:
当您需要在桌面和移动设备之间使用不同的布局(即 html 标记)时,有一些解决方案:
- 复制元素,以便它们在 DOM 中同时位于桌面和移动位置。 使用 CSS 通过媒体查询隐藏一个或另一个。
+ 优点:易于设置,非常适合 SSR,不需要 js。
- 缺点:向 DOM 添加了额外的标记,如果执行太多次,可能会减慢页面呈现速度。
That's the solution I advise in OP's case
- 使用 javascript 动态渲染组件 在一个地方或另一个地方。在 vue 中,这意味着使用
v-if="isMobile"
.
+ 优点:避免 DOM 中的重影标记,如解决方案 1.
- 缺点:导致 SSR 闪烁(它在服务器上呈现为桌面或移动设备,然后在水合时更新为另一个布局)。
- 在某些情况下,仅使用 css 来移动 您的元素。喜欢
flex-direction: row-reverse
或order: n
.
+ 优点:易于设置,无需 js。
- 缺点:仅适用于兄弟元素。