顯示具有 javascript 標籤的文章。 顯示所有文章
顯示具有 javascript 標籤的文章。 顯示所有文章

2013/08/18

AngularJS雜記 (基於1.2的版本)

  • $timeout這個服務基本上是一個window.setTimetout的wrapper,它有一個很大的用處是其function執行時間會在Angular DOM rendering之後 (譬如在data變動之後,view跟著重新render...)
  • 避免angular在render時DOM的閃現問題,可以使用ngCloak先將DOM隱藏,不過此directive要配合一段css才有作用,在1.2版是
    [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
      display: none !important;
    }
  • 關於Directive (這邊Directive Definition Object簡稱DDO):
    1. DDO裡的controller,有可能建立不只一個instance (同樣的directive出現多個的情況),所以這種controller比較適合用來與child /sibling directive溝通;而要跨同種directive間的溝通用injected service比較好 (angular內的service全都是singleton,不論是透過Module.service/ Module.factory或$provide.provider註冊的)。
  • 有繼承關係的Scope要注意存取parent Scope變數的問題,尤其是一些directive會建立Child Scope而使用者沒查覺的時候;請參考這篇文章

跨瀏覽器相容性問題雜記

  • 目前webkit瀏覽器(Safari/ Chrome v.28)在連結被點擊時不會把CSS中的:focus樣式給套上,目前的解法是替連結加上tabindex的屬性。
     

2013/08/10

用jQuery寫出scrolling動畫效果

網路上的範例大多以body為容器,稍微修改了一下以適應在其他DOM內的scrolling效果:
/**
 * @param target a jQuery selector string, target DOM; or scrollTop value
 * @param container a jQuery selector string, represents DOM which contains target, default is 'html, body'
 */
function smoothScrollTo(target, container) {
    container = container ? container : 'html, body';

    $(container).animate({
        scrollTop: $.isNumeric(target) ? 
            target : 
            $(target).offset().top 
                + $(container).scrollTop() 
                - $(container).offset().top
    }, 300);
}

// Ex: smoothScrollTo('#anchor');

Anchor 1

This page is made to demonstrate what i learned from some popular javascript library/framework. For now, it used H5BP as basic template, Bootstrap for layout and CSS style, and jQuery. (Backbone.js is going to be added for MVC implemenation)

Anchor 2

This page is made to demonstrate what i learned from some popular javascript library/framework. For now, it used H5BP as basic template, Bootstrap for layout and CSS style, and jQuery. (Backbone.js is going to be added for MVC implemenation)

Anchor 3

This page is made to demonstrate what i learned from some popular javascript library/framework. For now, it used H5BP as basic template, Bootstrap for layout and CSS style, and jQuery. (Backbone.js is going to be added for MVC implemenation)




2013/07/19

文字顯示過長時以省略符號顯示並提示完整文字

此CSS只作用於單行文字的顯示上
.text-overflow-ellipsis {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

為了達到只在過長被省略才顯示提示,需要用javascript判斷一下 (這邊以jQuery為例)
$(function() {
    $('.text-overflow-ellipsis').each(function() {
        if (this.offsetWidth < this.scrollWidth && !$(this).attr('title')) {
            $(this).attr('title', $(this).text());
        }
    });
});

2013/07/17

取得瀏覽器顯示的Scrollbar寬度


有些情況下,需要取得Scrollbar寬度來動態計算元件長寬
參考了一下網路上的作法,用jQuery寫了一個function來做這件事
/**
 * 1. Generate nested divs
 * 2. Calculate the width of inner div before and after scrollbar becomes visible.
 * @returns calculated scrollbar width
 */
function getScrollbarWidth() {
    var $tempNode = 
        $('<div/>')
            .css({
                width: 100,
                position: 'absolute',
                top: -1000
            })
            .append($('<div/>', { height: 100 }))
            .appendTo('body');
 
    var withoutSroll = $tempNode.children(':first').innerWidth();
    var withScroll = $tempNode.css({ 'overflow-y': 'scroll' })
                        .children(':first').innerWidth();

    $tempNode.remove();
    return withoutSroll - withScroll;
}

Backbone.js 雜記

版本1.0.0
  • extend Backbone.View 時傳入的參數:events,格式
    {'event selector': 'callback'}
    底層使用 jQuery.on(event, selector, callback) 來完成事件註冊,要注意的是如果 selector 有值,根據 jQuery api 這事件只會發生在根 DOM 下符合 selector 條件的子 DOM 上。
    When a selector is provided, the event handler is referred to as delegated. The handler is not called when the event occurs directly on the bound element, but only for descendants (inner elements) that match the selector.
  • Backbone的View與Model要達到資料與顯示同步,得自行從View用listenTo()對Model的資料變動時的事件作處理

2012/10/23

alert('8' > '10'); // true?

在javascript內字串比較是依據長度,由左而右依序比較,規則是:
  • 相等則往下一位字元比較,反之則得出結果
  • 有值的比沒值的大

A的編碼是0041
B的編碼是0042
alert(‘A’ > ‘AB’); // false,因為最高位(最左邊)字元相等,而AB比較長
alert(‘B’ > ‘AB’); // true,最高位字元B比A大

再來看 ‘8’,‘1’,‘0’
0的編碼為0030
1的編碼為0031
8的編碼為0038
alert(‘8’ > ‘10’); // true
由於最高位’8’比’1’來的大,所以結果為true

2011/08/25

javascript中的null與undefined的差異

有些時候會作 object detection 來判斷物件是否存在(像是在 function 內判斷傳進來的參數存在與否),而判斷的標準用 null 或 undefined 其實會有些微的不同。
ECMA-262標準(*註1)中關於這部份的敘述:
  • undefined value

    primitive value used when a variable has not been assigned a value.
  • null value

    primitive value that represents the intentional absence of any object value.
簡單說,null 表示無值,而 undefined 表示沒有定義的變數。
下面就分別對其做了一些測試:

null
雖然 type 是 objet,null 但不算一個真正的物件,不是空字串'',也不是 false 值,但如果直接當成條件式來判斷,會得到 false
alert(null); //null
alert(typeof null); //object
alert(null == ''); //false
alert(null == false); //false
alert(null instanceof Object); //false
alert(null ? true: false); //false
理所當然的也不能對 null 的屬性作操作
var nullObj = null;
nullObj.property = 'value'; //丟出TypeError
alert(nullObj.someProperty) //丟出TypeError

undefined
undefined 的 type 就是 undefined,當成條件式使用一樣會得到 false
alert(typeof undefined); //undefined
alert(undefined == ''); //false
alert(undefined == false); //false
alert(undefined instanceof Object); //false
alert(undefined ? true: false); //false
沒宣告過的變數,雖然 type 是 undefined,但存取它則會丟出 ReferenceError
alert(typeof undefinedObj); //undefined
alert(undefinedObj); //丟出ReferenceError
alert(undefinedObj.property); //丟出ReferenceError
alert(undefinedObj === undefined); //丟出ReferenceError
宣告卻沒給值的變數,預設會給它 undefined 的值
var undefinedObj;
alert(typeof undefinedObj); //undefined
alert(undefinedObj); //undefined
alert(undefinedObj.property); //丟出ReferenceError
alert(undefinedObj === undefined); //true
定義過的物件,屬性未定義(宣告)前都屬於"宣告卻沒給值的變數",也就是帶 undefined 值
var definedObj = new Object();
alert(typeof definedObj.property) //undefined
alert(definedObj.property); //undefined
alert(definedObj.property === undefined); //true
從 function 內接收的參數如果有宣告且呼叫時未傳入值,等同宣告卻沒給值的變數
function methodCall(parameter) {
 alert(typeof parameter); //undefined
 alert(parameter); //undefined
}
methodCall();
微妙的是,用 == 運算子做比較,null 跟 undefined 會得到 true
alert(null == undefined) //true
alert(null === undefined); //false

結論
null 跟 undefined 就像 true/false 一樣表示一個值;而用於 object detection 的時候,遇到一個不知道宣告與否的變數,用 typeof 來判斷比較好。因為除非你自己設 null 值,不然在程式中遇到的機率很低。(目前我只知道 document.getElementById() 如果找不到元素,會回傳 null)
//如果用其他運算子來判斷,遇到未宣告過的變數會直接丟error
if(typeof obj == 'undefined') {
 //do something here...
}

//真的擔心會遇到null值,可以再加上後面的判斷式
if(typeof obj == 'undefined' && obj) {
 //do something here...
}
對於已宣告的物件,則可以直接當成條件式來使用
var definedObj = new Object();
//javascript中&&和||只要運算到可以得出結果就會忽略剩下的運算式
//所以如果otherObj無定義,則直接跳出此if判斷
if(definedObj.otherObj && definedObj.otherObj.someFunction) {
 definedObj.otherObj.someFunction();
}

//函式呼叫
function methodCall(parameter) {
 if(parameter) {
  //do something with parameter...
 }
}

註1:ECMA-262 是 javascript 的標準,由 ECMA 這個組織定的

2011/08/19

javascript的物件導向程式設計

javascript 是一種 prototype-based 的語言,在 OOP 的寫法上相較於 java 更為麻煩,所以特別研究了一下幾篇文章,順便紀錄一下心得,免得以後忘記。


物件的建立
一種是透過 new 關鍵字
//這個牽涉到建構子,稍後會提到
var banana = new Fruit();
另一種則是使用 {} 宣告一個物件
//隱含的建立一個 javascript 內建的 Object 物件
var banana = {
 //物件屬性
 color: 'yellow',
 size: '15cm',
 //物件方法
 destroy: function() {
  alert('Noooooooooo!');
 }
};


建構子(Constructor)、物件屬性和物件方法的宣告
使用 function 宣告不只是可以建立函式,也可以建立一個建構子。而屬性和方法可以在建構子內宣告,這種方式相當於在每個物件建立時才把屬性和方法附加在物件上;不過這樣做有個缺點,如果父類別採用這種方式宣告,當存取父類別的屬性或方法時,會變成 undefined,因為屬性和方法是附加在每個建立好的物件上,而不是類別本身。
//建構子乍看之下就只是一個函式而已
function Fruit(name, color) {
 //私用屬性(private)
 //其實就是區域變數的概念而已
 var secret = 'You cant see this property.';
 //公用屬性(public)
 this.name = name;
 this.color = color; 
 
 //私用方法(private)
 function doNothing() {};
 //公用方法(public)
 this.changeColor = function(newColor) {
  this.color = newColor;
 }
}
之後便可以透過 new 來產生新的類別實體
//建立類別實體
var fruit1 = new Fruit('banana', 'yellow');
var fruit2 = new Fruit('apple', 'red');

alert(fruit1 instanceof Fruit); //true
alert(fruit1 === fruit2); //false
alert(fruit1.color); //yellow

fruit1.changeColor('green');
alert(fruit1.color); //green

alert(typeof fruit1.secret); //undefined
alert(typeof fruit1.doNothing); //undefined
alert(typeof fruit1.stillDoNothing); //undefined
但是如果直接對變數宣告屬性或方法,只會附加在目標變數指向的物件上,而不是類別本身。
//直接對變數宣告屬性
fruit1.looks = 'Like a banana.';
var fruit3 = new Fruit('grape', 'purple');

alert(fruit1.looks); //Like a banana.
alert(typeof fruit3.looks); //undefiend


javascript 的 prototype 與繼承(Inheritance)
在 javascript 中物件的繼承跟 prototype 這個屬性有很大的關係。

在取出物件的屬性時,會先去檢查該物件是否有直接定義目標屬性;若是沒有,則檢查該物件的 prototype 物件有沒有定義,如果還是沒有,會往 prototype chain (透過繼承將 prototype 鏈結起來)的上一層找,直到根部的 prototype 為止。特別要注意的是所有的物件都會隱含的參照到一個 prototype,但是只有 Function 物件(建構子)可以直接存取 prototype 屬性。

而物件的屬性和方法比較正規的宣告方式也是使用 prototype 來宣告,這樣做有一個好處,就是可以設定屬性初始值。
//改用繼承的方式來寫
//水果建構子
function Fruit(name) {
 this.name = name ? name : this.name;
}

//使用 prototype 作宣告並初始化
Fruit.prototype.name = 'Fruit';
Fruit.prototype.inFruit = 'inFruit';
Fruit.prototype.show = function() {
 alert(this.name);
};

//香蕉建構子,香蕉是一種水果我跟你說
function Banana() {
 //呼叫父類別的建構子
 this.super.call(this, 'Banana');
}

//繼承自 Fruit
//也是把 Banana 接上 Fruit 的 prototype chain
Banana.prototype = new Fruit();
//修正 Banana 的建構子指標,根據網路上的說法他會指向 Fruit 的建構子
//但測試後,有沒有這行其實沒差,因為上面已經宣告過 Banana 的建構子了
Banana.prototype.constructor = Banana;

//使用 prototype 作宣告並初始化
Banana.prototype.super = Fruit; //父類別參照(super)得自己宣告,
                                //因為 javascript 不提供直接參
                                //照到父類別的變數
Banana.prototype.color = 'yellow';
Banana.prototype.changeColor = function(newColor) {
 this.color = newColor;
};
//覆寫父類別的function
Banana.prototype.show = function() {
 alert(this.name + '\'s color is ' + this.color + '.');
};

var banana = new Banana();
alert(banana instanceof Banana); //true
alert(banana instanceof Fruit); //true
alert(banana.inFruit); //inFruit
banana.show(); //Banana's color is yellow.

banana.changeColor('green');
banana.show(); //Banana's color is green.
若要存取父類別的屬性或方法,還是要透過 prototype 來取得。
alert('Parent\'s name is ' + banana.super.prototype.name + '.');
                                       //Parent's name is Fruit.
banana.super.prototype.show(); //Fruit

2011/08/18

javascript的Function.apply()與Function.call()

有時候寫網頁時,DOM 元素的事件處理函式,裡面都是用 this 來存取觸發事件的元素;若想直接呼叫這些處理函式,則 this 會變成指向 window 物件。在沒有辦法指定 this 的情況下要如何直接呼叫這些函式呢?老師有沒有蕉你要多翻API...還愣著做什麼!

原生的 Function 物件提供了兩個函式 apply 與 call,可以在呼叫函式時改變函式內 this 指向的物件
Function.apply(obj, [argument1, argument2, ..., argumentN]);
Function.call(obj, argument1, argument2, ..., argumentN);

而這兩個函式的差異只在參數的傳遞方式而已,第一個參數皆為 this 的指標,而呼叫函式時的參數,apply 用陣列把參數包起來,call 則是依序列出參數
function alertColor(name) {
 //若直接呼叫此函式,this 會指向底層的 window 物件
 alert(name + '\'s color is ' + this.color + '!');
} 

function Fruit(color) {
 this.color = color; 
}

var banana = new Fruit('yellow');
var apple = new Fruit('red');
alertColor.apply(banana, ['Banana']);
alertColor.call(apple, 'Apple');

據說這在實作物件階層時特別有用(呼叫父類別的函式?),有機會研究在補上。

jQuery與其他library的相容問題

以前傻傻的沒碰過,到了真的遇到其他 javascript library 也用 $ 當變數的時候,要改起來的時候還真有些麻煩咧...好在官方也不是傻子,他們提供了一個方便又好用的函式 jQuery.noConflict,可以將 $ 的控制權釋放出去,於是就有了下列幾種解法:


jQuery 程式碼包成函式
jQuery.noConflict();
(function($) {
   //Write you jQuery code here, use $ instead of jQuery...
   $('div').html('testing');
})(jQuery);
將程式碼包在一個函式裡面,將 jQuery 作為一個參數傳遞進去,在接收時就可以任意命名了 (這裡是使用預設的 $ ),缺點是只有在這函式內可以使用 $,有 scope 上的限制


用其他別名取代 $
var j = jQuery.noConflict();
//Do something with jQuery...
j('input').hide();
//Do something with another library's $
$.something();
宣告一個變數接受 jQuery.noConflict() 回傳的值,就可以直接當成別名使用了


直接使用原來的變數名稱
jQuery.noConflict();
//Do something with jQuery...
jQuery('input').hide();
//Do something with another library's $
$.something();
跟上面那個沒什麼不同,變數名稱的差異而已


自己寫的網頁應該是不容易發生這種問題,倒是如果要改別人寫的東西,要加東加西時最好先看一下用了哪些 library,避免浪費無謂的時間。