Oliwans'blog

不会写影评的摄影师不是好的FED

创建可以高度自适应的input或textarea


  input与textarea是网页中常见的文本输入框,但是他们有一个共同的缺点,就是无法高度自适应,这个在传统的html与css中尝试了很多办法都无法解决,只有从js入手,但是在js中写jquery来动态控制,也有一定的问题,比如动态改变了input或textarea的高度,但是当文字数量减少时,宽度却无法回收,这是一个比较严重的问题,并不能达到我们想要的效果,所以只有另寻他法,好在html5提供了一个div模拟高度自适应的textarea方法,解决了这个问题:

直接晒代码:

1
<div contenteditable="true" class="texttitle"></div>

css中的代码:

1
2
3
4
5
6
7
8
.texttitle{
background: #eeeeee;
width: 100%;
min-height: 80px;
resize:none;
padding: 10px 5px;
-webkit-user-select:text;
}

怎么样?很容易吧,这个就可以轻易的解决input和textarea不能高度自适应的问题核心代码是contenteditable="true",html5新增的一种属性,为了模拟文本框设计的。
-webkit-user-select:text; //兼容iphone及个别浏览器不能输入的问题
resize:none; //这个是css3禁止用户调整文本框尺寸,即去掉右下角三角标记

嗯…总感觉哪里不对,感觉少了点什么,没错,预填充内容placeholder没有加,可是当我把代码改成<div contenteditable="true" class="texttitle" placeholder="请输入题目名称"></div>时,我发现文本框中还是没有效果,这到底是怎么回事?

原来,div模拟文本框是不支持placeholder的,没关系,我们可以用css来模拟placeholder,先设一个属性data-placeholder,然后css进行控制,代码如下:

1
<div contenteditable="true" class="texttitle rich" data-placeholder="请输入题目名称"></div>

css中的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.texttitle{
background: #eeeeee;
width: 100%;
min-height: 80px;
resize:none;
padding: 10px 5px;
-webkit-user-select:text;
}

.rich{
color:#000;
}

.rich:empty:before{
content: attr(data-placeholder)
;

color:#bbb;
}
.rich:focus:before{
content:none
;

}

至此,div模拟文本框就差不多了,可以输入,可以高度自适应,兼容各个浏览器,并且有预填充placeholder效果,如果用jquery的话基本可以满足日常的使用,不过对于流行的js框架来讲还是有一定的缺陷,例如angular.js不能双向绑定,这里以angular为例,说下解决办法:因为这种模拟文本框输入不支持angular的重要属性之一,文本框的ng-model双向绑定,想要双向绑定有个方法,就是添加一个directive方法,然后依赖注入,在config里注入一下,这里晒一下directive代码(在网上可以找到):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
'use strict';
app.directive('contenteditable', function() {
return {
restrict: 'A', // only activate on element attribute
require: '?ngModel', // get a hold of NgModelController
link: function(scope, element, attrs, ngModel) {
if (!ngModel) {
return;
} // do nothing if no ng-model
// Specify how UI should be updated
ngModel.$render = function() {
element.html(ngModel.$viewValue || '');
};
// Listen for change events to enable binding
element.on('blur keyup change', function() {
// console.log(readViewText);
scope.$apply(readViewText);
});
// No need to initialize, AngularJS will initialize the text based on ng-model attribute
// Write data to the model
function readViewText() {
var html = element.html();
// When we clear the content editable the browser leaves a <br> behind
// If strip-br attribute is provided then we strip this out
if (attrs.stripBr && html === '<br>') {
html = '';
}
ngModel.$setViewValue(html);
}
}
};
});

然后html代码改为

1
<div contenteditable="true" class="texttitle rich" data-placeholder="请输入题目名称" ng-model="title"></div>

与controller中的$scope.title双向绑定,至此完整的可复用的模拟文本框完成,有了这个,input和textarea还有什么用呢?(玩笑)

Oliwans

个人博客技术、观点、见解分享者;我会在这里分享工作中的问题;兴趣方面的观点;生活中的感悟。

Proudly published with Hexo