$(document).ready(function(){
if (this.id == 'switcher-narrow') {
$('body').addClass('narrow');
}
else if (this.id == 'switcher-large') {
$('body').addClass('large');
}
});
Compound Event
ready(), toggle(), hover()
toggle
$(document).ready(function() {
$('#switcher h3').toggle(function() {
$('#switcher .button').addClass('hidden');
}, function() {
$('#switcher .button').removeClass('hidden');
});
});
$(document).ready(function() {
$('#switcher h3').click(function() {
$('#switcher .button').toggleClass('hidden');
});
});
hover
$(document).ready(function() {
$('#switcher .button').hover(function() {
$(this).addClass('hover');
}, function() {
$(this).removeClass('hover');
});
});
The Journey of Event
event capturing
event bubbling
Preventing Event Bubbling
$(document).ready(function() {
$('#switcher').click(function(event) {
if (event.target == this) {
$('#switcher .button').toggleClass('hidden');
}
});
});
event.target 可以知道第一個觸發 event 的是哪個element
Stopping Event Propagation
event.stopPropagation()
Default Actions
.preventDefault() 阻止一些例如link 的預設行為
.preventDefault + .stopPropagation = return false
Removing an Event Handler
$(document).ready(function() {
var toggleStyleSwitcher = function() {
$('#switcher .button').toggleClass('hidden');
};
$('#switcher').click(toggleStyleSwitcher);
$('#switcher-narrow, #switcher-large').click(function() {
$('#switcher').unbind('click', toggleStyleSwitcher);
});
});
只執行一次toggle
$(document).ready(function() {
$('#switcher').one('click', toggleStyleSwitcher);
})
Simulating User Interaction
幫妳觸發 click
$(document).ready(function() {
$('#switcher').trigger('click');
});
$(document).ready(function() {
$('#switcher').click();
});
2008年5月3日 星期六
jQuery memo 3
2008年5月2日 星期五
jQuery memo1,2
addClass(), removeClass()
$(document).ready(function(){
});
$(function(){
});
//not include class, element
$('#selectd-plays li:not(.horizontal)').addClass('sub-level');
$('tr:not([th]):even').addClass('even')
//attribute
$('a[@title]')
//element
$('div[ol]')
// ^
$('a[@href^="mailto:"]').addClass('mailto')
//$
$('a[@href$=".pdf"]').addClass('pdflink')
//*
&('a[@href*="mysite.com"]').addClass('mysite')
//js zero-based ; CSS one-based
$('div.horizontal:eq(1)')
$('tr:odd').addClass('odd') = $('tr').filter(':odd').addClass('odd')
$('tr:even').addClass('even')
$('td:contains("Henry")').addClass('highlight')
//contain value
$('th').parent().addClass('table-heading')
$('td:contains("Henry")').next().addClass('highlight')
$('th').siblings().addClass('table-heading')
//拿到DOM Elements
$('#my-element') => jQuery object
$('#my-element').get(0).tagName
some archives, 許多高手好文
http://ihower.idv.tw/blog/archives/1691
http://ihower.idv.tw/blog/archives/1696
http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model
Don’t Loop Around ActiveRecord
ActiveRecord 跑迴圈的時候小心產生一筆一筆 SQL queries 啊,請愛用 :include 一次就把(子)資料讀出來,而不是一筆筆去捅資料庫。甚至直接寫點 SQL conditions,目標是讓 SQL query 一次即可。若要用 :select 請搭配 :join。
Beware of Binary Fields
若欄位有 Binary data,用 find 時請務必愛用 :select 只讀出必要欄位。另外也建議使用 with_scope method 或 scope_out plugin。
Keep Your Controllers and Views Skinny
實在是 Rails 的原罪: 因為 ActiveRecord 提供很多好用的 method,所以我們習慣把 code 塞到 controller 甚至 view 裡。正確的作法應該盡量重構至 Model 中 (例如有複雜參數的 find ),有可讀性、可測試(model unit testing)跟好的MVC。請看這篇經典文章 Skinny Controller, Fat Model。這裡作者又在推薦了一次 with_scope 。
Don’t Store Objects in the Session
別這樣做 session[:user]=user,你的memory很快用完,而且session資料跟db資料不一致,請用 session[:user_id] = user.id。真要存 object 請裝 Memcached 吧。
Avoid Heavy Response Processing
耗用時間的操作請用 queuing system,入門方法可用 rake 跟 crob 自動執行,進階有 BackgroundRB, Amazon’s SQS 等。可以試試 acts_as_state_machine 這個 plugin 來設計自己的排程系統。
Use ActiveRecord Mailing
寄送大量郵件,介紹 ar_mailer plugin
Date Formatting
用 parse_date 把 String 變成 Date 是個非常昂貴的操作,建議你直接用字串操作(正規表示法)把 String(例如從DB撈出來的db_date) 變成你想要的格式,或是從中拆出你想要的年月日。(PDF 有 example code)
ObjectSpace.each_object
DO NOT USE IT,你不會想在 per-request 下去執行的,很貴。
Symbol.to_proc
ActiveSupport 提供的 @var.map(&:name) 語法,雖然方便,但是用 inline block 的方法 @var.map{ |a| a.name| } 執行效率比較快。
Using .nil?
如果要測試的值已知不是 Boolean,那就不需要用 .nil 多一個 method call,直接 if x 就好了而不是 if x.nil?
nil? or empty? versus blank?
ActionPack 有提供 x.blank?,不需要用 x.nil? || x.empty?
Test Most Frequent Case First
用 case 時把較常發生的放前面,若都差不多,把貴的操作的放後面。
Optimize Access to Global Constants
在 Constant 前面加上 namespace operator :: 會比較快,減少查詢時間
Caching Data in Instance Variables
例如在 controller 裡面 def captial_letters { (”A”..”Z”).to_a } end 請改用 def captial_letters { @captial_letters ||= (”A”..”Z”).to_a } end
Local Variables Are Cheap
method 中傳進來的參數若常用,可以先存成 Local Variables 再來多次使用。
Interpolated Strnges
方法一 s = “:#{a}.#{b}” 比方法二 s = “:” <<>
In-Place Updates
直接修改比複製一份快: gsub! 比 gsub 快,merge! 比 merge 快。例如這個範例 s.gsub().gsub!().gsub! 而不是 s.gsub.gsub.gsub
2008年5月1日 星期四
jQuery some example
$("div.contents p")
<div id="body">
<h2>Some Header</h2>
<div class="contents">
<p>...</p>
<p>...</p>
</div>
</div>
選取 class 為 contents 的 <div> 所包住的所有下層的 <p>
$("div > div")
<div id="body">
<h2>Some Header</h2>
<div class="contents">
<p>...</p>
<p>...</p>
</div>
</div>
解釋:選取被 <div> 包住的下一層 <div>
$("div:has(div)")
<div id="body">
<h2>Some Header</h2>
<div class="contents">
<p>...</p>
<p>...</p>
</div>
</div>
解釋:和前一個範例相反,這邊是選取至少有包住一個 <div> 的 <div>
$("a[target]").append(" (Opens in New Window)");
1. $("#body").css({
2. border: "1px solid green",
3. height: "40px"
4. });
1. $("form").submit(function() {
2. if ($("input#username").val() == "")
3. $("span.help").show();
4. });
當 user 點選 id 為 open 的連結時,顯示 id 為 menu 的區塊,並回傳 false 避免瀏覽器真的換頁。
1. $("a#open").click(function() {
2. $("#menu").show();
3. return false;
4. });
$("#menu").slideDown("fast");
1. $("div").animate({
2. width: '300px',
3. padding: '20px'
4. }, 'slow');
1. $("div").hide(500, function(){
2. // $(this) 是每一個各別的 <div>
3. $(this).show(500);
4. });
取得 sample.html 並將找出文件內所有 <div> 下一層的 <h1> 填入原本文件 id 為 body 的元素內
1. $("#body").load("sample.html div > h1");
透過 getJSON() 取得 JSON 格式的資料,並透過 callback 函數處理資料
1. $.getJSON("test.json", function(data){
2. for (var idx in data)
3. $("#menu").append("<li>" + data[idx] + "</li>");
4. });
$("div").css("color", "blue");
1. $("ul.open") // [ ul, ul, ul ]
2. .children("li") // [ li, li, li ]
3. .addClass("open") // [ li, li, li]
4. .end() // [ ul, ul, ul ]
5. .find("a") // [ a, a, a ]
6. .click(function(){
7. $(this).next().toggle();
8. return false;
9. }) // [ a, a, a ]
10. .end(); // [ ul, ul, ul ]
1. var $j = jQuery.noConflict();
2. $j(document).ready(function() {
3. $j("div").addClass("special");
4. });
jquery, select, change, inject
Problem
想把select 到的item value 加到text field裡
<%= text_field_tag :email %>
<%= select :contact, :user, @me.contacts.inject([]){|a, user| a << [user.nickname, user.nickname] }, :id => 'select_user', :prompt => '通訊錄聯絡人' %>
Solution
http://jquery.com/api/
http://visualjquery.com/1.1.2.html
<script type="text/javascript">
$(document).ready(function(){
$('#contact_user').change(function(){
str = $('#contact_user option:selected').val();
contact_str = $('#email').val();
$('#email').val(contact_str+','+str);
});
</script>
$('#contact_user option:selected') 取到的是jQuery object 他是沒有value 的
要用val() 去取
$('#contact_user option:selected').get(0) 取到的才是該 element 才有 value attribute
所以也可以寫成$('#contact_user option:selected').get(0).value = "ooxx" 當然比較麻煩
append 是加在element 後, 不是value
find, sql in ; select detect partition concat gsub split
http://www.rubyinside.com/clever-find-conditions-in-rails-without-sql-56.html
list = [1,2]
User.find(:all, :conditions => {:id => list, :staus => 'health'})
User.find(:all, :conditions => ["follows_counter =0 and id In (?)",list])
SELECT * FROM `users` WHERE (`users`.`id` IN (1,2))
http://www.ruby-doc.org/core/classes/Enumerable.html#M003154
#把參數處理成 array
emails = params[:email].gsub(/\s/, "").gsub(/;/, ",").split(/,/)
in_email_users = User.find(:all, :conditions => {:nickname => emails })
in_email = in_email_users.map(&:nickname)
#就像是兩個回圈下去跑
out_emails = emails.select { |e| !in_email.detect{|i| i == e } }
#email 的驗證 regular expression
out_emails, wrong_emails = out_emails.partition { |e|
e =~ /^([_a-z0-9-]+)(\.[_a-z0-9-]+)*@([a-z0-9-]+)(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/
}
out_emails.concat(in_email)
>> (1..20).select {|i| i % 5 == 0 }
=> [5, 10, 15, 20]
>> (1..20).detect {|i| i % 5 == 0 }
=> 5
text_field, text_field_tag, link_to, link_to_remote
text_field(:session, :user, :onchange => "if $('session[user]').value == 'admin' { alert('Your login can not be admin!'); }")
# => <input type="text" id="session_user" name="session[user]" value="#{@session.user}" onchange = "if $('session[user]').value == 'admin' { alert('Your login can not be admin!'); }"/>
注意value = @session.user, id = session_user, name = session[user]
還有如何在這使用event像onchange
http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#M001038
text_field_tag 'payment_amount', '$0.00', :disabled => true
# => <input disabled="disabled" id="payment_amount" name="payment_amount" type="text" value="$0.00" />
id = name = payment_amount
<%= link_to "追蹤",{ :controller => "favorite", :action => "add", :id => @item.id }, :class => "bbt_ch", :title => "追蹤" %>
<%= link_to "", {:action => "push", :id => @item.id}, :confirm => '確定要推薦?', :method => :post, :class => "push" %>
用到些其他options 時, url部份要{} 起來
link_to_remote "Delete this post", :update => "posts", :url => { :action => "destroy", :id => post.id }
link_to_remote "Delete this post", :update => "posts", :url => post_url(@post), :method => :delete, :html => { :class => "destructive" }
<%= link_to_remote "Delete this post", {:url => user_url, :update => "post", :method => :delete}, :class => "sec"%>
url的部份要用url symbol指定, attribute的部份要用html symbol