使用“动态宽度”时如何将过渡应用于 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
        
      ]
    ;
  

【讨论】:

嗯,这种方式仍然使用固定宽度,意思是我们预先提供了宽度的值。我的情况可能与我在问题中描述的情况有些不同。表单输入字段是从服务器查询的,因此每个表单的输入标签都不同。所以我只能在表单渲染后才能得到表单的宽度 好的,我想我更好地理解了这个问题,但我不太清楚解决方案。我可能会尝试使用$refsclientWidth,类似于这种情况:***.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,这意味着宽度 =“未设置”?的主要内容,如果未能解决你的问题,请参考以下文章

如何仅将 CSS 过渡应用于 transform 属性

如何将 CSS3 过渡应用于除背景位置之外的所有属性?

如何将 UINavigationControllerDelegate 中的自定义过渡动画应用于特定的推送和弹出事件?

过渡结束时应用 CSS 属性

如何设置动态宽度 UICollectionViewCell

在反应引导模式上指定/设置宽度和高度