日期:2014-05-16  浏览次数:20403 次

ExtJs源码分析与学习—工具类Ext.util.TextMetrics

????? Ext提供了一个很有用的工具类Ext.util.TextMetrics,利用该类可以很方便的为一段文字提供一个精确象素级的测量,以便可以得到某段文字的高度和宽度。该类的实现采用了单例模式,即当调用该类时,该类内部属性shared已实例,下次调用时不需再实例化。先看函数的定义

?

Ext.util.TextMetrics = function(){
    var shared;
    return {
        measure : function(el, text, fixedWidth){
            if(!shared){
                shared = Ext.util.TextMetrics.Instance(el, fixedWidth);
            }
            shared.bind(el);
            shared.setFixedWidth(fixedWidth || 'auto');
            return shared.getSize(text);
        },

        createInstance : function(el, fixedWidth){
            return Ext.util.TextMetrics.Instance(el, fixedWidth);
        }
    };
}();

?

????? 该函数是自执行函数,执行完后该类提供了两个方法measure和createInstance,分别用来测量元素el的大小和创建实例。
????? 方法measure中三个参数为el测试的DOM对象,text要测量的文字,fixedWidth设置该值可以根据该值压缩文字的多行显示,从而根据行数的不同返回文本的高度,不设置时会默认根据文本显示的行数返回内容的高度。该方法首先实例化要测量的对象,然后绑定el,绑定的过程会设置其与字体相关的css样式,最后返回一段文字的大小。
上面方法中调用的函数实际上在Ext.util.TextMetrics.Instance中定义,函数主体如下

?

Ext.util.TextMetrics.Instance = function(bindTo, fixedWidth){
    ...

    var instance = {
      ...
    };

    instance.bind(bindTo);

    return instance;
};

?

????? 该函数实际上返回闭包变量instance,Ext.util.TextMetrics.Instance中封装了要实现的函数,首先看Instance中的变量

?

var ml = new Ext.Element(document.createElement('div'));
    document.body.appendChild(ml.dom);
    ml.position('absolute');
    ml.setLeftTop(-1000, -1000);
    ml.hide();

    if(fixedWidth){
        ml.setWidth(fixedWidth);
}

??? 该类定义了辅助div,隐藏显示,用来存放要测试的文字,下面看闭包变量instance中的函数

?

        /**
         * 返回一个指定文字的尺寸。该文字内置元素的样式和宽度属性
         * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
         * Returns the size of the specified text based on the internal element's style and width properties
         * @param {String} text 要测量的文字 The text to measure 
         * @return {Object} An object containing the text's size {width: (width), height: (height)}
         */
        getSize : function(text){
            ml.update(text);
            var s = ml.getSize();
            ml.update('');
            return s;
        },

?注意返回大小后把ml内容清空

?

       /**
         * 绑定某个样式的TextMetrics实例,使得被渲染之文字重新获得CSS样式。
         * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
         * Binds this TextMetrics instance to an element from which to copy existing CSS styles
         * that can affect the size of the rendered text
         * @param {String/HTMLElement} el The element, dom node or id
         */
        bind : function(el){
            ml.setStyle(
                Ext.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing')
            );
        },

?绑定时只设置与字体相关的属性

?

        /**
         * 对内置的测量元素设置一个固定的宽度。
         * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
         * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
         * to set a fixed width in order to accurately measure the text height.
         * @param {Number} width The width to set on the element
         */
        setFixedWidth : function(width){
            ml.setWidth(width);
    },

        /**
         * 返回指定文字的宽度
         * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
         * Returns the measured width of the specified text