vue 实现 input自动换行并自适应高度_通过Vue实现vw/vh自适应单位

本文介绍了如何通过Vue实现输入框(input)自动换行并自适应高度,以及如何使用vw/vh自适应单位。文章探讨了在响应式布局不适用时,如何利用JavaScript动态计算实现类似vw/vh的效果。通过监听屏幕尺寸变化,调整元素大小,以适应不同屏幕方向。在Vue中,结合生命周期钩子和MediaQueryList,实现了屏幕方向变化时的自动适配。最后,给出了代码示例和在线演示链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

虽然现在可能响应式布局多一些,但是我还是觉得自适应单位比较好用。对于一些框架的UI组件,例如Vuetify,可能并不支持使用自适应单位,此时就会非常影响布局效果。

这篇文章提供的方法可以帮助你实现这个功能,但是这个方法更适合实现需要在不同屏幕方向下使用不同长度单位的需求。

仅对于实现vw/vh来说,这不是非常完美的方法。

问题

首先,vw/vh就是基于当前视窗的百分比,这个我就不再阐述了。

我们来看一下环境:

 <v-progress-circular
            color="primary"
            indeterminate
            size="30vw"
            width="3"
          >
</v-progress-circular>
<!--  此时获取为30,默认单位为px,使用的是30px而不是30vw  -->

我们换个思路,既然不支持,因为自适应环境又很难获取到目标环境的具体像素值,那我们可以逆向工程实现一个动态计算的单位。

思路

我们通过JS捕获到用户的屏幕宽度,高度以及其他你想要使用的尺寸,对这个数据按照百分比计算就可以实现类似vw/vh的效果。

我会使用MQL来监听屏幕方向,下面我将解释原因。

当然,按照这个思路,做点别的也可以,比如获取一下其他的数据,宽度等等。

实现

首先我们需要获取用户屏幕的宽度和高度。

因为BOM里相关的数据非常多,我在这里推荐一篇文章:

关于js获取屏幕高度和宽度( window.document.body,window.screen)(PC端和移动端)​blog.csdn.net
a676d2aa7cf546ee7bc0007dc6d48b9a.png

我最后选择的是document.body.clientWidth/Height。

按照我的测试,虽然在旋转屏幕时两个数据会互换,也就是clientWidth是实际屏幕方向下的宽度,但是这个数据转换并没有引起Vue的第二次计算。我目前的解决方案是使用MQL的监听器,应该会有更好的方案。

虽然这个方法有点曲线救国的意思,但是实现并不是非常复杂,所以我保留了这个方法。

如果你正在处理的是一个小程序或者其他的内容,在限制屏幕方向的情况下,可以不考虑监听,跳过这一步。

this.size = document.body.clientWidth * 0.4;

我们使用 MediaQueryList 来捕获用户屏幕方向。

MediaQueryList​developer.mozilla.org
603917d87a49464c88de4f1e2a12d985.png

我大概解释一下,这个接口可以为我们提供相关的信息,如果你感兴趣可以仔细看一下我们获取的MQL对象内容。

MQL有点复杂,如果你想知道更多有关MQL的内容可以阅读MDN文档。

我们可以利用生命周期钩子实现这个功能,在这里我选择的是created。

created() {
    let mql = window.matchMedia("(orientation: portrait)");

同时,MQL会自带一个matches属性,当其值为真时即表明此时的屏幕方向为portait,即竖屏状态,你也可以将这个参数修改为landscape,即横屏。同时,我们可以使用MQL的addListener来订阅事件,监听屏幕方向变化。

我们并不需要在屏幕不同方向时做出不同的操作,所以我们可以省略MDN示例中的判断。当然,你也可以实现在不同屏幕方向(不同屏幕比例)时更换单位,但是因为我使用的Vuetify是有断点属性的,所以这里对我没有什么帮助。

    function handleOrientationChange(mql) {
        // 干点什么
    }
    mql.addListener(handleOrientationChange);

这样,我们整体的结构就基本上完成了。

我们可以把其带入到之前的监听器里:

    // 监听
    // eslint-disable-next-line no-unused-vars
    function handleOrientationChange(mql) {
        size = document.body.clientWidth * 0.4;
    }

因为我开启了ESLint,所以增加了注释。如果你没有开启ESLint,可以放弃这种写法。

这里放弃ESLint是为了减少代码量,否则的话就需要一个判断但是执行两个完全相同的语句。

如果你想在不同屏幕方向时使用不同的尺寸,则可以保留判断语句:

我引用MDN的例子:

var para = document.querySelector('p');
var mql = window.matchMedia('(max-width: 600px)');

function screenTest(e) {
  if (e.matches) {
    /* the viewport is 600 pixels wide or less */
    para.textContent = 'This is a narrow screen — less than 600px wide.';
    document.body.style.backgroundColor = 'red';
  } else {
    /* the viewport is more than than 600 pixels wide */
    para.textContent = 'This is a wide screen — more than 600px wide.';
    document.body.style.backgroundColor = 'blue';
  }
}

mql.addEventListener('change', screenTest);

我们回到template,依靠Vue的双向绑定,实现数据自动更新:

<v-progress-circular
            color="primary"
            indeterminate
            :size="size"
            width="3"
          >
</v-progress-circular>
data: () => ({
    size: null
  }),

因为我们的size初始值为null,为了不让在渲染时出问题,我们可以在created中填充一个默认值。我这里选择的是0.4,类似40vw。

同时,由于作用域,在一个函数内部使用this并不能访问到data中的数据,所以使用一个简单的声明解决这个小问题。

对应的,修改钩子:

  created() {
    let mql = window.matchMedia("(orientation: portrait)");
    let __this = this;
    // mql.matches为true时为竖屏
    this.size = document.body.clientWidth * 0.4;
    // 监听
    // eslint-disable-next-line no-unused-vars
    function handleOrientationChange(mql) {
      __this.size = document.body.clientWidth * 0.4;
    }
    mql.addListener(handleOrientationChange);
  }

效果

ff8c5776cdf360b54ab5172b20679da0.gif

Demo: ldwid.com

虽然我实装了这个属性,但是我没有对我的站点做更多的移动端横屏适配。

最后

感谢:

JS 获取和监听屏幕方向变化(portrait / landscape)​www.cnblogs.com
375cd4b74a1d48947d699f8e11149f70.png

继续给我自己打广告,有校招或者内推名额请联系我!我会很努力的!

<think>首先,用户的问题是关于Vue 3的:他们想在模态框(modal)中实现高度可变的模态框,确保输入框始终位于模态框的底部。我需要基于我的知识来回答,同时参考提供的引用内容。 回顾用户提供的引用: - 引用[1]:讨论了移动端模态框滚动穿透问题,使用了event.preventDefault()来处理。 - 引用[2]:展示了一个简单的Vue组件示例。 - 引用[3]:描述了登录界面的组件结构,包括表单验证数据绑定。 - 引用[4]:提到了使用Naive UI的模态框组件,有预设的dialog样式。 用户的问题焦点是:在Vue 3中,模态框高度可变时,如何保持输入框在底部。 关键点: - 模态框高度可变:意味着内容可能变化,导致模态框高度调整。 - 输入框始终在底部:无论模态框高度如何变化,输入框都应固定在底部。 在Web开发中,实现元素固定在容器底部通常使用CSS定位。常见方法: 1. **Flexbox**:使用flex布局,将容器设置为display: flex,flex-direction: column,然后让输入框部分margin-top: auto或align-self: flex-end。 2. **Position absolute**:将输入框设置为position: absolute; bottom: 0; 但需要确保模态框有position: relative。 3. **Grid**:类似flexbox,但使用CSS grid。 在Vue 3中,这主要是CSS问题,但Vue组件结构会影响实现。 参考引用: - 引用[4]提到了Naive UI的模态框,使用preset="dialog"。Naive UI是一个Vue UI库,其模态框可能有内置样式。用户可能在使用Naive UI或其他库。 - 用户没有指定UI库,所以我应该提供通用解决方案,但可以提到如果使用特定库如Naive UI。 用户问题:"我想在Vue 3中实现一个高度可变的模态框,确保输入框始终位于模态框底部" 所以,我需要: - 解释如何创建模态框。 - 确保输入框固定在底部。 - 处理高度可变性。 步骤: 1. **创建模态框组件**:在Vue 3中,模态框通常是一个组件,使用position: fixed或absolute覆盖整个屏幕。 2. **内部结构**:模态框内容区需要可滚动或自适应高度。 3. **固定输入框**:使用CSS将输入框固定在内容区底部。 4. **处理高度变化**:由于高度可变,内容可能溢出,需要确保模态框能滚动,而输入框保持固定。 CSS建议: - 模态框容器:position: fixed; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;(居中模态框) - 模态框内容区:background: white; padding: 20px; border-radius: 8px; max-height: 80vh; overflow-y: auto;(设置最大高度滚动) - 内部结构:使用flex column布局。 - 例如:<div class="modal-content"> <div class="modal-body"> <!-- 主要内容 --> </div> <div class="modal-footer"> <!-- 输入框按钮 --> </div> </div> - 在.modal-content中设置display: flex; flex-direction: column; height: 100%;(或min-height) - 然后.modal-body设置flex-grow: 1; overflow-y: auto;(允许内容滚动) - .modal-footer设置margin-top: auto; 或 align-self: flex-end; 来固定在底部。 在Vue 3组件中实现: - 使用<script setup>或Composition API。 - 数据绑定事件处理。 参考引用[3]:它提到了表单验证数据绑定,使用reactivev-model。类似地,这里可以绑定输入框的值。 引用[1]:关于滚动穿透,如果模态框内容滚动时底层页面滚动,需要阻止默认行为。但用户问题中没有提到移动端或滚动问题,所以可能不需要,但可以简要提及。 引用[4]:如果用户使用Naive UI,可以展示如何使用其模态框组件。但用户没有指定,所以我应该提供原生实现或通用方法。 最终回答结构: 1. **介绍**:简要解释问题。 2. **实现步骤**: - 创建模态框组件。 - 使用CSS布局固定输入框在底部。 - 处理高度可变性。 3. **代码示例**:提供Vue 3组件代码。 4. **注意事项**:如滚动处理、响应式设计。 5. **相关问题**:生成相关问题。 系统指令要求: - 行内数学表达式用$...$,但这里没有数学内容,所以不需要。 - 独立公式用$$...$$,同样不需要。 - LaTeX语法正确:不适用。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾添加引用标识:参考提供的引用,但用户引用是关于其他内容的,所以我需要谨慎引用。可能不需要直接引用,除非相关。 用户引用[1]是关于滚动穿透的,[3]是关于表单绑定的,[4]是关于Naive UI模态框的。可以引用[4]如果讨论Naive UI。 但用户说:"上述引用仅供参考,不是用户真正的需求",所以我可以忽略或简要参考。 在回答中,我可以提到类似引用中的概念。 生成相关问题: - 基于用户问题,相关问题如: 1. 如何在Vue 3中处理模态框滚动穿透问题? 2. 如何实现模态框的表单验证? 3. 使用Naive UI或其他库实现模态框的优缺点? 4. 如何使模态框响应式适应不同屏幕大小? 现在,构建回答。</think>### Vue 3 中实现高度可变模态框固定输入框在底部的解决方案Vue 3 中实现高度可变的模态框,确保输入框始终位于底部,主要依赖于 CSS 布局技术(如 Flexbox 或 Grid)结合 Vue 的响应式数据绑定。高度可变通常由动态内容(如列表、文本)引起,而固定底部元素需要将模态框内容区设计为可伸缩容器。以下是逐步实现方案,包括代码示例注意事项。 #### 1. **核心实现思路** - **模态框结构**:使用 Vue 组件创建模态框,外层为遮罩层(mask),内层为内容容器(content)。内容容器使用 Flexbox 的列布局(`flex-direction: column`),使主体内容可伸缩,输入框固定在底部。 - **高度可变处理**:设置内容主体区域(`modal-body`)为 `flex-grow: 1` `overflow-y: auto`,当内容增加时自动扩展高度支持滚动,输入框区域(`modal-footer`)通过 `margin-top: auto` 或 `align-self: flex-end` 固定在底部。 - **响应式设计**:使用 Vue 的 `ref` `reactive` 处理动态数据绑定,确保输入框值可追踪。 - **滚动穿透预防**:参考移动端最佳实践[^1],在遮罩层阻止默认滚动行为,避免底层页面滚动。 #### 2. **完整代码示例** 以下是一个 Vue 3 组件示例,使用 Composition API(`<script setup>` 语法)实现。组件包括: - 遮罩层(mask):阻止滚动穿透。 - 模态框内容区:动态高度,输入框固定在底部。 - 模拟高度变化按钮:演示内容增减时输入框位置不变。 ```vue <template> <!-- 遮罩层,阻止滚动穿透 --> <div v-if="showModal" class="modal-mask" @touchmove.prevent @wheel.prevent @click.self="closeModal" > <!-- 模态框内容容器 --> <div class="modal-container"> <div class="modal-header"> <h2>动态高度模态框</h2> </div> <!-- 主体内容区:高度可变,支持滚动 --> <div class="modal-body"> <p v-for="(item, index) in dynamicContent" :key="index">{{ item }}</p> </div> <!-- 输入框固定在底部 --> <div class="modal-footer"> <input v-model="inputValue" type="text" placeholder="输入框始终在底部" class="input-field" /> <button @click="addContent">添加内容</button> <button @click="closeModal">关闭</button> </div> </div> </div> <!-- 触发模态框按钮 --> <button @click="showModal = true">打开模态框</button> </template> <script setup> import { ref, reactive } from 'vue'; // 控制模态框显示 const showModal = ref(false); // 输入框数据绑定 const inputValue = ref(''); // 动态内容数组,模拟高度变化 const dynamicContent = reactive([ '初始内容行 1', '初始内容行 2' ]); // 添加内容,使模态框高度增加 const addContent = () => { dynamicContent.push(`新内容行 ${dynamicContent.length + 1}`); }; // 关闭模态框 const closeModal = () => { showModal.value = false; }; </script> <style scoped> /* 遮罩层:全屏固定,阻止底层滚动 */ .modal-mask { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 1000; } /* 模态框容器:固定宽度,最大高度,Flex 列布局 */ .modal-container { width: 80%; max-width: 500px; max-height: 80vh; /* 限制最大高度 */ background: white; border-radius: 8px; display: flex; flex-direction: column; /* 关键:列布局 */ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); } /* 主体内容区:可伸缩,支持滚动 */ .modal-body { flex-grow: 1; /* 关键:占据剩余空间 */ overflow-y: auto; /* 内容溢出时滚动 */ padding: 16px; border-top: 1px solid #eee; border-bottom: 1px solid #eee; } /* 底部输入框区域:固定在底部 */ .modal-footer { padding: 16px; display: flex; gap: 10px; margin-top: auto; /* 关键:自动上边距,固定在底部 */ } .input-field { flex-grow: 1; padding: 8px; border: 1px solid #ccc; border-radius: 4px; } button { padding: 8px 12px; cursor: pointer; } </style> ``` #### 3. **关键点解释** - **Flexbox 布局**:`.modal-container` 设置为 `flex-direction: column`,`.modal-body` 使用 `flex-grow: 1` 填充空间,`.modal-footer` 通过 `margin-top: auto` 固定在底部。即使 `.modal-body` 内容变化,输入框也不会移动。 - **高度可变处理**:`.modal-body` 的 `overflow-y: auto` 允许内容滚动,避免模态框无限增高。`max-height: 80vh` 确保模态框不会超出视口。 - **滚动穿透预防**:遮罩层(`.modal-mask`)使用 `@touchmove.prevent` `@wheel.prevent` 阻止默认滚动行为(参考引用[^1]),确保模态框内滚动时底层页面不滑动。 - **数据绑定**:使用 Vue 的 `ref` `reactive` 管理动态内容输入值,类似引用[^3]中的表单绑定方法。 - **响应式设计**:模态框宽度高度使用百分比视口单位(`vw`/`vh`),适应不同屏幕尺寸。 #### 4. **注意事项** - **移动端兼容性**:在移动设备上测试滚动行为,必要时添加 `-webkit-overflow-scrolling: touch` 优化滚动体验。 - **UI 库集成**:如果使用 Naive UI 等库(如引用[^4]),可以复用其模态框组件(`<n-modal>`),但需自定义插槽(slot)内容: ```vue <n-modal v-model:show="showModal" preset="dialog"> <template #default> <div class="custom-content"> <!-- 主体内容 --> <div class="modal-body">...</div> <!-- 底部输入框 --> <div class="modal-footer">...</div> </div> </template> </n-modal> ``` 在样式中应用相同的 Flexbox 逻辑。 - **性能优化**:当动态内容过多时,使用虚拟滚动(如 Vue Virtual Scroller)避免性能问题。 - **表单验证**:如需输入框验证,参考引用[^3]的方法,使用 Vue 的 `reactive` 验证库(如 VeeValidate)。 #### 5. **相关问题** 1. **如何在 Vue 3 中处理模态框滚动穿透问题?** (参考引用[^1],结合 `event.preventDefault()` CSS 溢出控制。) 2. **如何实现模态框的动态高度动画?** (使用 CSS 过渡或 Vue 的 `<Transition>` 组件,结合 `height: auto` `max-height` 动画。) 3. **在 Vue 3 中,如何集成 Naive UI 的模态框自定义布局?** (类似引用[^4],利用插槽预设属性扩展功能。) 4. **模态框内表单验证的最佳实践是什么?** (参考引用[^3],结合响应式数据验证规则库。) 通过以上方案,您可以轻松实现高度可变的模态框,确保输入框始终固定在底部,同时保持代码的可维护性响应性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值