最近跟百度廣告打了會交道,若是您正在或者即將和百度廣告打交道,那太好了,本文必定會讓您不枉此行。百度廣告,即百度聯盟廣告,在 這裏 進行註冊後,通過 一些配置,即可以生成一段 js,將該 js 插入到 HTML 頁面中,便能出現百度的廣告。javascript
恩,百度廣告您必定見過,隨便截張圖:html
隨便給一段生成的百度廣告代碼感覺下:java
<script type="text/javascript"> var cpro_id = "u2557752"; </script> <script src="http://cpro.baidustatic.com/cpro/ui/cm.js" type="text/javascript"></script>
以上代碼如何可以展示廣告?最重要的緣由是 cm.js 中將廣告內容用 document.write 方法輸出。git
通常場景,也是最簡單的使用,須要廣告出如今哪一個位置,就把該段 js 放在哪一個位置。很是容易理解,由於廣告的生成用的是 document.write,因此執行到該段 js 時,會同步輸出廣告內容。github
使用方式大概這樣:緩存
<html> <body> <!-- DOM 元素 --> <script type="text/javascript"> var cpro_id = "u2557752"; </script> <script src="http://cpro.baidustatic.com/cpro/ui/cm.js" type="text/javascript"></script> <!-- DOM 元素 --> <script type="text/javascript"> var cpro_id = "u2557760"; </script> <script src="http://cpro.baidustatic.com/cpro/ui/cm.js" type="text/javascript"></script> <!-- DOM 元素 --> </body> </html>
以上的通常場景下,若是有性能瓶頸,很顯然是由於百度廣告圖片加載的問題,js 的加載並非首要緣由(js還有緩存)。出於好奇,仍是首先對 cm.js 試試可否異步加載。併發
<body> <script> function scriptDomElement(u) { var s = document.createElement('script') , h = document.getElementsByTagName('head')[0]; s.src = u; s.async = true; h && h.insertBefore(s, h.firstChild); } var cpro_id = "u2557760"; scriptDomElement("http://cpro.baidustatic.com/cpro/ui/cm.js"); </script> </body>
控制檯有個 warning,可是廣告也出來了:app
以前咱們說到百度廣告是用 document.write 同步輸出到頁面上的,很顯然,並不能異步加載有 document.write 方法的 js 文件(究竟是重寫頁面呢,仍是重寫頁面呢),因此會有該 warning。可是,爲何會有廣告呢?異步
這是由於百度有一套 "備胎" 方案。當 cm.js 內部判斷該 js 是被異步加載的時候,隨即執行這套備胎方案:async
createBackupWrapper: function(t) { try { var e = document.getElementsByTagName("script") , i = e[e.length - 1]; if (i) { var n = i.parentNode; if (n) { var o = document.createElement("div"); return o.id = t.containerId, n.insertBefore(o, i), !0 } } } catch (r) {} return !1 },
代碼寫的很清楚,就是把廣告元素插入到最後一個 script 標籤的前面。爲了保證廣告所在的位置便是咱們但願的位置,很顯然最後一個 script 元素必須就是 cm.js。
這樣理解的話,咱們彷佛能夠得出這樣一個結論:當廣告位置在頁面最底部時(而且只有一處廣告位),咱們能夠對這段廣告的 js 進行如上的異步加載。可是 js 異步加載了,廣告所須要的圖片還得請求,標籤頁上的小圈圈仍是一直在轉,因此我以爲對 cm.js 文件進行異步加載,並無什麼卵用。
事實上,cm.js 內部就提供了異步加載的方案 -> 廣告位異步加載代碼
<div id="PAGE_AD_1"></div> HELLO WORLD <div id="PAGE_AD_2"></div> <!--廣告位代碼放在頁面最後--> <script type="text/javascript" src="http://cbjs.baidu.com/js/m.js"></script> <!--異步加載開始--> <script type="text/javascript"> BAIDU_CLB_fillSlotAsync('u2557752','PAGE_AD_1');//12345是廣告編號,PAGE_AD_1是您要投放廣告的位置 BAIDU_CLB_fillSlotAsync('u2557760','PAGE_AD_2'); </script> <!--異步加載結束 -->
這樣不只 cm.js 只需加載一次,並且調用也方便多了。(好吧,以前的異步測試算是無用功)
單純的異步加載對於頁面總體的加載速度彷佛並無什麼提高(廣告圖片略多),是否能夠用 setTimeout 進行延遲的異步加載?ok,咱們對以前的代碼進行一點改造,用一個定時器延遲執行 scriptDomElement 函數。
<body> <script> function scriptDomElement(u) { var s = document.createElement('script') , h = document.getElementsByTagName('head')[0]; s.src = u; s.async = true; h && h.insertBefore(s, h.firstChild); } var cpro_id = "u2557760"; setTimeout(function() { scriptDomElement("http://cpro.baidustatic.com/cpro/ui/cm.js"); }, 2000); </script> </body>
前面說了,異步加載僅適用於 cm.js 做爲最後一個 script 標籤的狀況,也就是廣告在頁面最底部的狀況。what's more,通過這樣的處理,大多數狀況下是能夠看到廣告的,可是小部分狀況廣告沒法展示,究其緣由,樓主以爲是 cm.js 內部對該 js 是不是異步加載沒法精確判斷。
因此樓主以爲,若是能夠接受某些機器下沒法展示百度廣告,這個方法仍是能夠一試的。
恩,其實咱們徹底能夠用 cm.js 提供的 BAIDU_CLB_fillSlotAsync 方法和 setTimeout 進行配合。
(強勢插入硬廣一枚:樓主 Github 求關注~)
很是簡單,寫個簡單的 DEMO(重寫完後記得改回來,DEMO 中沒改回來):
<body> Hello world! <div id='ad'> </div> <script> // 重寫 document.write document.write = function( text ){ document.getElementById('ad').innerHTML = text; }; function scriptDomElement(u) { var s = document.createElement('script') , h = document.getElementsByTagName('head')[0]; s.src = u; s.async = true; h && h.insertBefore(s, h.firstChild); } var cpro_id = "u2557760"; scriptDomElement("http://cpro.baidustatic.com/cpro/ui/cm.js"); </script> </body>
如何能作到延遲加載?咱們能夠採用 BigRender 的思路,將廣告代碼放在 textarea 標籤中,當 textarea 出如今視野中時,取出廣告代碼執行。參考雨夜帶刀的代碼:
<div> <textarea style="display:none"> <script type="text/javascript" src="http://gg.5173.com/adpolestar/5173/ ;ap=2EBE5681_1BA3_4663_FA3F_E73D2B83FBDC;ct=js;pu=5173;/?"></script> </textarea> </div> 延遲加載script並重寫document.write,下面是代碼實現: var loadScript = function( elem ){ var url = elem.value.match( /src="([\s\S]*?)"/i )[1], parent = elem.parentNode, // 緩存原生的document.write docWrite = document.write, // 建立一個新script來加載 script = document.createElement( 'script' ), head = document.head || document.getElementsByTagName( 'head' )[0] || document.documentElement; // 重寫document.write document.write = function( text ){ parent.innerHTML = text; }; script.type = 'text/javascript'; script.src = url; script.onerror = script.onload = script.onreadystatechange = function( e ){ e = e || window.event; if( !script.readyState || /loaded|complete/.test(script.readyState) || e === 'error' ){ // 恢復原生的document.write document.write = docWrite; head.removeChild( script ); // 卸載事件和斷開DOM的引用 // 儘可能避免內存泄漏 head = parent = elem = script = script.onerror = script.onload = script.onreadystatechange = null; } } // 加載script head.insertBefore( script, head.firstChild ); };
若是有多個廣告片斷,由於 document.write 是全局方法,因此不得不維護個腳本隊列,一個一個執行,又退化成了同步執行腳本。若是異步併發執行的話,極可能廣告的位置會出現對調現象。固然,有些百度廣告並不會十分在意順序,好比下面要說的新聞信息流。
其實我以爲若是要延遲加載某些特定位置的廣告區域,能夠用 BAIDU_CLB_fillSlotAsync 方法,將該方法所在的代碼塞入 textarea 中。 有一點須要注意的是,BAIDU_CLB_fillSlotAsync 必須指定廣告位置的 DOM id。
將百度廣告插入到新聞信息流,這是很廣泛的作法。
好比網易:
那麼如何將廣告插入到新聞信息流當中去呢?咱們仍是能夠用重寫 document.write 的方法。
舉個簡單的例子:
<body> <ul> <li class="news"></li> <li class="news"></li> <li class="news"></li> <li class="bdad"></li> <li class="news"></li> </ul> <script> // 重寫 document.write document.write = function( text ){ document.getElementsByClassName('bdad')[0].innerHTML = text; }; function scriptDomElement(u) { var s = document.createElement('script') , h = document.getElementsByTagName('head')[0]; s.src = u; s.async = true; h && h.insertBefore(s, h.firstChild); } var cpro_id = "u2557760"; scriptDomElement("http://cpro.baidustatic.com/cpro/ui/cm.js"); </script> </body>
重寫一個系統的方法畢竟不是什麼好事,網易、 頭條新聞 採用的都是另外一種方法,套一個 iframe,很是巧妙。
index.htm 文件:
<body> <ul> <li class="news"></li> <li class="news"></li> <li class="news"></li> <li class="news"><iframe src="ad.htm"></iframe></li> <li class="news"></li> </ul> </body>
ad.htm 文件:
<script type="text/javascript"> var cpro_id = "u2557760"; </script> <script src="http://cpro.baidustatic.com/cpro/ui/cm.js"></script>
固然,一些樣式方面的細節還須要本身去把握,這裏只提供一個思路。
對於百度廣告在不一樣環境中的投放,有不一樣的處理方式。主要有三種:
利用 cm.js 中的 BAIDU_CLB_fillSlotAsync 方法(該方法須要廣告位置的 DOM id)
重寫 document.write
新建 iframe,在該 iframe 中同步輸出廣告代碼
仁者見仁智者見智吧。
Read more: