2015-12-22 100 views
0

這是我參考上週發佈的questionJavascript - 將所有電話號碼替換爲「點擊通話」鏈接中​​的鏈接

我想查找頁面上的所有有效電話號碼。如果他們還不在鏈接中,我想創建一個「點擊呼叫」鏈接,以便在移動瀏覽器上使用。 對於我發佈的原始問題,我收到了一些很好的答案,但想嘗試不同的方法/擴展反饋。

我正在使用jQuery和正則表達式來過濾頁面的內容,並使鏈接可點擊。

這裏是我想出來的:

var phoneRegex = new RegExp(/([(]?\d{3}[)]?[(\s)?.-]\d{3}[\s.-]\d{4})(?![^<]*>|[^<>]*<\/)/g); 
    var phoneNums = $("body *").filter(function() { 
    var tagname = $(this).prop("tagName"); 
    tagname = tagname === null ? "" : tagname.toLowerCase(); 
    if (tagname == "a") { 
     return false; 
    } 
    var match = $(this).html().match(phoneRegex); 
    if (match === null || match.length === 0) { 
     return false; 
    } 
    return true; 
}); 
phoneNums.html(function() { 
    var newhtml = $(this).html().replace(phoneRegex, function(match) { 
     var phonenumber = match.replace(/ /g, "").replace(/-/g, "").replace(/\(/g, "").replace(/\)/g, ""); 
     var link = '<a href="tel:' + phonenumber + '">' + match + '</a>'; 
     return link; 
    }); 
    return newhtml; 
}); 

所以,基本上我尋找一切在體內尋找(不包括錨標籤),每個標籤。我匹配正則表達式並將值存儲在'phoneNums'變量中。 從那裏我刪除所有的空格,破折號和括號,因此號碼將正確格式爲tel屬性。 所以許多像這樣的:(123)456-7890將格式化像這樣:<a href="tel:1234567890">(123) 456-7890</a>

我做的是,如果這些數字都在頁面上嵌套的標籤,我得到的結果多看到的問題倍。 (如果你在鏈接上做一個console.log,就可以看到它,就在它返回之前。)結果是正確的,但是想知道這是否合理。

有沒有更有效的方法來做到這一點?提前致謝!

+0

這就是爲什麼我在我的答案中使用了'XPath';它可以讓你直接找到文本節點,並處理它們,而無需使用正則表達式來解析/修改HTML。您希望儘可能低的工作量,而不是在'.html'上運行查找和替換(這意味着您正在替換大量可能包含'script'標籤,元素屬性等內容的東西)。 – ShadowRanger

+0

@ShadowRanger - 你有沒有一個例子,我可以重新插入格式化的數字返回到DOM中,一旦找到了這種格式?我是整個XPath解決方案的新手。 – Tim

+0

一旦找到節點,XPath實際上不會涉及。我已經擴展了我的原始答案,包括顯示如何執行替換的代碼;應該可以看看並刪除這個問題。 – ShadowRanger

回答

1

像以前一樣(這是從原來的問題複製粘貼後,我更新它,包括執行元素替換代碼),Don't use regular expressions to parse HTML。使用HTML/DOM解析器來獲取文本節點(瀏覽器可以爲您過濾它,刪除錨標籤,所有文本太短以至於不包含電話號碼),您可以直接查看文本。

例如,使用XPath(這是一個有點難看,但對於處理文本支持直接節點的方式大多數其他DOM方法沒有):

// This query finds all text nodes with at least 12 non-whitespace characters 
// who are not direct children of an anchor tag 
// Letting XPath apply basic filters dramatically reduces the number of elements 
// you need to process (there are tons of short and/or pure whitespace text nodes 
// in most DOMs) 
var xpr = document.evaluate('descendant-or-self::text()[not(parent::A) and string-length(normalize-space(self::text())) >= 12]', 
          document.body, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); 
for (var i=0, len=xpr.snapshotLength; i < len; ++i) { 
    var txt = xpr.snapshotItem(i); 
    // Splits with grouping to preserve the text split on 
    var numbers = txt.data.split(/([(]?\d{3}[)]?[(\s)?.-]\d{3}[\s.-]\d{4})/); 
    // split will return at least three items on a hit, prefix, split match, and suffix 
    if (numbers.length >= 3) { 
     var parent = txt.parentNode; // Save parent before replacing child 
     // Replace contents of parent with text before first number 
     parent.textContent = numbers[0]; 

     // Now explicitly create pairs of anchors and following text nodes 
     for (var i = 1; i < numbers.length; i += 2) { 
      // Operate in pairs; odd index is phone number, even is 
      // text following that phone number 
      var anc = document.createElement('a'); 
      anc.href = 'tel:' + numbers[i].replace(/\D+/g, ''); 
      anc.textContent = numbers[i]; 
      parent.appendChild(anc); 
      parent.appendChild(document.createTextNode(numbers[i+1])); 
     } 
     parent.normalize(); // Normalize whitespace after rebuilding 
    } 
} 

爲了記錄在案,基本過濾器在大多數頁面上幫助lot。例如,現在,在我看到的這個頁面上(不同的用戶,瀏覽器,瀏覽器擴展和腳本等)沒有過濾器,查詢'descendant-or-self::text()'的快照將有1794個項目。忽略由定位標記父節點構成的文本,'descendant-or-self::text()[not(parent::A)]'將其降至1538,並且驗證非空白內容至少有12個字符長度的完整查詢將其降至87個項目。將正則表達式應用到87個項目是改變性能的,性能明智的,並且您已經消除了使用不適合的工具解析HTML的需要。