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自适应内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Vue实现动态显示textarea剩余字数

    Vue实现动态显示textarea剩余文字数量,具体内容如下 这里我们假设允许用户输入的最多数量为200个 html代码如下: <textarea maxlength="200" @input="descInput" v-model="desc" /> <span>{{remnant}}/200</span> javascript代码如下: data(){ return{ remnant: 200 } } me

  • Vue实现textarea固定输入行数与添加下划线样式的思路详解

    先上效果图### textarea下划线 设置一张1*35 //行高 的图片 , 设置背景图即可. background: url('./img/linebg.png') repeat; border: none;outline: none;overflow: hidden; line-height: 35px;//注意行高要和背景图高度一致resize: none; 固定输入行数 需求:用户固定不论多少字节,只能输入2行. 因为是限制行数,所以不能用maxlength设置. 实现思路 首先想到

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

    目录 隐藏的问题 解决自适应高度的方案 先给方案,Vue栈有需求的同学可以直接下载vue-awesome-textarea 隐藏的问题 抛开原生JS,框架的大部分UI库都支持自适应textarea高度功能,但普遍都忽略了一个功能,就是自适应高度的回显. 使用这些库的时候,我们很容易的在textarea中键入内容,超出范围时会自动延展一行,保证内容高度的自适应.当我们提交内容,在其它页面使用同样的UI来渲染时,麻烦的就来了,有些UI库是不支持自适应回显的,这就需要我们通过行高.行数甚至高度之间的计

  • Vue中的性能优化方案

    目录 减少响应式使用 1. 使用 computed 缓存计算结果 2. 本地化响应式变量 3. 函数式组件(Vue2) 减少 DOM 渲染压力 1. DOM 频繁切换展示的情况使用 v-show 2. keep-alive 缓存组件状态 3. 路由懒加载 4. 图片懒加载 5. 组件销毁时要清除定时器.EventListener 6. 列表使用唯一 key 减少打包体积 1. 开启 gzip 压缩 2. 按需引入第三方组件 最近使用 Vue 开发的过程中使用到一些对于性能有所提升的编码方式,所以

  • jquery ajax应用中iframe自适应高度问题解决方法

    iframe自适应高度本身是很简单的方法,就是在页面加载完成后,重新计算一下高度即可. 代码如下: 复制代码 代码如下: //公共方法:设置iframe的高度以保证全部显示数据//function SetPageHeight() {//    var iframe = getUrlParam('ifname');//    var myiframe = window.parent.document.getElementById(iframe);//     iframeLoaded(myifra

  • jquery实现文本框textarea自适应高度

    浏览器中默认的文本框是不能根据内容的增多变高,只能固定高度有滚动条,体验不是很好,找了很多方法兼容都不行,总算找到个兼容良好的方法: <body> <textarea id="textarea3" style="overflow-y:hidden; height:20px;resize: none"> </textarea> <script type="text/javascript" src="

  • 基于jquery的让textarea自适应高度的插件

    Introduction 1. This textarea is like the google calendar's description when you create one new or update one existence calendar; 2. Its height will be changed accroding to user's input; 3. Its scrollbar is removed, which makes it much user friendly.

  • Vue中jsx不完全应用指南小结

    前言:文章不介绍任务背景知识,没有原理说明,偏向于实践的总结和经验分享. 文章所有的代码是基于Vue CLI 3.x版本,不会涉及到一步步通过Webpack来配置JSX所需要的知识点. 在使用Vue开发项目时绝大多数情况下都是使用模板来写HTML,但是有些时候页面复杂又存在各种条件判断来显示/隐藏和拼凑页面内容,或者页面中很多部分存在部分DOM结构一样的时候就略显捉襟见肘,会写大量重复的代码,会出现单个.vue文件过长的情况,这个时候我们就需要更多的代码控制,这时候可以使用渲染函数. 渲染函数想

  • Vue常见组件间通信方案及典型应用场景详解

    目录 什么是组件通信 1.父子组件通信场景 2.兄弟组件通信场景 3.根组件和后代组件通信场景 4.插槽通信场景 5 无直接关系的组件通信场景 6 大型项目中的复杂组件通信场景 - Vuex状态管理 7 其他的一些组件通信方案 总结 什么是组件通信 所谓组件通信,就是组件之间的数据交互,也就是把一个组件A里面的数据传递到另一个组件B,并能够让组件B根据这个数据更新界面. 在 Vue中,可用的通信方案有很多,下面给大家描述几个常用的组件通信方案及其典型的应用场景. 1.父子组件通信场景 父子组件通

  • 详解vue中移动端自适应方案

    方案1: 直接引入js  (自己 写的动态改变fontsize的js) function htRem() { var ww = document.documentElement.clientWidth; if (ww > 750) { ww = 750; } document.documentElement.style.fontSize = ww / 7.5 + "px"; } htRem(); window.onresize = function() { htRem(); };

  • div实现自适应高度的textarea实现angular双向绑定

    相信不少同学模拟过腾讯的QQ做一个聊天应用,至少我是其中一个. 过程中我遇到的一个问题就是QQ输入框,自适应高度,最高高度为3row. 如果你也像我一样打算使用textarea,那么很抱歉,你一开始就错了. textarea不是不可以的,然后我是这样错的.(就是监听scroll 如果出现了,就增加1rows 的高度)然而这样真的很挫 textarea.bind('change','keydown'){ if(scrollTop > 0 ) { textarea.rows += 1 } } 正确的

  • Vue 自适应高度表格的实现方法

    前言 示例版本为 Element-ui 2.13.1 + Vue 2.6.11 本人是做后台开发的,由于公司业务要求需要将前后台模块进行分离,两年前选择使用vue-element-admin项目进行前台的开发,该框架集成了很多功能,特别适合对 Vue 很陌生的新手,公司项目组成员接受程度普遍较高. 在使用过程中 表格 是必不可少的一个控件,用于展示数据,单页数据量过多就会导致浏览器自动生成右侧滚动条. 如果页面有头部信息或查询按钮,移动滚动条后会遮挡住这些操作和信息内容. Element-UI

随机推荐