textarea 根據內容自適應高度


textarea 多行文本域,大家所熟悉的,當對其設置了高度以后,如果里面的文本多了,那么就會出現滾動條.有些設計師覺得出現滾動條就是不友好的體現,那么我們就試着來消除它吧.

首先我對textarea設置height為確定的某值,然后設置overflow屬性,其值為hidden,這樣就能夠去掉滾動條了,不論textarea里面的文本是多是少。現在問題又來了,如果這樣設置的話,豈不是當文本很多的時候,很不友好嗎?答案是對的,非常不友好,至少在我看來是這樣的。

隨后,我們進一步設想,如果textarea如果能夠隨着內容文本的增加為自適應的增加自身的height,這是不是很好呢?有想法了,就去做吧!

剛開始的時候,我的想法是,生成一個與當前textarea對應的div元素,設為隱藏,並且各種外觀樣式與textarea元素一致,然后我們對textarea綁定相關事件,同步二者之間的內容文本,這樣,我們就可以取得div的高度了,然后我們設置textarea為這個高度。附上相關代碼:

View Code
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>JQuery plugin textareaHeightAuto</title>
<meta name="keywords" content="" />
<meta name="description" content="" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<style type="text/css">
*{margin: 0;padding: 0}
.textarea {overflow: hidden;margin: 50px;height: 100px;width: 400px;border: 1px solid #ccc;}
.button {padding: 5px 10px;cursor: pointer;}
</style>
</head>
<body>

<textarea id="J_Txt" class="textarea"></textarea>
<button type="button" id="J_Btn" class="button">destroy</button>

<script type="text/javascript">
;(function($){
    var methods = {
        init: function(options){
            debug('textareaHeightAuto start !');
            var main_opts = $.extend({}, $.fn.textareaHeightAuto.defaults, options);
            return this.each(function(){
                var $this = $(this);
                var opts = main_opts;
                $this.data('textareaHeightAuto', opts);
                var styles = {
                    width: $this.width(),
                    height: $this.height(),
                    padding: {
                        top: $this.css('padding-top'),
                        right: $this.css('padding-right'),
                        bottom: $this.css('padding-bottom'),
                        left: $this.css('padding-left')
                    },
                    margin: {
                        top: $this.css('margin-top'),
                        right: $this.css('margin-right'),
                        bottom: $this.css('margin-bottom'),
                        left: $this.css('margin-left')
                    },
                    border: {
                        width: $this.css('border-width'),
                        style: $this.css('border-style'),
                        color: $this.css('border-color')
                    },
                    fontSize: $this.css('font-size'),
                    fontFamily: $this.css('font-family'),
                    lineHeight: $this.css('line-height')
                };
                $this.css({overflow: 'hidden', resize: 'none'});
                var $textareaCloneDom = $('<div class="textareaCloneDom"></div>');
                $textareaCloneDom.css({
                    'display': 'none',
                    /*
                    'margin-top': styles.margin.top,
                    'margin-right': styles.margin.right,
                    'margin-bottom': styles.margin.bottom,
                    'margin-left': styles.margin.left,
                    */
                    'padding-top': styles.padding.top,
                    'padding-right': styles.padding.right,
                    'padding-bottom': styles.padding.bottom,
                    'padding-left': styles.padding.left,
                    'width': styles.width,
                    'height': 'auto',
                    'min-height': styles.height,
                    'font-size': styles.fontSize,
                    'font-family': styles.fontFamily,
                    'line-height': styles.lineHeight,
                    'word-wrap': 'break-word',
                    'word-break': 'normal',
                    'border': styles.border.width +' '+ styles.border.style +' '+ styles.border.color
                });
                if($.browser.msie && $.browser.version == 6.0){
                    $textareaCloneDom.css({'height': styles.height});
                }
                $this.after($textareaCloneDom);
                var _val;

                $this.on(opts.eventName, function(e){
                    var $target = $(this);
                    _val = $target.val();
                    _val = _val.replace(/\n/g, '<br />');
                    $textareaCloneDom.html(_val+'<br /><br />');
                    $target.height($textareaCloneDom.height());
                });
            });
        },
        destroy: function(){
            return this.each(function(){
                var $this = $(this),
                    data = $this.data('textareaHeightAuto');
                $this.siblings('div.textareaCloneDom').remove();
                $this.off(data.eventName);
                $this.css({height: data.minHeight});
                $this.removeData('textareaHeightAuto');
            });
        }
    };

    $.fn.textareaHeightAuto = function(method){
        if(methods[method]){
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        }else if(typeof method === 'object' || !method){
            return methods.init.apply(this, arguments);
        }else{
            $.error('Method '+ method + ' does not exist on jQuery.textareaHeightAuto');
        }
    };

    // 內部方法
    function debug(obj){
        if(window.console && window.console.log){
            window.console.log(obj);
        }
    }

    // 可以適當暴露一些可擴展的方法
    //$.fn.textareaHeightAuto.fun = function(str){};

    // 把默認參數放在外面,使得用戶可以在插件之外就修改插件默認設置
    // $.fn.textareaHeightAuto.defaults.bottomHeight = 0;// 修改插件的默認設置
    // $('#textarea').textareaHeightAuto({bottomHeight: 0});// 修改應用插件的當前元素的默認設置
    $.fn.textareaHeightAuto.defaults = {
        maxHeight: 600,
        minHeight: 100,
        bottomHeight: 18,
        eventName: 'paste cut keydown keyup focus blur'
    };
})(jQuery);

$(document).ready(function(){
    $('#J_Txt').textareaHeightAuto();

    $('#J_Btn').on('click', function(){
        $('#J_Txt').textareaHeightAuto('destroy');
        $(this).attr('disabled', true);
    });
});
</script>
</body>
</html>

上面的做法雖然實現了相關的效果,但是感覺有些復雜了,我們是否還能對此改進呢?答案是肯定的!

后面我翻閱了相關資料,也搜索了類似的相關js,找到這么一個 scrollHeight 屬性,手冊上是這么解釋該屬性的:

scrollHeight是返回整個網頁或某個元素內容的高度,然后再加上滾動條可以滾動的高度值.就是scrollHeight返回的正確結果

利用這個屬性,我們可以大大的簡化代碼。附上代碼:

View Code
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>JQuery plugin textareaHeightAuto</title>
<meta name="keywords" content="" />
<meta name="description" content="" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<style type="text/css">
*{margin: 0;padding: 0}
.textarea {overflow: hidden;margin: 50px;height: 100px;width: 400px;border: 1px solid #ccc;}
.button {padding: 5px 10px;cursor: pointer;}
</style>
</head>
<body>

<textarea id="J_Txt" class="textarea"></textarea>
<button type="button" id="J_Btn" class="button">destroy</button>

<script type="text/javascript">
;(function($){
    var methods = {
        init: function(options){
            debug('textareaHeightAuto start !');
            var main_opts = $.extend({}, $.fn.textareaHeightAuto.defaults, options);
            return this.each(function(){
                var $this = $(this);
                debug($this);
                //var opts = $.metadata ? $.extend({}, main_opts, $this.metadata()) : main_opts;
                var opts = main_opts;
                $this.data('textareaHeightAuto', opts);
                $this.on(opts.eventName, function(){
                    var $target = $(this);
                    // 這里是比較重要的地方 必須先對textarea的高度進行設置,然后才能取 scrollHeight 的值
                    // 這是因為 scrollHeight 返回的是 元素內容的高度 + 滾動條可以滾動的高度值,明白了這點,下面就可以理解了
                    $target.height(opts.minHeight - opts.bottomHeight);// 增加這個間隔值是為了修復設置textarea高度時(特別是在最后一行回車時)跳動太大的情況
                    var scrollHeight = $target[0].scrollHeight + opts.bottomHeight;// 一加一減,相互抵消
                    if((scrollHeight) > opts.minHeight){
                        if(scrollHeight < opts.maxHeight){
                            $target.css({'overflow-y': 'hidden'}).height(scrollHeight);
                        }else{
                            $target.css({'overflow-y': 'auto'}).height(opts.maxHeight);
                        }
                    }else{
                        $target.css({'overflow-y': 'hidden'}).height(opts.minHeight);
                    }
                });
            });
        },
        destroy: function(){
            return this.each(function(){
                var $this = $(this),
                    data = $this.data('textareaHeightAuto');
                $this.off(data.eventName);
                $this.css({height: data.minHeight});// 不知道重置(還原?)textarea高度是否有必要
                $this.removeData('textareaHeightAuto');
            });
        }
    };

    $.fn.textareaHeightAuto = function(method){
        if(methods[method]){
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        }else if(typeof method === 'object' || !method){
            return methods.init.apply(this, arguments);
        }else{
            $.error('Method '+ method + ' does not exist on jQuery.textareaHeightAuto');
        }
    };

    // 內部方法
    function debug(obj){
        if(window.console && window.console.log){
            window.console.log(obj);
        }
    }

    // 可以適當暴露一些可擴展的方法
    //$.fn.textareaHeightAuto.fun = function(str){};

    // 把默認參數放在外面,使得用戶可以在插件之外就修改插件默認設置
    // $.fn.textareaHeightAuto.defaults.bottomHeight = 0;// 修改插件的默認設置
    // $('#textarea').textareaHeightAuto({bottomHeight: 0});// 修改應用插件的當前元素的默認設置
    $.fn.textareaHeightAuto.defaults = {
        maxHeight: 600,
        minHeight: 100,
        bottomHeight: 18,
        eventName: 'paste cut keydown keyup focus blur'
    };
})(jQuery);

$(document).ready(function(){
    $('#J_Txt').textareaHeightAuto();

    $('#J_Btn').on('click', function(){
        $('#J_Txt').textareaHeightAuto('destroy');
        $(this).attr('disabled', true);
    });
});
</script>
</body>
</html>

 

最后,我在搜索資料的過程中,發現了另外一種類似效果的實現方式,通過設置block元素的contenteditable屬性為true來實現,原文請看這里:div模擬textarea文本域輕松實現高度自適應,不失為一種可取的方法,感謝原作者!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM