需求简介

一个搜索页面,上面输入框,下面列表展示搜索到的结果。

重点是:产品要求搜索框默认显示一行,当输入的文字超过一行时,输入框的高度会随着改变,直到输入完毕。

解决思路设想

本想利用textarea实现,但textarea不支持自适应高度,而是定好高度或者是行数之后,超出部分就会显示滚动条。只能另想。

根据需求,首先想到了张鑫旭伪类匹配列表数目实现微信群头像CSS布局的技巧一文提到的文字多字号自动变小的技巧,但仔细一琢磨,不行。这个是根据内容元素的个数,进行处理,而这儿是输入框,没有内容元素。

后面想到可以利用html属性contenteditable="true",加在div上让其可编辑来模拟自适应高度。可是需要在vue中双向绑定实现,这个不是很好处理。

后面想到利用textarea的row属性,根据输入内容的长度控制row的值,为1-n行,但这个似乎不是很智能,因为多少个字体一行不一定,英文、中文、数字的宽度不一致,而且row属性在每个浏览器中的表现不一致。

最后利用textarea,监听change事件,让其高度=其滚动条高度,来达到高度自适应。

没想到最后还是利用了textarea。

实现

参考:textarea如何实现高度自适应?

util.js

/**
* 文本框根据输入内容自适应高度
* @param {HTMLElement} 输入框元素
* @param {Number} 设置光标与输入框保持的距离(默认0)
* @param {Number} 设置最大高度(可选)
* @callback {Function} 设置回调函数(可选)
*/
export const autoTextarea = function (elem, extra, maxHeight, callback) {
extra = extra || 0;
var isFirefox = !!document.getBoxObjectFor || 'mozInnerScreenX' in window,
isOpera = !!window.opera && !!window.opera.toString().indexOf('Opera'),
addEvent = function (type, callback) {
elem.addEventListener ?
elem.addEventListener(type, callback, false) :
elem.attachEvent('on' + type, callback);
},
getStyle = elem.currentStyle ? function (name) {
var val = elem.currentStyle[name]; if (name === 'height' && val.search(/px/i) !== 1) {
var rect = elem.getBoundingClientRect();
return rect.bottom - rect.top -
parseFloat(getStyle('paddingTop')) -
parseFloat(getStyle('paddingBottom')) + 'px';
}; return val;
} : function (name) {
return getComputedStyle(elem, null)[name];
},
minHeight = parseFloat(getStyle('height')); elem.style.resize = 'none'; var change = function () {
var scrollTop, height,
padding = 0,
style = elem.style; if (elem._length === elem.value.length) return;
elem._length = elem.value.length; if (!isFirefox && !isOpera) {
padding = parseInt(getStyle('paddingTop')) + parseInt(getStyle('paddingBottom'));
};
scrollTop = document.body.scrollTop || document.documentElement.scrollTop; elem.style.height = minHeight + 'px';
if (elem.scrollHeight > minHeight) {
if (maxHeight && elem.scrollHeight > maxHeight) {
height = maxHeight - padding;
style.overflowY = 'auto';
} else {
height = elem.scrollHeight - padding;
style.overflowY = 'hidden';
};
style.height = height + extra + 'px';
scrollTop += parseInt(style.height) - elem.currHeight;
document.body.scrollTop = scrollTop;
document.documentElement.scrollTop = scrollTop;
elem.currHeight = parseInt(style.height); callback(parseInt(style.height));
};
}; addEvent('propertychange', change);
addEvent('input', change);
addEvent('focus', change);
change();
}; export const debounce = function (func, delay) {
let timer; return function (...args) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
func.apply(this, args);
}, delay || 500);
}
}

说明:由于下面是列表,需要计算高度,为了避免重新再去获取高度,所以加了个回调方法,把高度回调出去。

vue-search.vue

<template>
<div class="search-list">
<div>
<textarea ref="textarea" v-model="keywords" :maxlength="keywordsMax" @change="searchChange"></textarea>
<span class="clear" @click="clearKeywords">x</span>
</div>
<div class="list" ref="list">
<ul>
<li v-for="item in list" :key="item.id">
<span class="icon"></span>
<dl>
<dt>{{item.title}}</dt>
<dd>{{item.desc}}</dd>
</dl>
</li>
</ul>
</div>
</div>
</template> <script>
import { debounce, autoTextarea } from '@/util.js'; let rootFontSize = parseFloat(document.documentElement.style.fontSize); export default {
data () {
return {
keywordsMax: 128,
keywords: '',
list: []
}
},
mounted () {
this.$nextTick(() => {
let textarea = this.$refs.textarea;
textarea.focus();
let prevHeight = 65;
textarea && autoTextarea(textarea, 5, 0, (height) => {
height += 20;
if (height !== prevHeight) {
prevHeight = height;
let rem = height / rootFontSize;
this.$refs.list.style.height = `calc(100% - ${rem}rem)`;
}
});
})
},
methods: {
clearKeywords () {
this.keywords = '';
this.list = [];
let textarea = this.$refs.textarea;
let height = 40;
let rem = height / rootFontSize;
textarea.style.height = `${rem}rem`;
rem = (height + 20) / rootFontSize;
this.$refs.list.style.height = `calc(100% - ${rem}rem)`;
textarea.focus();
},
searchChange: debounce(function () {
let trim = this.keywords.trim();
if (!trim) {
this.list = [];
return;
}
const params = {
keywords: this.keywords
}
// 调api ...
})
}
}
</script>

补充div模拟textarea自适应

<style>
.textarea{
width: 400px;
min-height: 20px;
max-height: 300px;
_height: 120px;
margin-left: auto;
margin-right: auto;
padding: 3px;
outline: 0;
border: 1px solid #a0b3d6;
font-size: 12px;
line-height: 24px;
padding: 2px;
word-wrap: break-word;
overflow-x: hidden;
overflow-y: auto; border-color: rgba(82, 168, 236, 0.8);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
}
</style> <div class="textarea" contenteditable="true"></div>

vue-textarea 自适应高度的更多相关文章

  1. textarea自适应高度,div模仿textarea可编辑实现自适应高度,placeholder使用图标

    1.textarea自适应高度,placeholder使用图标 自适应高度,有很多种办法: 1)jq: $("textarea").on("input",fun ...

  2. div模拟textarea自适应高度

    之前在公司做项目的时候,有这么一个需求,要我写一个评论框,可以随着评论的行数增加而自动扩大,最开始我想用textarea实现,但是后来尝试后发现textarea并不适合,textarea的高度不会随着 ...

  3. textarea自适应高度

    最近做项目遇见了这个自适应高度的问题,也在网上找了些资料,大多选择用DIV模拟textarea,但是这样就有安全性的问题,因为你是可以直接将HTML代码输入进去的. 接下来介绍的这种办法是采用两个te ...

  4. 简单实现一个textarea自适应高度

    textarea自适应的实现方法很多,原理其实比较简单:监听textarea的input或者键盘事件,获取元素的scrollHeight,重置textarea元素的高度. 预览地址:textarea ...

  5. js实现textarea自适应高度

    html结构: <div class="container" id="container"> <div class="text-wr ...

  6. jquery文本框textarea自适应高度

    浏览器中默认的文本框是不能根据内容的增多变高,只能固定高度有滚动条,体验不是很好,找了很多方法兼容都不行,总算找到个兼容良好的方法: <body> <textarea id=&quo ...

  7. Textarea自适应高度 JS实现,兼容IE6\7\8\9\10\11

    <!DOCTYPE html> <html> <head> <title>autoresizing textarea</title> < ...

  8. textarea 自适应高度

    试了好多方法,包括百度了好多.一旦接口获取的内容,就不好用了.有时候就是脑袋转不过来,想了好久的方法居然那么简单,然后,脑洞大开,忽然想到还可以这样弄, 很简单,两句话 var textareaHei ...

  9. 将textarea实现自适应高度及IE下滚动条不出现的bug

    1.<el-table-column label="备注" width="180"> <template scope="scope& ...

  10. div实现自适应高度的textarea,实现angular双向绑定

    相信不少同学模拟过腾讯的QQ做一个聊天应用,至少我是其中一个. 过程中我遇到的一个问题就是QQ输入框,自适应高度,最高高度为3row. 如果你也像我一样打算使用textarea,那么很抱歉,你一开始就 ...

随机推荐

  1. oracle 启动三步骤

    oracle 启动三步骤 oracle启动会经过三个过程,分别是nomount.mount.open 一.nomount 阶段 nomount 阶段,可以看到实例已经启动.oracle进程会根据参数文 ...

  2. 获取Shell脚本当前的目录

    https://qiushao.net/article/1489983836453?p=1&m=0 SCRIPT_DIR=$(cd $(dirname ${BASH_SOURCE[0]}); ...

  3. Linq中类型转换

    var BusDebts = db1.BusDebts.Where(s => s.BusOpt >= dts && s.BusOpt < dte && ...

  4. PHP实现多维数组按指定值排序

    主要用到的PHP函数 array_multisort() .先实现指定多维数组一个字段排序 根据二维数组的id值来排序,转换后的数组格式如下: function arraySortByOneField ...

  5. Egg.js

    一.Egg简介绍 Express和Koa缺少约定,缺少规范,Eggjs对MVA进行约定规范,为企业框架而生. 特性: 基于Egg定制上层框架. 高度可扩展插件机制. 内置多进程管理.对比Nodejs. ...

  6. 在SOUI中使用窗口自適應大小

    SOUI 2.5.0.3開始支持窗口大小自適應. 2.5.0.3以前,宿主窗口要適應顯示內容大小比較麻煩,因爲一般都是佈局內容適應宿主. SOUI 2.5.+開始支持線性佈局,線性佈局是借鑑的Andr ...

  7. 译文 - Recommender Systems: Issues, Challenges, and Research Opportunities

    REF: 原文 Recommender Systems: Issues, Challenges, and Research Opportunities Shah Khusro, Zafar Ali a ...

  8. scss/less语法以及在vue项目中的使用(转载)

    1.scss与less都是css的预处理器,首先我们的明白为什么要用scss与less,因为css只是一种标记语言,其中并没有函数变量之类的,所以当写复杂的样式时必然存在局限性,不灵活,而scss与l ...

  9. Axure RP 8 软件介绍

    介绍 此软件可以用于制作快速原型,也可以绘制中保真原型草图. 应用人群:产品经理.交互设计师.UI设计师.网页设计师. 原型分类:低保真(手绘草图).中保真(使用相关软件绘制出来的).高保真(包含效果 ...

  10. [enum]enum的用法

    ENUM概况 enum枚举类型是C/C++中的一种数据类型,与struct和class一样是用户自定义的类型,其特点在于enum类型的变量取值是有限的,是可以一一列举出来的. ENUM定义 C++ e ...