《JavaScript修煉之道》讀書筆記

1、參考書目

入門:《JavaScript DOM編程藝術》第二版

進階:《JavaScript高級程序設計》第二版、《JavaScript編程精粹》

《JavaScript權威指南》

2、引言

Node.js是CommonJS的一個部分實現

本書代碼下載:

http://github.com/tdd/pragmatic-javascript

https://github.com/tdd/pragmatic-javascript/archive/master.zip

http://media.pragprog.com/titles/pg_js/code/pg_js-code.tgz

介紹的框架包括:Prototype、jQuery、MooTools、YUI、Dojo、ExtJS

 

3、利用事件委託

  • 優先使用事件委託
  • 元素共享同一個行爲,最好在DOM高層次監聽事件,這樣可以節省內存和CPU時間

dom/delegation.html

<ul id="items">
  <!-- We will insert togglers in each LI using JS -->
  <li><div><p>Data 1</p><p>Data 2</p></div></li>
  <li><div><p>Data 1</p><p>Data 2</p></div></li>
  <li><div><p>Data 1</p><p>Data 2</p></div></li>
  <!-- Potentially lots more elements here… -->
</ul>

dom/delegation.js(Prototype)

document.observe('dom:loaded', function() {
  $('items').observe('click', function(e) { 
    var trigger = e.findElement('a.toggler'); 
    if (!trigger) return;
    e.stop();
    var content = trigger.up('p').next('div');
    if (!content) return;
    content.toggle();
    trigger.update(content.visible() ? 'Close' : 'Open');
    trigger.blur();
  });

  $('items').select('li').each(function(item) {
    item.insert({ top: '<p><a class="toggler" href="#">Open</a></p>' });
    item.down('div').hide();
  });
});

4、模擬後臺處理

  • 利用HTML5的Web Workers實現多線程
  • 分解成多個小任務,利用setTimerout和clearTimeout模擬後臺處理
var handle = windows.setTimeout(callback, intervalInMs)
window.clearTimeout(hanle);

參考https://github.com/madrobby/emile 50行小程序實現精確定時器

(function(emile, container){
  var parseEl = document.createElement('div'),
    props = ('backgroundColor borderBottomColor borderBottomWidth borderLeftColor borderLeftWidth '+
    'borderRightColor borderRightWidth borderSpacing borderTopColor borderTopWidth bottom color fontSize '+
    'fontWeight height left letterSpacing lineHeight marginBottom marginLeft marginRight marginTop maxHeight '+
    'maxWidth minHeight minWidth opacity outlineColor outlineOffset outlineWidth paddingBottom paddingLeft '+
    'paddingRight paddingTop right textIndent top width wordSpacing zIndex').split(' ');

  function interpolate(source,target,pos){ return (source+(target-source)*pos).toFixed(3); }
  function s(str, p, c){ return str.substr(p,c||1); }
  function color(source,target,pos){
    var i = 2, j, c, tmp, v = [], r = [];
    while(j=3,c=arguments[i-1],i--)
      if(s(c,0)=='r') { c = c.match(/\d+/g); while(j--) v.push(~~c[j]); } else {
        if(c.length==4) c='#'+s(c,1)+s(c,1)+s(c,2)+s(c,2)+s(c,3)+s(c,3);
        while(j--) v.push(parseInt(s(c,1+j*2,2), 16)); }
    while(j--) { tmp = ~~(v[j+3]+(v[j]-v[j+3])*pos); r.push(tmp<0?0:tmp>255?255:tmp); }
    return 'rgb('+r.join(',')+')';
  }
  
  function parse(prop){
    var p = parseFloat(prop), q = prop.replace(/^[\-\d\.]+/,'');
    return isNaN(p) ? { v: q, f: color, u: ''} : { v: p, f: interpolate, u: q };
  }
  
  function normalize(style){
    var css, rules = {}, i = props.length, v;
    parseEl.innerHTML = '<div style="'+style+'"></div>';
    css = parseEl.childNodes[0].style;
    while(i--) if(v = css[props[i]]) rules[props[i]] = parse(v);
    return rules;
  }  
  
  container[emile] = function(el, style, opts, after){
    el = typeof el == 'string' ? document.getElementById(el) : el;
    opts = opts || {};
    var target = normalize(style), comp = el.currentStyle ? el.currentStyle : getComputedStyle(el, null),
      prop, current = {}, start = +new Date, dur = opts.duration||200, finish = start+dur, interval,
      easing = opts.easing || function(pos){ return (-Math.cos(pos*Math.PI)/2) + 0.5; };
    for(prop in target) current[prop] = parse(comp[prop]);
    interval = setInterval(function(){
      var time = +new Date, pos = time>finish ? 1 : (time-start)/dur;
      for(prop in target)
        el.style[prop] = target[prop].f(current[prop].v,target[prop].v,easing(pos)) + target[prop].u;
      if(time>finish) { clearInterval(interval); opts.after && opts.after(); after && setTimeout(after,1); }
    },10);
  }
})('emile', this);

dom/background.js

var CHUNK_INTERVAL = 25; // ms.
  var running = false, progress = 0, processTimer;

  function runChunk() {
    window.clearTimeout(processTimer);
    processTimer = null;
    if (!running) return;
    // Some work chunk.  Let's simulate it:
    for (var i = 0; i < 10000; i += (Math.random() * 5).round())
      ;
    ++progress;
    updateUI(); // See source archive -- just updates a progressbar
    if (progress < 100) {
      processTimer = window.setTimeout(runChunk, CHUNK_INTERVAL);
    } else {
      progress = 0, running = false;
    }
  }
  
  function toggleProcessing() {
    running = !running;
    if (running) {
      processTimer = window.setTimeout(runChunk, CHUNK_INTERVAL);
    }
  }

5、打造漂亮的tooltip

用CSS屬性設置tooltip元素爲默認隱藏,並在其內容標籤上加:hover選擇器來恢復顯示。

但這種方式在IE6不起作用,因爲IE6只允許<a>元素上有:hover。只能手動編寫腳本,響應mouseover和mouseout。

作者推薦Prototype的Prototip2庫http://www.nickstakenburg.com/projects/prototip2/

4{5OB7)DWK}Y6YWLGWM3CCA

ui/tooltips/index.html

<li tabindex="1">
    <span class="name">Capacity: 1.5 TB</span>
    <div class="tooltip" >
      <p><strong>1.5 Terabyte = 1,536 Gigabytes</strong></p>
      <p>Enough for 50,000 songs, 1,000 DivX movies, 100,000
        high-definition photos, hundreds of iDVD projects and
        plenty of backup space left.</p>
    </div>
  </li>

ui/tooltips/tooltips.css

#files li { position: relative; }
#files li .tooltip {
  position: absolute; top: 8px; left: 120px; width: 24em;
  z-index: 1; display: none;
  /* IE6 doesn't know li:hover, so we need to toggle via JS,
     therefore avoiding in-rule display: none */
  _display: block;
  border: 1px solid gray; 
  background: #fffdc3 url(bg_tooltip.png) top left repeat-x;
}
#files li:hover .tooltip,
#files li:focus .tooltip { display: block; }

ui/tooltips/tooltips.js

function toggle(reveal, e) {
    var trigger = e.findElement('li'),
      tooltip = trigger && trigger.down('.tooltip');
    if (!tooltip) return;
    tooltip[reveal ? 'show' : 'hide']();
  }
  
  document.observe('dom:loaded', function() {
    var isIE6 = Prototype.Browser.IE &&
      undefined === document.body.style.maxHeight;
    if (!isIE6) return;
    var files = $('files'), tooltips = files && files.select('.tooltip');
    if (!files || 0 == tooltips.length) return;
    tooltips.invoke('hide');
    files.observe('mouseover', toggle.curry(true)).
      observe('mouseout', toggle.curry(false));
  });

 

6、友好的彈窗

用<a>鏈接到要彈出的內容(href=,target=”_blank”),然後在鏈接上掛上JavaScript代碼。這樣可以解決禁止彈窗、屏幕閱讀器(視覺障礙者使用)、搜索引擎的訪問問題。

ui/popups/index.html

<p>
  The great thing about <a class="popup" target="_blank"
  href="http://pragprog.com/titles/pg_js">Pocket Guide to JavaScript</a>
  is that it focuses on a bunch of specific, useful tasks.</p>

ui/popus/popus.js

var POPUP_FEATURES = 'status=yes,resizable=yes,scrollbars=yes,' + 
    'width=800,height=500,left=100,top=100';
  
  function hookPopupLink(e) {
    var trigger = e.findElement('a.popup');
    if (!trigger) return;
    e.stop(); trigger.blur();
    var wndName = trigger.readAttribute('target') ||
      ('wnd' + trigger.identify());
    window.open(trigger.href, wndName, POPUP_FEATURES).focus();
  }
  
  document.observe('click', hookPopupLink);

7、光箱特效

u=1109846169,3307702938&fm=21&gp=0

利用FancyBox jQuery插件

ui/lightbox/lightbox.js

$('#thumbnails a').fancybox({
    zoomSpeedIn: 300, zoomOpacity: true, overlayColor: '#000',
    overlayOpacity: 0.6
  });

8、無限翻頁

ui/infinite/infinite.js

function lowEnough() {
    var pageHeight = Math.max(document.body.scrollHeight,
      document.body.offsetHeight);
    var viewportHeight = window.innerHeight ||
      document.documentElement.clientHeight || 
      document.body.clientHeight || 0;
    var scrollHeight = window.pageYOffset ||
      document.documentElement.scrollTop || 
      document.body.scrollTop || 0;
    // Trigger for scrolls within 20 pixels from page bottom
    return pageHeight - viewportHeight - scrollHeight < 20;
  }

  function checkScroll() {
    if (!lowEnough()) return pollScroll();
    $('spinner').show();
    new Ajax.Updater('posts', 'more.php', {
      method: 'get', insertion: 'bottom',
      onComplete: function() { $('spinner').hide(); },
      onSuccess: pollScroll
    });
  }
  
  function pollScroll() { setTimeout(checkScroll, 100); }
  
  pollScroll();

9、載入內容時保持顯示區域的位置不變

ui/viewport/index.html

<h2>Comments</h2>

<div id="extraComments">
  <a id="loadKnownComments" href="?with_known_comments">See previous
    comments you already know about</a>
</div>

<h3>Comment 5</h3>

ui/viewport/viewport.js

function loadKnownComments(e) {
    e.stop();
    var zone = $('extraComments'), ref = zone.next('h3');
    var upd = new Ajax.Request('known_comments.html', {
      method: 'get',
      onSuccess: function(res) {
        var orig = ref.cumulativeOffset().top -
          document.viewport.getScrollOffsets().top;
        zone.insert({ before: res.responseText });
        window.scrollTo(0, ref.cumulativeOffset().top - orig);
      }
    });
  }
  
  document.observe('dom:loaded', function() {
    var loader = $('loadKnownComments');
    loader && loader.observe('click', loadKnownComments);
  });

10、提供輸入長度的反饋

  • 對keyup和keypress監聽,以及對非字符鍵(刪除、剪切、粘貼)做出響應。沒必要監聽keydown
  • 爲避免每次按鍵都重複計算最大長度,我們在初始化時把它緩存起來。爲了把最大長度和輸入區域關聯起來,我們用了JS關聯數組,這比用屬性輕便點

form/feedback/index.html

<p>
    <label for="edtDescription">Description</label>
    <textarea id="edtDescription" name="description" cols="40"
     rows="5" class="maxLength200"></textarea>
  </p>

form/feedback/feedback.js

var maxLengths = {};
  
  function bindMaxLengthFeedbacks() {
    var mlClass, maxLength, feedback;
    $$('*[class^=maxLength]').each(function(field) {
      field.up('p').addClassName('lengthFeedback');
      mlClass = field.className.match(/\bmaxLength(\d+)\b/)[0];
      maxLength = parseInt(mlClass.replace(/\D+/g, ''), 10);

      feedback = new Element('span', { 'class': 'feedback' });
      maxLengths[field.identify()] = [maxLength, feedback];
      updateFeedback(field);
      field.observe('keyup', updateFeedback).
        observe('keypress', updateFeedback);

      feedback.clonePosition(field, { setHeight: false,
        offsetTop: field.offsetHeight + 2 });
      field.insert({ after: feedback });
    });
  }
  
  function updateFeedback(e) {
    var field = e.tagName ? e : e.element();
    var current = field.getValue().length,
      data = maxLengths[field.id], max = data[0],
      delta = current < max ? max - current : 0;
    data[1].update('Remaining: ' + delta);
    if (current > max) {
      field.setValue(field.getValue().substring(0, max));
    }
  }

  document.observe('dom:loaded', bindMaxLengthFeedbacks);

11、同時選擇或反選多個checkbox

form/checklist/index_for_book.html

<table id="mailbox">
  <thead>
    <tr>
      <th><input type="checkbox" id="toggler" /></th>
      <th>Subject</th>
      <th>Date</th>
      <!-- From, Size, Attachments… -->
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><input type="checkbox" name="mail_ids[]" value="1" /></td>
      <td>Happy new year!</td>
      <td>Jan 1, 2010 00:03am</td>
      <!---->
    </tr>
    <!-- More rows… -->
  </tbody>
</table>

form/checklist/checklist.js

function toggleAllCheckboxes() {
    var scope = this.up('table').down('tbody'), boxes = scope &&
      scope.select('tr input[type="checkbox"]:first-of-type');
    var refChecked = this.checked;
    (boxes || []).each(function(box) { box.checked = refChecked; });
  }
  
  document.observe('dom:loaded', function() {
    $('toggler').observe('click', toggleAllCheckboxes);
  });

12、表單驗證

檢驗未填的必填項

form/validation101/validation101.js

function checkForm(e) {
    var firstOffender, value;
    this.select('.required').each(function(field) {
      value = field.getValue();
      if (value && !value.blank()) {
        field.up('p').removeClassName('missing');
      } else {
        firstOffender = firstOffender || field;
        field.up('p').addClassName('missing');
      }
    });
    if (firstOffender) { e.stop(); firstOffender.focus(); }
  }
  
  document.observe('dom:loaded', function() {
    $('registration').observe('submit', checkForm);
  });

檢查特定格式的輸入域

form/validation102/validation102.js

var FIELD_PATTERNS = {
    integer: /^\d+$/,
    number: /^\d+(?:\.\d+)?$/,
    email: /^[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$/i
  };
  
  function checkField(field) {
    var value = $F(field).toString().strip();
    for (var pattern in FIELD_PATTERNS) {
      if (!field.hasClassName(pattern)) continue;
      if (!FIELD_PATTERNS[pattern].test(value)) return false;
    }
    return true;
  }

和服務器端通信,監測登錄名域

form/validation_ajax/validation_ajax.js

document.observe('dom:loaded', function checkLogin() {
    var feedback = $('user_login').next('.feedback'),
      spinner = $('user_login').next('.spinner');
    new Field.Observer('user_login', 0.8, function(_, value) {
      if (value.length < 2) return;
      feedback.hide(); spinner.show();
      new Ajax.Request('check_login.php', {
        method: 'get', parameters: { login: value },
        onComplete: function(res) {
          if (Ajax.activeRequestCount > 1) return;
          if (res.request.success() && res.status) {
            feedback.update('Login available!').removeClassName('ko');
          } else {
            feedback.update('Login taken!').addClassName('ko');
          }
          spinner.hide(); feedback.show();
        },
      });
    });

form/validation_ajax/check_login.php

sleep(rand(5, 10) / 10.0); // Simulate intarwebs delay…
$RESERVED = array('bob', 'doudou', 'tdd', 'meshak', 'ook');
$login = isset($_GET['login']) ? $_GET['login'] : '';
$response = in_array($login, $RESERVED) ? '422 Conflict' : '202 Accepted';
header('HTTP/1.1 ' . $response);

13、在表單中提供動態的幫助tooltip

form/tooltips/index.html

<p>
    <label for="user_login">
      Login*
      <span class="tooltip" style="display: none;">
        Logins must be unique, at least 3 characters long,
        and may only use letters, numbers, white space,
        hyphens, underscores and periods.
      </span>
    </label>
    <input type="text" id="user_login" name="user[login]"
     class="required text" />
  </p>

form/tooltips/tooltips.css

#registration { font-family: sans-serif; }
#registration p { margin: 0 0 0.5em;}
/* START:main */
#registration label { float: left; width: 6em; position: relative; zoom: 1; }
#registration input.text { width: 14em; }
#registration .tooltip {
  display: block; position: absolute; left: 24em; top: 0;
  padding: 0.35em 0.5em 0.35em 2em; width: 15em;
  border: 1px solid silver;
  color: gray; font-size: 80%;
  background: #ffc url(lightbulb.png) 0.5em 0.3em no-repeat;
}

form/tooltips/tooltips.js

document.observe('dom:loaded', function() {
    var attr = Prototype.Browser.IE ? 'htmlFor' : 'for';
    function showTooltip() {
      var tooltip = $$('label['+attr+'="'+this.id+'"] .tooltip').first();
      tooltip && tooltip.show();
    }
    function hideTooltip() {
      var tooltip = $$('label['+attr+'="'+this.id+'"] .tooltip').first();
      tooltip && tooltip.hide();
    }
    
    $('registration').getInputs().invoke('observe', 'focus', showTooltip).
      invoke('observe', 'blur', hideTooltip);
  });

14、自動完成輸入

Prototype的Sctipt.aculo.us控件

form/autocompletion/index.html

<div class="p" id="local">
    <label for="edtCachedSearch">Local search:</label>
    <input type="text" id="edtCachedSearch" name="search" type="text" />
    <div class="completions"></div>
  </div>
  <div class="p">
    <label for="edtAjaxSearch">Ajax search:</label>
    <input type="text" id="edtAjaxSearch" name="search" type="text" />
    (capitals of the world)
    <div class="completions"></div>
  </div>

form/autocompletion/autocompletion.css

.completions {
  border: 1px solid silver; background: white; font-size: 80%; z-index: 2;
}
.completions ul { margin: 0; padding: 0; list-style-type: none; }
.completions li { line-height: 1.5em; white-space: nowrap; 
                  overflow: hidden; }
.completions li.selected { background: #ffa; }
.completions strong { color: green; }

form/autocompletion/autocompletion.js

var FREQUENT_SEARCHES = [
    'JavaScript', 'JavaScript frameworks', 'Prototype', 'jQuery', 'Dojo',
    'MooTools', 'Ext', 'Ext JS', 'script.aculo.us', 'Scripty2', 'Ajax',
    'XHR', '42'
  ];
  
  function initLocalCompletions() {
    var field = $('edtCachedSearch'), zone = field.next('.completions');
    new Autocompleter.Local(field, zone, FREQUENT_SEARCHES, 
                            { fullSearch: true });
  }
  
  function initAjaxCompletions() {
    var field = $('edtAjaxSearch'), zone = field.next('.completions');
    new Ajax.Autocompleter(field, zone, 'autocomplete.php', {
      method: 'get', paramName: 'search' });
  }

15、多文件自動上傳

HTML5之前使用Base64編碼,每個上傳文件膨脹33%

form/uploads/index.html

<form method="post" action="server.php" enctype="multipart/form-data">
  <ul id="uploads"></ul>
  <p><input type="file" name="files[]" id="filSelector" /></p>
  <p><input type="submit" value="Send these files" /></p>
</form>

form/uploads/uploads.js

var ICONS = $H({ word: $w('doc docx'), image: $w('jpg jpeg gif png') });
  
  function getFileClass(fileName) {
    var ext = (fileName.match(/\.(.+?)$/) || [])[1].toString().toLowerCase();
    var icon = ICONS.detect(function(pair) { return pair[1].include(ext); });
    return (icon || [])[0];
  }
  
  function handleQueueRemoval(e) {
    var trigger = e.findElement('button');
    trigger && trigger.up('li').remove();
  }
  
  function queueFile() {
    var fileName = $F(this), clone = this.cloneNode(true);
    var item = new Element('li', { 'class': getFileClass(fileName) });
    $(clone).observe('change', queueFile).setValue('');
    this.parentNode.appendChild(clone);
    item.appendChild(this);
    item.appendChild(document.createTextNode(fileName));
    item.insert('<button><img src="remove.png" alt="Remove" /></button>');
    $('uploads').appendChild(item);
  }
  
  document.observe('dom:loaded', function() {
    $('filSelector').observe('change', queueFile);
    $('uploads').observe('click', handleQueueRemoval);
  });

16、使用JSON-P

JSON-P的傳輸主要依賴於動態生成的<script>標籤,所以傳輸數據可以不限於同一來源。

jsonp和ajax完全是兩個概念,可以說jsonp出現的理由就是彌補ajax無法跨域訪問的缺陷而出現的。jsonp返回的數據並不是json,而是javascrip。

參考文章:說說JSON和JSONP   初識jsonp

server/jsonp/jsonp.js

function injectData(data) {
    var ref = $('sysInfo').down('tbody tr:last-child'), row = new Element('tr'), key;
    ref.select('td').each(function(cell) {
      row.appendChild($(cell.cloneNode(true)).update(data[cell.className]));
    });
    ref.insert({ after: row });
  }
  window.injectData = injectData;
  
  function loadJSONPBasic(e) {
    e.stop(); this.blur();
    document.documentElement.firstChild.appendChild(
      new Element('script', { type: 'text/javascript',
        src: this.href + '&r=' + Math.random() }));
  }
  
  function loadJSONP(e) {
    e.stop(); this.blur();
    var script = new Element('script', { type: 'text/javascript',
      src: this.href });
    script.src += ('&r=' + script.identify());
    script.observe('load', Element.remove.curry(script));
    document.documentElement.firstChild.appendChild(script);
  }
  
  document.observe('dom:loaded', function() {
    $('triggerJSONP').observe('click', loadJSONP);
  });

隨機參數是爲了避免瀏覽器緩存而添加的,爲了保證代碼質量,最好先檢查下一URI,以決定用&還是?(這個參數是否是第一個參數)

在瀏覽器載入之後將其刪除,以免DOM變得過大

17、跨域“Ajax”1

跨域的方法:

  • 通過服務器端代理來載入數據
  • 跨來源資源共享(Cross-Origin Resource Sharing,CORS)。XHR2就是用的CORS,這也是W3C指定的跨域數據請求的方式
  • 使用JSON-P,或者同時使用動態/隱藏表單和<iframe>

server/crossdomain1/crossdomain1.js

// 同時使用動態生成的表單和<iframe>
  function loadUsingDF1(e) {
    e.stop(); this.blur();
    var warp = new Element('iframe', { name: '__blackhole' });
    warp.setStyle('width: 0; height: 0; border: 0');
    document.body.appendChild(warp);
    warp.observe('load', function() {
      $('responses').insert('<p>OK, posted.</p>');
    });
    var form = new Element('form', { method: 'post', action: this.href,
      target: '__blackhole' });
    form.submit();
  }
  
  // 使用得到204響應的動態生成的表單
  function loadUsingDF2(e) {
    e.stop(); this.blur();
    var form = new Element('form', { method: 'post', action: this.href });
    form.submit();
    Element.insert.defer('responses', '<p>OK, posted.</p>');
  }
  
  // 使用服務器端協議
  function loadUsingSSP(e) {
    e.stop(); this.blur();
    new Ajax.Updater({ success: 'responses' }, 'ssp.php', {
      method: 'get', parameters: { uri: this.href }, insertion: 'bottom'
    });
  }
  
  // 使用CORS兼容的XMLHttpRequest
  function loadUsingXHR(e) {
    e.stop(); this.blur();
    new Ajax.Updater({ success: 'responses' }, this.href, {
      method: 'get', insertion: 'bottom'
    });
  }

18、跨域“Ajax”2

YQL並不是雲數據庫的一部分,它是一個嚴格的查詢處理託管服務。另外,這也意味着YQL不受單獨的數據資源限制,甚至不限制應用於雅虎的自身產品。YQL可以操作任何第三方數據源,只要對方是一種常見的格式,如RSS, ATOM, JSON, XML,等等。

// 使用之前那種普通的JSON-P
  function loadUsingJSONP(e) {
    e.stop(); this.blur();
    window.jsonpCallback = function jsonpCallback(data) {
      $('responses').update(data.payload.escapeHTML());
    };
    document.documentElement.firstChild.appendChild(
      new Element('script', { type: 'text/javascript',
        src: this.href + '?r=' + Math.random() + '&callback=jsonpCallback' }));
  }
  
  // 使用JSON-P-X形式的YQL html表(XML格式的JSON-P)
  function loadUsingYQLget(e) {
    e.stop(); this.blur();
    window.yqlCallback = function yqlCallback(data) {
      $('responses').update('<ul>' + data.results.map(function(td) {
        return '<li>' + td.replace(/<\/?(?:td|p)[^>]*>/g, '').
          replace(/href="/g, 'href="http://github.com') + '</li>';
      }).join("\n") + '</ul>');
    };
    var url = this.href, xpath = "//*[@class='title']",
      yql = 'select * from html where url="' + url + '" and xpath="' + xpath + '"',
      data = { q: yql, format: 'xml', callback: 'yqlCallback' };
    document.documentElement.firstChild.appendChild(
      new Element('script', { type: 'text/javascript',
        src: 'http://query.yahooapis.com/v1/public/yql?' + Object.toQueryString(data) +
          '&r=' + Math.random()
    }));
  }
  
  // 使用JSON-P形式的YQL htmlpost表
  function loadUsingYQLpost(e) {
    e.stop(); this.blur();
    window.yqlCallback = function yqlCallback(data) {
      $('responses').update(data.query.results.postresult.p.join("<br/>"));
    };
    var post = Object.toQueryString({ foo: 'foo', bar: 'bar' }),
      url = this.href, xpath = "//p", env = 'store://datatables.org/alltableswithkeys',
      yql = 'select * from htmlpost where url="' + url + '" and postdata="' + post + '"' +
        ' and xpath="' + xpath + '"',
        data = { q: yql, format: 'json', env: env, callback: 'yqlCallback' };
    document.documentElement.firstChild.appendChild(
      new Element('script', { type: 'text/javascript',
        src: 'http://query.yahooapis.com/v1/public/yql?' + Object.toQueryString(data) +
          '&r=' + Math.random()
    }));
  }

  // 使用CSSHttpRequest
  function loadUsingCHR(e) {
    e.stop(); this.blur();
    CSSHttpRequest.get(this.href, function(res) {
      $('responses').insert('<p>' + res.escapeHTML() + '</p>');
    });
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章