Chrome自定义插件—小温之家的私人订制

Rolling in the Deep – Adele–:– / 03:48
(*+﹏+*)

Chrome已经位居现代浏览器榜首,其中一个重要原因就是插件丰富,开发一款自己的专属插件也比较容易入手。做一个跳转小温之家前后台和书签管理的页面。记录下大致的操作吧。

【wenqyChromeExt】这是当前扩展插件根目录,运行tree -f命令查看目录结构。

chrome_ext_tree

Mainfest.json

看下Mainfest.json核心入口文件

  1. {
  2.   “update_url”“https://wenqy.com/crx”,
  3.   // 描述
  4.   “name”“小温之家-行走在猿类世界”,
  5.   “description”“小温之家-行走在猿类世界,记下你的世界,做自己最真实的友人!”,
  6.   “version”“1.0.0”,
  7.   “permissions”: [
  8.     “*://*/*”,
  9.     “activeTab”,
  10.     “tabs”,
  11.     “contextMenus”// 右键菜单
  12.     “webRequest”,
  13.     “webRequestBlocking”,
  14.     “storage”
  15.   ],
  16.   // 图标
  17.   “icons”:
  18.   {
  19.     “16”“imgs/map/icon16.png”,
  20.     “48”“imgs/map/icon48.png”,
  21.     “128”“imgs/map/icon128.png”
  22.   },
  23.   “background”: {
  24.     “page”“background.html”
  25.   },
  26.   // 默认语言
  27.   “default_locale”“zh_CN”,
  28.   // 引入脚本
  29.   “content_scripts”: [
  30.     {
  31.       // 匹配时使用脚本、样式
  32.       “matches”: [“https://*/*”“http://*/*”],
  33.       “exclude_matches”: [],
  34.       “css” : [“css/wenqy.css”],
  35.       “js”: [“js/wenqy.js”],
  36.       // 运行 文档加载结束
  37.       “run_at”“document_end”
  38.     }
  39.   ],
  40.   “browser_action”: {
  41.     “default_title”“点击进入小温之家”,
  42.     “default_icon”“imgs/map/icon48.png”,
  43.     “default_popup”“popup.html”
  44.   },
  45.   // 选项页
  46.   “options_page”“options.html”,
  47.   // 默认策略限制
  48.   // “content_security_policy”: “script-src ‘self’; object-src ‘self'”,
  49.   //”web_accessible_resources”: [
  50.   //  “imgs/map/*.png”
  51.   //],
  52.   “manifest_version”: 2
  53. }

popup.html

popup.html 点击chrome浏览器插件图标后的弹出层,与用户交互界面。

  1. <body id=“yc-baidu-translate”>
  2.         <div class=“container”>
  3.             <div class=“header”>
  4.                 <div class=“jumbotron”>
  5.                     <button class=“” id=“wenqy-page”><img title=“前往小温之家” src=“imgs/map/arrow_down_nomal.png” />登录小温之家</button>
  6.                 </div>
  7.             </div>
  8.             <div class=“main”>
  9.                 <div class=“select-l translate-from” data-click=“no-click”>
  10.                     <div class=“selected-l”>
  11.                         <span class=“selected-l-text” value=“”><img title=“前往小温之家” src=“imgs/map/right-arrow.png” />站点书签</span>
  12.                     </div>
  13.                 </div>
  14.             </div>
  15.             <div class=“row”>
  16.                 <select id=“select_sites” style=“width:100%”>
  17.                     <option value=“”>请搜索书签</option>
  18.                 </select>
  19.             </div>
  20.             <div class=“yc-baidu-translate-footer”>
  21.                 <div class=“icon_options”>
  22.                     <a href=“javascript:;” id=“icon_options_home” class=“icon_options_item”>
  23.                         <img title=“前往小温之家” id=“icon_options_home_img” src=“imgs/map/home.png”>
  24.                     </a>
  25.                     <a href=“javascript:;” id=“icon_options_setting” class=“icon_options_item”>
  26.                         <img title=“插件设置” id=“icon_options_setting_img” src=“imgs/map/setup.png”>
  27.                     </a>
  28.                     <a href=“javascript:;” id=“icon_options_help” class=“icon_options_item”>
  29.                         <img title=“帮助和反馈” id=“icon_options_help_img” src=“imgs/map/help.png”>
  30.                     </a>
  31.                 </div>
  32.             </div>
  33.         </div>
  34. </body>

popup.js

popup.js popup.html引用的外部js文件,行为操作层

  1. var haitao_sites = {
  2.     ‘www.wenqy.com’: ‘小温之家’,
  3.     ‘www.baidu.com’: ‘百度’
  4. };
  5. function parseURL(url) {
  6.     var domain;
  7.     if (url.indexOf(“/”) >= 0) {
  8.         domain = url.substr(0, url.indexOf(“/”));
  9.     } else {
  10.         domain = url;
  11.     }
  12.     var domainName, port;
  13.     var idx = domain.indexOf(“:”);
  14.     if (idx > 0) {
  15.         domainName = domain.substr(0, idx);
  16.         port = domain.substr(idx + 1);
  17.     } else {
  18.         domainName = domain;
  19.     }
  20.     var shortName = domainName.substr(url.indexOf(“.”) + 1);
  21.     if (shortName.indexOf(“.”) < 0) {
  22.         shortName = domainName;
  23.     }
  24.     var tmp2 = url.substr(url.indexOf(“/”) + 1);
  25.     var webContext = tmp2.substr(0, tmp2.indexOf(‘/’));
  26.     var uri = tmp2.substr(tmp2.indexOf(‘/’));
  27.     return {
  28.         domainName: domainName,
  29.         shortName: shortName,
  30.         port: port,
  31.         webContext: webContext,
  32.         uri: uri
  33.     }
  34. }
  35. function restore_options() {
  36.     chrome.storage.local.get(nullfunction(items) {
  37.         // console.log(‘items’, items);
  38.         if (items[‘custom_sites’] && items[‘custom_sites’].length > 0) {
  39.             var selectText = “”;
  40.             for (var i in items[‘custom_sites’]) {
  41.                 var input_obj = parseURL(items[‘custom_sites’][i]);
  42.                 var name = haitao_sites[input_obj.domainName] ? haitao_sites[input_obj.domainName] : input_obj.shortName;
  43.                 selectText += ‘<option value=’+items[‘custom_sites’][i]+’>’+name+'<option>’;
  44.             }
  45.             $(“#select_sites”).empty().append(selectText);
  46.         }
  47.     })
  48. }
  49. restore_options();
  50. $(document).ready(function() {
  51.     $(“#select_sites”).select2();
  52.     $(“#select_sites”).change(function(event) {
  53.         window.open(“http://” +$(“#select_sites option:selected”).val());
  54.     });
  55.     $(“#icon_options_setting”).click(function() {
  56.         window.open(‘options.html’);
  57.     });
  58.     $(“#icon_options_setting”).hover(function() {
  59.         $(“#icon_options_setting_img”).attr(‘src’, ‘imgs/map/setuphover.png’);
  60.     }, function() {
  61.         $(“#icon_options_setting_img”).attr(‘src’, ‘imgs/map/setup.png’);
  62.     });
  63.     $(‘#wenqy-page’).click(function() {
  64.         window.open(‘http://wenqy.com/wp-login.php’);
  65.     });
  66.     $(“#icon_options_home”).click(function() {
  67.         window.open(‘http://wenqy.com/’);
  68.     });
  69.     $(‘#icon_options_home’).hover(function () {
  70.         $(‘#icon_options_home_img’).attr(‘src’, ‘imgs/map/home_hover.png’);
  71.     }, function () {
  72.         $(‘#icon_options_home_img’).attr(‘src’, ‘imgs/map/home.png’);
  73.     });
  74.     $(‘#icon_options_help’).click(function () {
  75.         window.open(‘http://wenqy.com’);
  76.     });
  77.     $(‘#icon_options_help’).hover(function () {
  78.         $(‘#icon_options_help_img’).attr(‘src’, ‘imgs/map/help_hover.png’);
  79.     }, function () {
  80.         $(‘#icon_options_help_img’).attr(‘src’, ‘imgs/map/help.png’);
  81.     });
  82. });

options.html

options.html 扩展插件的设置界面

  1. <body>
  2. <h1 style=“text-align:center;”>小温之家| 自定义设置</h1>
  3. <h2>喜欢的颜色:</h2>
  4. <h2 style=“text-align:center;” id=“status”></h2>
  5. <br>
  6. </br>
  7. <div class=“autoTranslate”>
  8.     <div class=“autoTranslate-switch”>
  9.         <h2>喜欢的颜色:</h2>
  10.         <table id=“custom-head” class=“table”>
  11.             <tr>
  12.                 <td id=“thead-tip”>
  13.                     <select id=“color”>
  14.                      <option value=“”></option>
  15.                      <option value=“red”>red</option>
  16.                      <option value=“green”>green</option>
  17.                      <option value=“blue”>blue</option>
  18.                      <option value=“yellow”>yellow</option>
  19.                      <option value=“white”>white</option>
  20.                     </select>
  21.                 </td>
  22.                 <td>
  23.                     <a href=“#” id=“saveOptions”>保存</a>
  24.                 </td>
  25.             </tr>
  26.         </table>
  27.         <h2>书签管理</h2>
  28.         <table id=“custom-head” class=“table”>
  29.             <tr>
  30.                 <td id=“thead-tip”>
  31.                     书签
  32.                 </td>
  33.                 <td>
  34.                     <a href=“#” id=“add”>+添加站点</a>
  35.                 </td>
  36.             </tr>
  37.         </table>
  38.     </div>
  39.     <div class=“table-container”>
  40.         <table id=“custom” class=“table-custom”>
  41.         </table>
  42.     </div>
  43. </div>
  44. </body>

wenqy.js

wenqy.js options.html 设置界面引用的外部行为操作层

  1. function save_options() {
  2.     custom_sites = [];
  3.     $(‘.site’).each(function() {
  4.         if ($(this).text() !=  && custom_sites.indexOf($(this).text()) == -1) {
  5.             custom_sites.push($(this).text());
  6.         }
  7.     })
  8.     chrome.storage.local.set({
  9.         ‘custom_sites’: custom_sites,
  10.     }, function() {
  11.         location.reload();
  12.     });
  13. }
  14. function restore_options() {
  15.     chrome.storage.local.get(nullfunction(items) {
  16.         // console.log(‘items’, items);
  17.         if (items[‘custom_sites’] && items[‘custom_sites’].length > 0) {
  18.             $(“#custom”).addClass(“table-custom-padding”);
  19.             for (var i in items[‘custom_sites’]) {
  20.                 var input_obj = parseURL(items[‘custom_sites’][i]);
  21.                 var name = haitao_sites[input_obj.domainName] ? haitao_sites[input_obj.domainName] : input_obj.shortName;
  22.                 $(“#custom”).append(‘\
  23.           <tr>\
  24.             <td class=“site”><a href=“http://’ + items[‘custom_sites’][i] + ‘” target=“_blank”>’ + items[‘custom_sites’][i] + ‘</a></td>\
  25.             <td class=“site-name”>’ + name + ‘</td>\
  26.             <td class=“site-remove”><a href=“#” class=“remove”>移除</a></td>\
  27.           </tr>’);
  28.                 $(“.remove”).click(function() {
  29.                     $(this).parent().parent().remove();
  30.                     save_options();
  31.                 });
  32.             }
  33.         } else {
  34.             $(“#custom”).append(‘\
  35.         <tr id=“blank”>\
  36.           <td class=“custom-nothing”>无</td>\
  37.         </tr>’);
  38.         }
  39.     })
  40. }
  41. restore_options();
  42. /**
  43. * @author wenqy.com
  44. *
  45. *
  46. */
  47. $(function(){
  48.     // Saves options to localStorage.
  49.     function save_options_test() {
  50.       var select = $(“#color option:selected”).val();
  51.       localStorage[“favorite_color”] = select;
  52.       // Update status to let user know options were saved.
  53.       $(“#status”).text(“选项已保存”);
  54.       console.log(“select->”+select);
  55.       $(“body”).css(“background-color”,select);
  56.       setTimeout(function() {
  57.         $(“#status”).text(“”);
  58.       }, 750);
  59.     }
  60.     // Restores select box state to saved value from localStorage.
  61.     function restore_options_test() {
  62.       var favorite = localStorage[“favorite_color”];
  63.       if (!favorite) {
  64.         return;
  65.       }
  66.       $(“#color”).val(favorite);
  67.       $(“body”).css(“background-color”,favorite);
  68.     }
  69.     restore_options_test();
  70.     $(“#saveOptions”).click(save_options_test);
  71.     var url_expression = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi;
  72.     var url_regex = new RegExp(url_expression);
  73.     var c_id = 0;
  74.     $(“#add”).on(‘click’, function() {
  75.         if ($(‘.add-tr’).length <= 0 ) {
  76.             if (!$(“#custom”).hasClass(“table-custom-padding”)) {
  77.                 $(“#custom”).addClass(“table-custom-padding”);
  78.             }
  79.             $(“#custom”).before(‘\
  80.         <table id=“‘ + c_id + ‘” class=“add-table”>\
  81.           <tr class=“add-tr”>\
  82.             <td class=“td-add-input”>\
  83.               <input type=“text” class=“form-control site” placeholder=“请输入网站地址,如: www.wenqy.com” required>\
  84.             </td>\
  85.             <td class=“td-add-button”>\
  86.               <button type=“button” class=“switch-open add-confirm” style=“width:79px;float: none;margin-left:16px;”>添加</button>\
  87.             </td>\
  88.             <td class=“td-add-remove-button”>\
  89.               <button type=“button” class=“switch-close add-remove” style=“width:79px;float: none;”>取消</button>\
  90.             </td>\
  91.           </tr>\
  92.           <tr><td class=“fail”></td></tr>\
  93.         </table>’);
  94.             $(“.add-remove”).on(‘click’, function() {
  95.                 $(this).parent().parent().parent().parent().remove();
  96.                 if ($(“.site”).length <= 0) {
  97.                     $(“#custom”).removeClass(“table-custom-padding”);
  98.                 }
  99.             });
  100.             $(“#” + c_id + ” .add-confirm”).on(‘click’, function() {
  101.                 var input_valid = true;
  102.                 var url_input = $(this).parent().prev().children(‘input’).val().replace(‘。’, ‘.’).replace(‘http://’, ”).replace(‘https://’, ”);
  103.                 if (url_input == “”) {
  104.                     $(‘.fail’).text(‘输入内容不能为空’);
  105.                     $(‘.fail’).show();
  106.                     input_valid = false;
  107.                 } else if (!url_input.match(url_regex)) {
  108.                     $(‘.fail’).text(‘无效网址’);
  109.                     $(‘.fail’).show();
  110.                     input_valid = false;
  111.                 }
  112.                 if (input_valid) {
  113.                     var input_obj = parseURL(url_input);
  114.                     var name = haitao_sites[input_obj.domainName] ? haitao_sites[input_obj.domainName] : input_obj.shortName;
  115.                     $(“#custom #blank”).remove();
  116.                     $(“#custom”).prepend(‘\
  117.             <tr>\
  118.               <td class=“site”><a href=“http://’ + url_input + ‘” target=“_blank”>’ + url_input + ‘</a></td>\
  119.               <td class=“site-name”>’ + name + ‘</td>\
  120.               <td class=“site-remove”><a href=“#” class=“remove”>移除</a></td>\
  121.             </tr>’);
  122.                     $(this).parent().parent().remove();
  123.                     $(“.remove”).on(‘click’, function() {
  124.                         $(this).parent().parent().remove();
  125.                         save_options();
  126.                     });
  127.                     save_options();
  128.                 }
  129.             });
  130.             c_id += 1;
  131.         }
  132.     });
  133. });

直接将百度翻译的插件进行改造,阉割了。。。

该开始编写样例的时候报错,扩展页面动态绑定JS事件提示错误

Refused to execute inline event handler because it violates the following Content Security Policy directive: "script-src 'self' blob: filesystem: chrome-extension-resource:". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.

JavaScript事件都用外部引入的方式就可以了

Chrome插件安装

Chrome浏览器中输入URL:chrome://extensions,进行【扩展程序】管理页面,当然也可以在【设置】里找,选择【加载已解压的扩展程序】,选中扩展插件的目录即可。当然也可以把扩展插件的目录打包,打包成.crx后缀结尾的扩展插件。

chrome扩展插件引入

安装扩展后,如图所示:

chrome_wenqy

点击【登录小温之家】,跳转到小温之家的后台登录界面;点击主页图标,跳转到小温之家首页,点击帮助图标也是;点击设置图标,跳转到站点管理页面。

chrome_options

添加站点后,就可以搜索选择啦,选择站点后,跳转到站点页面。

chrome_bookmark

 Console效果

姑且在加下console的打印效果
  1. var str = “WENQY”;
  2. var mode = “stereo”// 平面
  3. if (mode === ‘planar’) {
  4.    var character = character_planar;
  5.  }
  6.  if (mode === ‘stereo’) { // 立体
  7.    var character = character_stereo;
  8.  }
  9.  var result = ‘\n’;
  10.  var strArr = str.split(‘\n’);
  11.  for (var k = 0; k < strArr.length; k++) {
  12.    for (var j = 0; j < 7; j++) {
  13.      for (var i = 0, length = strArr[k].length; i < length; i++) {
  14.        result = result + character[strArr[k][i]][j];
  15.      }
  16.      result = result + ‘\n’;
  17.    }
  18.  }
  19.  console.group(“Info”);
  20.  console.log(result);
  21. console.log(“welcome to http://wenqy.com”);
  22. console.log(”   …..∵ ∴★.∴∵∴ ╭ ╯╭ ╯╭ ╯╭ ╯∴∵∴∵∴ “);
  23. console.log(“.☆.∵∴∵.∴∵∴▍▍ ▍▍ ▍▍ ▍▍☆ ★∵∴ “);
  24. console.log(“▍.∴∵∴∵.∴▅███████████☆ ★∵ “);
  25. console.log(“◥█▅▅▅▅███▅█▅█▅█▅█▅█▅███◤ “);
  26. console.log(“. ◥███████████████████◤ “);
  27. console.log(“....◥████████████████■◤”);
  28. console.log(“.. .. .. .. .. .. .. .”);
  29. console.log(“.. .. .. .. . “);
  30. console.log(“…友谊的巨轮向你驶来”);
  31. console.groupEnd();
  32. console.group(“Reference”);
  33. console.log(“https://github.com/starkwang”);
  34. console.log(“http://www.fuhaodq.com/fuhaotuan/1215.html”);
  35. console.log(“http://www.cnblogs.com/tinyTea/p/6072618.html”);
  36. console.log(“http://www.cnblogs.com/zhongxinWang/p/4121111.html”);
  37. console.groupEnd();
  38. );

效果图:

wenqychrome

第一版自定义插件算是入门啦,当然存在痛点了,插件卸载后,重新安装并没有保存原先添加的站点记录,也没有为这些站点定义名称字段方便记忆和管理,话说还会再改吗?姑且记之吧。

参考

http://open.chrome.360.cn/extension_dev/overview.html
http://open.chrome.360.cn/extension_dev/manifest.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注

19 + 20 = ?