(2016/9/6)プロフィールページ(/about)のエラー修正(可読版参照)
(2016/12/4)記事の上下に表示可能な改訂版があります
はてなブログの読み込みが重い理由のひとつは、ソーシャルボタンがiframe
で読み込まれているからです。以下5回の記事で、hatena, facebook, twitter, google+ をダイレクトリンクに変更し、シェアカウントを素の Javascript 非同期で読み込む方法を試してきましたが、何とか完成しましたので公開します。
- シェアボタン(ソーシャルボタン)を改良して読み込みを速くする
- Facebookシェアボタン/シェアカウントを素の Javascript で取得する
- Facebookシェアダイアログでシェアする/Facebook SDK for JavaScript
- ツイート数付きツイートボタンをオリジナルでつくる(素の javascript 付き)
- Google+のシェアボタンをカウント付きで自作する
01ボタンの見た目
ボタンの見た目は、 CSSで自由に変更できます。デフォルトは次の通りです。
スマートフォンの場合
現在のところ、レスポンシブデザインのテーマを使用していない場合はスマートフォンでは表示されません。はてなブログのスマートフォン向けテーマではトップ画面は記事一覧でソーシャルボタンは表示されませんすので、記事表示の場合に自作のものを表示するよう、記事の記事下やフッタに入れて、CSS をどうするかを考えればいけるとは思います。
レスポンシブデザインのテーマを使用している場合は次のように表示されます。
02挿入コード(Javascript 圧縮版)
必須項目
Facebook と Twitter のシェアカウントを取得するために次の2つの登録が必要です。
- Facebook アプリID
「【はてなブログ高速化3】Facebookシェアダイアログでシェアする/Facebook SDK for JavaScript – IMUZA.com」を参考にアプリID を取得し、以下のコードの26行目「Facebook のアプリID」を自分のアプリID に変更してください。 - count.jsoon への登録
「widgetoon.js & count.jsoon | digitiminimi」でサイトを登録してください。
上記完了後、下のコードをカスタマイズ > フッタに入れてください。
<ul id="tmplShareButtons"> <li class="hatena"> <a class="hatena-bookmark-button" data-hatena-bookmark-layout="simple"> <span class="hatena-bookmark-count share-count"></span> <i class="blogicon-bookmark lg"></i><span class="share-label">ブックマーク</span></a> </li> <li class="facebook"> <a href="javascript:void(0)" class="facebook-share-button"> <span class="facebook-count share-count"></span> <i class="blogicon-facebook lg"></i><span class="share-label">シェア</span></a> </li> <li class="twitter"> <a class="twitter-button"> <span class="twitter-count share-count"></span> <i class="blogicon-twitter lg"></i><span class="share-label">ツイート</span></a> </li> <li class="googleplus"> <a class="googleplus-button"> <span class="googleplus-count share-count"></span> <i class="blogicon-plus lg"></i> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" width="36px" height="22px" viewBox="-14 -8 72 44" class="u7 uzlpSb"><path d="M32 8.2h-3v4h-4V15h4v4h3v-4h4v-2.9h-4V8.2zm6-2V8h3v15h3V4l-6 2.2z"></path><path d="M11.4 11.3v4.5h6c-.4 2.6-2.7 4.5-6 4.5-3.6 0-6.6-3.1-6.6-6.7s2.9-6.7 6.6-6.7c1.7 0 3.1.5 4.3 1.7l3.2-3.2c-2-1.8-4.5-2.9-7.5-2.9C5.3 2.5.3 7.5.3 13.6s5 11.1 11.1 11.1c6.5 0 10.7-4.6 10.7-10.9 0-.8-.1-1.7-.2-2.5H11.4z"></path></svg></a> </li> </ul> <script> window.fbAsyncInit = function() { FB.init({appId:'Facebook のアプリID',xfbml:true,version:'v2.7'}); }; (function(d, s, id){ var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) {return;} js = d.createElement(s); js.id = id; js.src = "//connect.facebook.net/ja_JP/sdk.js"; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk')); </script> <script> !function(){var e=function(e,t){var n="https://clients6.google.com/rpc?key=AIzaSyCKSbrvQasunBoV16zDH9R33D88CeLr9gQ",o=new XMLHttpRequest;o.onreadystatechange=function(){if(4===o.readyState&&200===o.status){var e=JSON.parse(o.responseText);t(e.result.metadata.globalCounts.count)}else t(0)},o.open("post",n,!0),o.setRequestHeader("Content-Type","application/json"),o.send(JSON.stringify(e))},t=function(e,t,n){var o=document.createElement("script");o.type="text/javascript";var a="ExternalCallback_"+t;window[a]=function(e){o.parentNode&&o.parentNode.removeChild(o);try{delete window[a]}catch(t){window[a]=null}n(e)},o.src=e+"&callback="+a,document.body.appendChild(o)},n=function(e,t){var n=new XMLHttpRequest;n.open("get",e,!0),n.onreadystatechange=function(){if(4===n.readyState&&200===n.status){var e=JSON.parse(n.responseText),o="share"in e?e.share:{},a="share_count"in o?o.share_count:0;t(a)}else t(0)},n.send(null)},o=0,a=document.getElementById("tmplShareButtons");a.removeAttribute("id");var s=document.getElementsByClassName("hentry");Array.prototype.forEach.call(s,function(s){var r=s.getElementsByClassName("bookmark")[0],i=r.getAttribute("href"),l=r.innerHTML,c=a.cloneNode(!0),u=c.getElementsByClassName("hatena-bookmark-button")[0];u.setAttribute("href","http://b.hatena.ne.jp/entry/"+i),u.setAttribute("data-hatena-bookmark-title",l);var p="http://api.b.st-hatena.com/entry.count?url="+encodeURIComponent(i);t(p,o,function(e){u.getElementsByClassName("hatena-bookmark-count")[0].innerHTML=e}),o++;var m=c.getElementsByClassName("facebook-share-button")[0];m.addEventListener("click",function(){FB.ui({method:"share",href:i},function(){})});var p="https://graph.facebook.com/?id="+encodeURIComponent(i);n(p,function(e){m.getElementsByClassName("facebook-count")[0].innerHTML=e});var d=c.getElementsByClassName("twitter-button")[0];d.setAttribute("href","http://twitter.com/intent/tweet?url="+encodeURIComponent(i)+"&text="+l);var p="http://jsoon.digitiminimi.com/twitter/count.json?url="+encodeURIComponent(i);t(p,o,function(e){d.getElementsByClassName("twitter-count")[0].innerHTML=e.count}),o++;var h=c.getElementsByClassName("googleplus-button")[0],g=500,y=500,f=(window.screen.width-g)/2,b=(window.screen.height-y)/2;h.setAttribute("href","javascript:void(window.open('https://plus.google.com/share?url="+encodeURIComponent(i)+"', '_blank', 'width="+g+",height="+y+",left="+f+",top="+b+"'))");var v={method:"pos.plusones.get",id:"p",params:{nolog:!0,id:i,source:"widget",userId:"@viewer",groupId:"@self"},jsonrpc:"2.0",key:"p",apiVersion:"v1"};e(v,function(e){h.getElementsByClassName("googleplus-count")[0].innerHTML=e}),s.getElementsByClassName("social-buttons")[0].appendChild(c)}),a.parentNode.removeChild(a)}(); </script>
03
以下のコードをカスタマイズ > デザインCSSに入れてください。
.social-buttons ul { padding: 0; margin: 0; } .social-buttons ul li { display: inline-block; margin: 0; padding: 0; list-style-type: none; width: 15%; border-radius: 3px; vertical-align: text-top; } .social-buttons ul li a { width: 100%; display: inline-block; color: #fff; text-decoration: none; position: relative; text-align: center; } .social-buttons ul li a span.share-count { display: inline-block; width: 100%; color: #000; background: #fff; line-height: 2rem; border-radius: 3px 3px 0 0; opacity: 1; -webkit-transition: opacity 0.4s, transform 0.4s; transition: opacity 0.4s, transform 0.4s; } .social-buttons ul li a i { padding: 0 5px; } .social-buttons ul li a i.blogicon-plus { color: #dd5144; } .social-buttons ul li a svg { position: absolute; left: 0; right: 0; margin: 0 auto; } .social-buttons ul li a svg path { fill: #fff; } .social-buttons ul li a span.share-label { font-size: .7rem; } .social-buttons ul li a:hover span.share-count { opacity: 0.8; } .social-buttons ul li.hatena { background: #00a4de; border: solid 1px #00a4de; } .social-buttons ul li.facebook { background: #3e59a5; border: solid 1px #3e59a5; } .social-buttons ul li.twitter { background: #1b95e0; border: solid 1px #1b95e0; } .social-buttons ul li.googleplus { background: #dd5144; border: solid 1px #dd5144; } @media (max-width: 767px) { .social-buttons ul li a span.share-label { display: none; } }
これで完了です。
このサイトの場合はいろいろ DOM 操作をやっていますのでもともとやや重めですが、このソーシャルボタンに変更したら、8秒くらいかかっていた読み込みが4秒くらいになりました。
以下は、Javascript の圧縮前のソースです。
Javascript 可読版
/*--------------------------------------------------------------------------* * * はてなブログ用ソーシャルボタン * * Copyright (c) 2016 IMUZA.com http://www.imuza.com * Released under the MIT license * http://opensource.org/licenses/mit-license.php * *--------------------------------------------------------------------------*/ (function(){ var getGoogleShareCount = function(obj, callback) { var url = 'https://clients6.google.com/rpc?key=AIzaSyCKSbrvQasunBoV16zDH9R33D88CeLr9gQ'; var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { var obj = JSON.parse(xhr.responseText); callback(obj.result.metadata.globalCounts.count); } else { callback(0); } }; xhr.open('post', url, true); xhr.setRequestHeader( 'Content-Type', 'application/json' ); xhr.send(JSON.stringify(obj)); }; var getCountByJSONP = function(url, count, callback) { var script = document.createElement('script'); script.type = 'text/javascript'; var callbackName = 'ExternalCallback_' + count; window[callbackName] = function (data){ if(script.parentNode){ script.parentNode.removeChild(script); } try{ delete window[callbackName]; }catch(e){ window[callbackName] = null; } callback(data); }; script.src = url + '&callback=' + callbackName; document.body.appendChild(script); }; var getFbShareCount = function(url, callback) { var xhr = new XMLHttpRequest(); xhr.open('get', url, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { var obj1 = JSON.parse(xhr.responseText), obj2 = 'share' in obj1 ? obj1.share : {}, count = 'share_count' in obj2 ? obj2.share_count : 0; callback(count); } else { callback(0); } }; xhr.send(null); }; var count = 0; var tmpl = document.getElementById('tmplShareButtons'); tmpl.removeAttribute('id'); //(2016/9/6)修正 // about ページで、記事ではない article を取得をしないようにクラス名に変更 // var articles = document.getElementsByTagName('article'); var articles = document.getElementsByClassName('hentry'); Array.prototype.forEach.call(articles, function(article) { var bm = article.getElementsByClassName('bookmark')[0]; var permalink = bm.getAttribute('href'); var title = bm.innerHTML; var clone = tmpl.cloneNode(true); var hatenaButton = clone.getElementsByClassName('hatena-bookmark-button')[0]; hatenaButton.setAttribute('href', 'http://b.hatena.ne.jp/entry/' + permalink); hatenaButton.setAttribute('data-hatena-bookmark-title', title); var url = 'http://api.b.st-hatena.com/entry.count?url=' + encodeURIComponent(permalink); getCountByJSONP(url, count, function(data) { hatenaButton.getElementsByClassName('hatena-bookmark-count')[0].innerHTML = data; }); count++; var facebookButton = clone.getElementsByClassName('facebook-share-button')[0]; facebookButton.addEventListener('click', function() { FB.ui({ method: 'share', href: permalink, }, function(response){}); }); var url = 'https://graph.facebook.com/?id=' + encodeURIComponent(permalink); getFbShareCount(url ,function(data) { facebookButton.getElementsByClassName('facebook-count')[0].innerHTML = data; }); var twitterButton = clone.getElementsByClassName('twitter-button')[0]; twitterButton.setAttribute('href', 'http://twitter.com/intent/tweet?url=' + encodeURIComponent(permalink) + '&text=' + title); var url = 'http://jsoon.digitiminimi.com/twitter/count.json?url=' + encodeURIComponent(permalink); getCountByJSONP(url, count, function(data) { twitterButton.getElementsByClassName('twitter-count')[0].innerHTML = data.count; }); count++; var googleButton = clone.getElementsByClassName('googleplus-button')[0]; var w = 500, h = 500, x = (window.screen.width - w ) / 2, y = (window.screen.height - h) / 2; googleButton.setAttribute('href', "javascript:void(window.open('https://plus.google.com/share?url=" + encodeURIComponent(permalink) + "', '_blank', 'width=" + w + ",height=" + h + ",left=" + x + ",top=" + y + "'))"); var obj = { "method":"pos.plusones.get", "id":"p", "params":{ "nolog":true, "id":permalink, "source":"widget", "userId":"@viewer", "groupId":"@self" }, "jsonrpc":"2.0", "key":"p", "apiVersion":"v1" }; getGoogleShareCount(obj, function(data) { googleButton.getElementsByClassName('googleplus-count')[0].innerHTML = data; }); article.getElementsByClassName('social-buttons')[0].appendChild(clone); }); tmpl.parentNode.removeChild(tmpl); })();