使用“动态宽度”时如何将过渡应用于 v-dialog,这意味着宽度 =“未设置”?
Posted
技术标签:
【中文标题】使用“动态宽度”时如何将过渡应用于 v-dialog,这意味着宽度 =“未设置”?【英文标题】:How to have transition applied to v-dialog when using "dynamic width", meaning that width="unset"? 【发布时间】:2020-08-30 06:55:55 【问题描述】:基本上,我正在创建一个包含在 v-dialog 中的表单组件。表单组件将具有基于选择输入呈现的不同子组件。所以我必须将 v-dialog 的宽度设置为“未设置”,以便对话框的宽度会拉伸以匹配其内容。
当我切换宽度值时,过渡会起作用,例如:450px 或 300px。问题是我事先不知道对话框中包含的表单宽度,所以我肯定需要使用动态宽度。
到目前为止,我无法在使用动态宽度时找到实现过渡的方法。我试图使用 refs 获取表单组件的宽度,但是将宽度设置为未设置,以防止转换。顺便说一句,我所说的过渡是宽度的过渡,当使用固定宽度时,它显示出很好的过渡,但对于动态宽度则没有
<div id="app">
<v-app id="inspire">
<div class="text-center">
<v-dialog v-model="dialog" >
<template v-slot:activator=" on ">
<v-btn color="red lighten-2" dark v-on="on">
Click Me
</v-btn>
</template>
<v-card>
<v-select v-model="selectedForm" :items="items">
</v-select>
<div v-if="selectedForm==='form-a'" class='form-a'>FormA</div>
<div v-if="selectedForm==='form-b'" class='form-b'>FormB</div>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" text @click="dialog = false">
I accept
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</v-app>
</div>
new Vue(
el: "#app",
vuetify: new Vuetify(),
data()
return
selectedForm: "form-a",
items: ["form-a", "form-b"],
dialog: false
;
);
使用固定宽度的代码笔:https://codepen.io/duongthienlee/pen/MWaBLXm 使用动态宽度的代码笔:https://codepen.io/duongthienlee/pen/GRpBzmL
请注意,在我在 codepen 中制作的示例中,我已经定义了宽度,但实际情况是我事先不知道 form-a 和 form-b 组件的宽度。 form-a 和 form-b 的宽度将由其父 div 继承,即 v-dialog,所以这就是我将 v-dialog 的宽度设置为未设置的原因。 我所说的“动态宽度”的一个例子:form-a 有一个选择输入。当用户选择一个项目时,将请求服务器获取输入标签。因此 form-a 将根据来自服务器的响应正文呈现多个输入字段。响应正文将包含标签和默认值信息。这样就使得form-a的宽度变成了动态的。
【问题讨论】:
【参考方案1】:我认为这样的事情对你有用。
像这样更改v-dialog
:
<v-dialog v-model="dialog" :>
修改 data() 以返回 forms
属性:
data()
return
selectedForm: "form-a",
items: ["form-a", "form-b"],
dialog: false,
forms: [
name: 'form-a',
width: 200
,
name: 'form-b',
width: 1000
]
;
【讨论】:
嗯,这种方式仍然使用固定宽度,意思是我们预先提供了宽度的值。我的情况可能与我在问题中描述的情况有些不同。表单输入字段是从服务器查询的,因此每个表单的输入标签都不同。所以我只能在表单渲染后才能得到表单的宽度 好的,我想我更好地理解了这个问题,但我不太清楚解决方案。我可能会尝试使用$refs
和clientWidth
,类似于这种情况:***.com/questions/44948714/…
我使用refs获取clientWidth时的问题是我仍然需要将模态的宽度指定为“未设置”,以便模态(表单)的内容将具有它的宽度.但是,由于宽度设置为未设置,因此即使我得到宽度,过渡也不起作用。【参考方案2】:
您要做的是获取渲染表单的大小,然后将其应用于对话框。 这是尝试使用动态尺寸为内容制作动画时的常见主题。 一种方法是:
-
将表单的可见性设置为隐藏
等待渲染
获取表单的宽度并将其设置为对话框
取消设置表单的可见性
棘手/棘手的部分是您必须正确等待 DOM (setTimeout
) 和 Vue ($nextTick
) 重新计算。在此示例中,我不必等待 Vue 的 $nextTick
,但如果您正在渲染嵌套表单组件,您可能会这样做:
<div class="form-container">
<div :style="formStyle('form-a')" class='form-a' ref="form-a">FormA</div>
<div :style="formStyle('form-b')" class='form-b' ref="form-b">FormB</div>
</div>
computed:
formStyle()
return form => (
visibility: this.selectedForm == form ? 'inherit' : 'hidden',
position: this.selectedForm == form ? 'inherit' : 'absolute'
)
,
methods:
async onSelectChange(form)
// async request
await new Promise(resolve => setTimeout(resolve, 1000))
this.selectedForm = form
this.recalculate()
,
async recalculate()
// wait for DOM to recalculate
await new Promise(resolve => setTimeout(resolve))
const formEl = this.$refs[this.selectedForm]
this.dialogWidth = formEl.clientWidth
this.dialogHeight = formEl.clientHeight
,
...
以下是可让您了解的工作代码: https://codepen.io/cuzox/pen/yLYwoQo
【讨论】:
【参考方案3】:如果我理解正确,那么这可以使用 css 来完成。您可以尝试将表单中的所有固定宽度替换为
width: fit-content;
例如在你的codepen中:
.form-a
width: fit-content;
height: 350px;
background: blue;
.form-b
width: fit-content;
height: 500px;
background: red;
【讨论】:
这不是我正在寻找的,因为我认为问题出在 v-dialog 组件上而不是表单组件上。将 v-dialog 组件的宽度设置为未设置将使表单组件具有其最大宽度。我可能需要稍微改写我的问题。【参考方案4】:v-dialog 渲染成一个带有 v-dialog 类的 div:
似乎动画仅在宽度为已知值时才有效,因此不能只是“取消设置”。解决方案是获取子元素的宽度,并使用变量相应地设置 v-dialog 的宽度。
查看VueJS get Width of Div了解如何获取子元素的宽度。
让我知道它是否有效,我觉得这很有趣。
【讨论】:
如果我忽略将宽度设置为“未设置”,v-dialog 会将对话框组件渲染为 100% 宽度减去边距。问题是我不知道表单组件的宽度,因为它取决于用户的选择。所以让 v-dialog 组件不渲染到 100% 的唯一方法是设置 。 您能否详细说明表单宽度如何根据用户选择而变化?这个宽度不能被捕获到设置 v-dialog 宽度的动态变量中吗? 举个例子:form-a有一个选择输入。当用户选择一个项目时,将请求服务器获取输入标签。因此 form-a 将根据来自服务器的响应正文呈现多个输入字段。响应正文将包含标签和默认值信息。这样就使得form-a的宽度变成动态的以上是关于使用“动态宽度”时如何将过渡应用于 v-dialog,这意味着宽度 =“未设置”?的主要内容,如果未能解决你的问题,请参考以下文章