我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Vue中textarea自适应高度方案的实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Vue中textarea自适应高度方案的实现

先给方案,Vue栈有需求的同学可以直接下载vue-awesome-textarea

隐藏的问题

抛开原生JS,框架的大部分UI库都支持自适应textarea高度功能,但普遍都忽略了一个功能,就是自适应高度的回显。

使用这些库的时候,我们很容易的在textarea中键入内容,超出范围时会自动延展一行,保证内容高度的自适应。当我们提交内容,在其它页面使用同样的UI来渲染时,麻烦的就来了,有些UI库是不支持自适应回显的,这就需要我们通过行高、行数甚至高度之间的计算得出一个基值,从而实现回显。

解决自适应高度的方案

常见得方案有两种,一种是在页面地“边远地区”添加一个ghost dom来模拟输入换行,这个dom的可能是editable属性为true的div或者是一个一摸一样得textarea。
以element-ui的input组件举例,当我们在组件内输入值时,会调用resizeTextarea方法


resizeTextarea() {
  if (this.$isServer) return;
  const { autosize, type } = this;
  if (type !== 'textarea') return;
  if (!autosize) {
    this.textareaCalcStyle = {
      minHeight: calcTextareaHeight(this.$refs.textarea).minHeight
    };
    return;
  }
  const minRows = autosize.minRows;
  const maxRows = autosize.maxRows;

  this.textareaCalcStyle = calcTextareaHeight(this.$refs.textarea, minRows, maxRows);
}

当设置了autosize为true则textarea设为自适应高度。此时textarea的高度会通过calcTextareaHeight方法实时计算。

export default function calcTextareaHeight(
  targetElement,
  minRows = 1,
  maxRows = null
) {
  if (!hiddenTextarea) {
    hiddenTextarea = document.createElement('textarea');
    document.body.appendChild(hiddenTextarea);
  }

  let {
    paddingSize,
    borderSize,
    boxSizing,
    contextStyle
  } = calculateNodeStyling(targetElement);

  hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`);
  hiddenTextarea.value = targetElement.value || targetElement.placeholder || '';

  let height = hiddenTextarea.scrollHeight;
  const result = {};

  if (boxSizing === 'border-box') {
    height = height + borderSize;
  } else if (boxSizing === 'content-box') {
    height = height - paddingSize;
  }

  hiddenTextarea.value = '';
  let singleRowHeight = hiddenTextarea.scrollHeight - paddingSize;

  if (minRows !== null) {
    let minHeight = singleRowHeight * minRows;
    if (boxSizing === 'border-box') {
      minHeight = minHeight + paddingSize + borderSize;
    }
    height = Math.max(minHeight, height);
    result.minHeight = `${ minHeight }px`;
  }
  if (maxRows !== null) {
    let maxHeight = singleRowHeight * maxRows;
    if (boxSizing === 'border-box') {
      maxHeight = maxHeight + paddingSize + borderSize;
    }
    height = Math.min(maxHeight, height);
  }
  result.height = `${ height }px`;
  hiddenTextarea.parentNode && hiddenTextarea.parentNode.removeChild(hiddenTextarea);
  hiddenTextarea = null;
  return result;
};

我们可以看到

if (!hiddenTextarea) {
  hiddenTextarea = document.createElement('textarea');
  document.body.appendChild(hiddenTextarea);
}

element-ui创建了一个textarea的dom,通过calculateNodeStyling方法将真正的textarea的样式复制给hiddenTextarea(overflow不同步,真正的textarea是为hidden)。接着监听textarea的输入值,同步给hiddenTextarea。同时将hiddenTextarea的scrollHeight同步给textarea的高度,最后再将dom销毁掉。

关于样式的同步,element这里用了getComputedStyle和getPropertyValue这两个API。当然,如果你自己封装的话,也可以使用css预处理器的mixin。

第二种方案与第一种方案类似,不过不会创建额外的dom。以开头的vue-awesome-textarea举例:

init() {
  this.initAutoResize()
},
initAutoResize () {
  this.autoResize && this.$nextTick(this.calcResize)
}

在页面mounted或者内容变动且开启自适应高度autoResize的时候,执行this.calcResize方法。

calcResize() {
  this.resetHeight()
  this.calcTextareaH()
},

resetHeight() {
  this.height = 'auto'
},

calcTextareaH() {
  let contentHeight = this.calcContentHeight()
  this.height = this.calcHeightChange(contentHeight) + 'px'
  if (this.needUpdateRows(contentHeight)) {
    this.updateRows(contentHeight)
  }
  this.oldContentHeight = contentHeight
},

calcContentHeight () {
  const { paddingSize } = this.calcNodeStyle(this.$el)
  return this.$el.scrollHeight - paddingSize
},

resetHeight()是来初始化textarea的高度,默认为auto。calcTextareaH()方法是用来计算内容区域的高度(textarea的scrollHeight减去padding的高度),同时将计算好的高度实时同步给textarea的高:
this.height = this.calcHeightChange(contentHeight) + 'px'

相比方案一,这个方案采用的思路相同(动态修改高度),但是减少了额外的dom创建和销毁的过程。
此外,vue-awesome-textarea还支持在自适应的过程中回调行数,可以更好的支持数据回显。实现的方法也很简单:

computed: {
  ...
  oneRowsHeight() {
    return this.calcContentHeight() / Number(this.rows) || 0
  }
  ...
}

在computed中我们计算出单行的高度,同时在执行this.calcTextareaH()方法时我们记录下内容高度:

this.oldContentHeight = contentHeight

接着我们会比对是否存在添加行操作,一旦添加则新的内容高度和老的内容高度会不同:

needUpdateRows(newContentHeight) {
  return this.oldContentHeight !== newContentHeight
},

此时我们会把最新的行高emit到组件外部:

updateRows(contentHeight) {
  this.$emit('getRows', Math.round(contentHeight / this.oneRowsHeight))
}

到此这篇关于Vue中textarea自适应高度方案的实现的文章就介绍到这了,更多相关Vue textarea自适应内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Vue中textarea自适应高度方案的实现

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Vue中textarea自适应高度方案怎么实现

本篇内容介绍了“Vue中textarea自适应高度方案怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!隐藏的问题抛开原生JS,框架的大
2023-06-22

怎么实现一个自适应高度的textarea

今天就跟大家聊聊有关怎么实现一个自适应高度的textarea,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。方法1. HTML结构:
2023-06-09

怎么在HTML5中使用 textarea实现高度自适应

今天就跟大家聊聊有关怎么在HTML5中使用 textarea实现高度自适应,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。方案一HTML5 Textarea 元素1. 自动获得焦点点击
2023-06-09

iframe实现高度自适应小程序web-view方案

这篇文章主要为大家介绍了iframe实现高度自适应小程序web-view方案详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-11

iframe窗口高度自适应的实现方法

要实现iframe窗口高度自适应,可以通过以下方法:1. 使用JavaScript动态调整iframe的高度:- 在iframe加载完成后,通过获取iframe的内容高度并设置给iframe的高度。可以使用JavaScript中的`cont
2023-08-11

CSS实现高度自适应铺满整屏的案例

这篇文章主要介绍CSS实现高度自适应铺满整屏的案例,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!在自己写demo的过程中,想使用display:flex实现垂直居中,代码如下: