項目分享六:圖片的延遲加載

1、關於延遲加載

圖片的延遲加載,是 APP 裏經常使用的一種技術,圖片首先會生成一張預覽圖,等到原圖下載完成後,再替換掉。 以下面二張圖所示。實現起來,雖然不是很難,但要把它封裝好,也不大容易。在這裏主要講解一下 ChiTuStore 項目中是如何封裝。html

 

2、圖片的綁定

咱們打開 App/Module/Home/Index.html 文件,能夠找到下面一段代碼,這段代碼是用來對首頁產品列表進行綁定的,我要關注的是 <img data-bind="attr:{src:ImagePath}" class="img-responsive-70"> 。node

這段話用來對圖片進行綁定的。git

    <div data-bind="foreach:homeProducts,visible:ko.unwrap(homeProducts).length > 0" class="row products" style="margin:0px;">
        <div class="col-xs-6 text-center item">
            <a data-bind="attr:{href:'#Home_Product_'+ProductId}" href="product.html">
                <img data-bind="attr:{src:ImagePath}" class="img-responsive-70">
                <div class="bottom">
                    <div class="interception" data-bind="html:Name"></div>
                    <div>
                        <div class="price pull-left" data-bind="money:Price"></div>
                        <promotion-label params="value:PromotionLabel" class="pull-right"></promotion-label>
                    </div>
                </div>
            </a>
        </div>
    </div>

 

3、重寫 ko attr 綁定

由於圖片的綁定,是使用 ko 的 attr 綁定來呈現的,咱們須要對其重寫。來實現咱們預覽圖的生成,原圖的下載及替換。打開 App/Core/ko.ext.ts 文件,這個文件是用來對 ko 進行擴展的。、github

咱們能夠在文件中找到下面的代碼,這代碼代碼就是用來重寫 ko attr 綁定的。canvas

var _attr = ko.bindingHandlers.attr;
ko.bindingHandlers.attr = (function () {
    return {
        'update': function (element, valueAccessor, allBindings) {
            if (element.tagName == 'IMG') {var value = ko.utils.unwrapObservable(valueAccessor()) || {};
                ko.utils['objectForEach'](value, function (attrName, attrValue) {
                    var src = ko.unwrap(attrValue);
                    if (attrName != 'src' || !src)
                        return true;

                    //==========================================================
                    // 說明:替換圖片路徑
                    var match = src.match(/_\d+_\d+/);
                    if (match && match.length > 0) {
                        var arr = match[0].split('_');
                        var img_width = new Number(arr[1]).valueOf();
                        var img_height = new Number(arr[2]).valueOf();

                        $(element).attr('width', img_width + 'px');
                        $(element).attr('height', img_height + 'px');

                        var src_replace
                        src_replace = getPreviewImage(img_width, img_height);

                        valueAccessor = $.proxy(function () {
                            var obj = ko.utils.unwrapObservable(this._source());
                            var src = ko.unwrap(obj.src);
                            obj.src = this._src;

                            var img_node = this._element;
                            var image = new Image();
                            image.onload = function () {
                                img_node.src = this.src;
                            }
                            image.src = getImageUrl(src);

                            return obj;

                        }, { _source: valueAccessor, _src: src_replace, _element: element });
                    }
                    else {
                        value.src = src;
                        valueAccessor = $.proxy(function () {
                            return this._value;
                        }, { _value: value });
                    }
                });
            }
            return _attr.update(element, valueAccessor, allBindings);
        }
    }
})();

咱們先來看第一句:瀏覽器

var _attr = ko.bindingHandlers.attr;

這句話是把 ko 原來的 attr 綁定賦值到 _attr 上,由於咱們還須要用到它原來的 attr 綁定。服務器

咱們繼續看,這段代碼是說,咱們只須要處理 IMG 元素就行了,其它,仍是按原來處理吧,看,_attr (就是原來的處理函數)用到了吧。函數

 if (element.tagName == 'IMG') {
      // 處理圖片,代碼已省略掉
}
return _attr.update(element, valueAccessor, allBindings);

這段話可能有點難懂。要生預覽圖,須要圖片文件的名稱按約定規命名,例如:17838fdb3e704178938cfb1a73556798_360_360.jpeg,其中的 360_360 分別是圖片的寬和高,也就是說,咱們必須知道圖片的寬高才能生成預覽圖,若是不清楚,是沒法生成的。下面代碼中的正規表達,就是用來判斷這個的,文件名符合規定的,才生成預覽圖,不然按常規的來處理。字體

var match = src.match(/_\d+_\d+/);
if (match && match.length > 0) {
//.....
}else{
  value.src = src;
   valueAccessor = $.proxy(function () {
     return this._value;
   }, { _value: value });
}

 

3、預覽圖的生成

咱們在代碼中能夠找到 getPreviewImage 函數,下面咱們看看這個函數。這裏又用到了 canvas。也就是說,若是瀏覽器不支持 canvas ,是沒法生成預覽圖的。代碼並不難理解,就不一一細說了。 this

function getPreviewImage(img_width, img_height) {

    var scale = (img_height / img_width).toFixed(2);
    var img_name = 'img_log' + scale;
    var img_src = localStorage.getItem(img_name);
    if (img_src)
        return img_src;

    var MAX_WIDTH = 320;
    var width = MAX_WIDTH;
    var height = width * new Number(scale).valueOf();

    var canvas = document.createElement('canvas');
    canvas.width = width; //img_width;
    canvas.height = height; //img_height;

    var ctx = canvas.getContext('2d');
    ctx.fillStyle = 'whitesmoke';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // 設置字體
    ctx.font = "Bold 40px Arial";
    // 設置對齊方式
    ctx.textAlign = "left";
    // 設置填充顏色
    ctx.fillStyle = "#999";
    // 設置字體內容,以及在畫布上的位置
    ctx.fillText(site.config.storeName, canvas.width / 2 - 75, canvas.height / 2);

    img_src = canvas.toDataURL('image/png');
    localStorage.setItem(img_name, img_src);
    return img_src;
}

 

4、小結

雖然實現了預覽圖的生成,可是,還不足夠好,由於還有一個很重要的功能是沒有實現,就是隻顯示可見區域的圖片。另外:有朋友可能會問,咱服務器上的圖片名稱不符合這裏的規範,咋辦?讓大家服務端的同事改唄。^_^

固然,若是你有更好的辦法,也能夠告訴我。

 

項目分享五:H5圖片壓縮與上傳 

項目分享四:購物車頁面的更新 

項目分享三:頁面之間的傳值

項目分享二:APP 小紅點中數字的處理

項目分享一:在項目中使用 IScroll 所碰到的那些坑

相關文章
相關標籤/搜索