MiniblogImgPop - 微博浮图

微博浮图控件,鼠标移过小图弹出浮动大图的脚本

目前为 2016-12-12 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name MiniblogImgPop - 微博浮图
  3. // @namespace http://userscripts.org/users/83994
  4. // @icon https://addons.cdn.mozilla.net/img/uploads/addon_icons/337/337281-64.png?modified=1361080128
  5. // @description 微博浮图控件,鼠标移过小图弹出浮动大图的脚本
  6. // @version 3.4.1
  7. // @include http://*qing.weibo.com/*
  8. // @include http://*weibo.com/*
  9. // @include http://*t.163.com/*
  10. // @include http://*t.sohu.com/*
  11. // @include http://*t.qq.com/*
  12. // @include http://*t.ifeng.com/*
  13. // @include http://*t.titan24.com/*
  14. // @include http://*t.people.com.cn/*
  15. // @include http://*tianya.cn/*
  16. // @include http://*diandian.com/*
  17. // @include http://*.digu.com/*
  18. // @include http://i.taobao.com/*
  19. // @include http://*t.cntv.cn*
  20. // @include http://*tieba.baidu.com/f*
  21. // @include http://*tieba.baidu.com/i*
  22. // @include http://*xueqiu.com/*
  23. // @include https://*douban.com/*
  24. // @include https://*work.alibaba-inc.com/*
  25. // @grant none
  26. // ==/UserScript==
  27.  
  28. // @author afc163
  29. // @weibo http://weibo.com/afc163
  30. // @code https://github.com/afc163/MiniblogImgPop
  31. // @blog http://pianyou.me
  32. // @date 2010.8.12
  33.  
  34. (function() {
  35.  
  36. // 各微博站点的feed配置
  37. var MIPConfig = {
  38. 'qing.weibo.com':{
  39. feedSelector:'.imgZoomIn',
  40. sFrag :'',
  41. bFrag :''
  42. },
  43. 'q.weibo.com':{
  44. feedSelector:'.bigcursor',
  45. sFrag :'thumbnail',
  46. bFrag :'large'
  47. },
  48. 'weibo.com':{
  49. feedSelector:'.bigcursor, .feed_img, .media_list img',
  50. sFrag :['thumb180', 'thumb150', 'orj480', 'orj360', 'thumbnail', 'square'],
  51. bFrag :['mw690', 'mw690', 'mw690', 'mw690', 'bmiddle', 'bmiddle']
  52. },
  53. 't.sohu.com':{
  54. feedSelector:'.pic',
  55. sFrag :['/f_','_1.jpg'],
  56. bFrag :['/m_','_0.jpg']
  57. },
  58. 't.163.com':{
  59. feedSelector:'.tweet-preview-pic',
  60. sFrag :['w=140&h=140', '&gif=1'],
  61. bFrag :['w=440', '&gif=0']
  62. },
  63. 't.qq.com':{
  64. feedSelector:'.pic img:not(.large)',
  65. sFrag :['/160', '/120'],
  66. bFrag :['/460', '/460']
  67. },
  68. 't.titan24.com':{
  69. feedSelector:'.imgBig',
  70. sFrag :'_thumbnail',
  71. bFrag :'_middle'
  72. },
  73. 't.people.com.cn':{
  74. feedSelector:'.list_s_pic img',
  75. sFrag:'/s_',
  76. bFrag:'/b_'
  77. },
  78. 't.ifeng.com':{
  79. feedSelector:'.zoom_in_image img',
  80. sFrag :'/128x160_',
  81. bFrag :'/520x0_'
  82. },
  83. 'www.tianya.cn':{
  84. feedSelector:'.pic-zoomin',
  85. bigSrc :'_middlepic',
  86. sFrag :'small',
  87. bFrag :'middle'
  88. },
  89. 'diandian.com':{
  90. feedSelector:'.feed-img',
  91. bigSrc :'imgsrc'
  92. },
  93. 'digu.com':{
  94. feedSelector:'.picture',
  95. sFrag :'_100x75',
  96. bFrag :'_640x480'
  97. },
  98. 't.cntv.cn':{
  99. feedSelector:'.zoom-move',
  100. sFrag :'/thumbnail',
  101. bFrag :'/bmiddle'
  102. },
  103. 'i.taobao.com':{
  104. feedSelector:'.thumb-image',
  105. sFrag :'_160x160',
  106. bFrag :'_450x10000'
  107. },
  108. 'tieba.baidu.com/f':{
  109. feedSelector:'.threadlist_media li',
  110. bigSrc: 'bpic'
  111. },
  112. 'tieba.baidu.com/i':{
  113. feedSelector:'.feat_img',
  114. bigSrc: 'data-field'
  115. },
  116. 'xueqiu.com':{
  117. feedSelector:'.expandable > img',
  118. sFrag :'!thumb',
  119. bFrag :'!custom'
  120. },
  121. 'douban.com':{
  122. feedSelector:'img',
  123. sFrag :'median',
  124. bFrag :'raw'
  125. },
  126. 'work.alibaba-inc.com':{
  127. feedSelector:'.uxcore-nw-message-wall-item-album-thumb li',
  128. sFrag :['240x240', '120x120'],
  129. bFrag :['620x10000', '620x10000']
  130. }
  131. };
  132.  
  133. // 居中显示的图片对象
  134. var PopImg = {
  135.  
  136. show: function(e) {
  137. this.allowMove = false;
  138. // fix firefox 22 beta 1
  139. this._hideTimer && window.clearTimeout(this._hideTimer);
  140.  
  141. var that = this;
  142. var smallImg = MiniblogImgPop.smallImg;
  143. var src = this.getBigImgsrc(smallImg);
  144. this.img.src = src;
  145. this.imgWidth = 500;
  146.  
  147. imgReady(src, function() {
  148. that.imgWidth = this.width;
  149. that.layoutImg(e);
  150.  
  151. that.img.style.opacity = 1;
  152. that.img.style.visibility = 'visible';
  153. that.img.style.marginTop = '-15px';
  154. Mask.show(e);
  155.  
  156. // 换算图片显示高度
  157. // 1. 宽度超过 500 时,高度要等比例压缩
  158. // 2. 加上边框高度
  159. var imgDisplayHeight;
  160. if (this.width > 500) {
  161. imgDisplayHeight = (this.height + 14) * 500 / this.width;
  162. } else {
  163. imgDisplayHeight = this.height + 14;
  164. }
  165.  
  166. if (window.innerHeight > imgDisplayHeight) {
  167. var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
  168. that.img.style.top = (scrollTop + (window.innerHeight - imgDisplayHeight)/2 + 15) + 'px';
  169. that.allowMove = false;
  170. } else {
  171. that.allowMove = true;
  172. that.move(e);
  173. }
  174. });
  175. },
  176.  
  177. // 设置大图的宽度与位置
  178. layoutImg: function(e) {
  179. var pos = offset(MiniblogImgPop.smallImg);
  180. var left = pos.x + pos.width + 30;
  181. var width = Math.min(this.imgWidth, 500);
  182. // 如果小图右边放不下
  183. if (left + width > window.innerWidth) {
  184. left = pos.x - width - 30;
  185. // 如果左边也放不下
  186. if (left < 0) {
  187. // 根据鼠标位置,选择空间大的一侧放置
  188. if (e.pageX > window.innerWidth / 2) {
  189. // 放置在左边
  190. width = Math.min(width, e.pageX - 30);
  191. left = 0;
  192. } else {
  193. // 放置在右边
  194. width = Math.min(width, window.innerWidth - e.pageX - 30);
  195. left = window.innerWidth - width;
  196. }
  197. }
  198. }
  199. this.img.style.width = width + 'px';
  200. this.img.style.left = left + 'px';
  201. },
  202.  
  203. hide: function() {
  204. var that = this;
  205. this.img.style.opacity = 0;
  206. this.img.style.marginTop = '0px';
  207.  
  208. Mask.hide();
  209. this.shown = false;
  210.  
  211. this._hideTimer = window.setTimeout(function() {
  212. that.img.src = '';
  213. that.img.style.visibility = 'hidden';
  214. }, 200);
  215. },
  216.  
  217. init: function() {
  218. var node = document.createElement('img');
  219. node.id = 'miniblogImgPop';
  220. document.body.appendChild(node);
  221. this.img = node;
  222.  
  223. Mask.init();
  224. },
  225.  
  226. move: function(e) {
  227. this.layoutImg(e); // 重新计算大图宽度与位置
  228. if (!this.allowMove) {
  229. return;
  230. }
  231. Mask.move(e);
  232. // 根据 Mask 的位置算出大图的位置
  233. var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
  234. this.img.style.top = (scrollTop - Mask.top * Mask.scale) + 14 + 'px';
  235. },
  236.  
  237. getBigImgsrc: function(obj) {
  238. var tempimgs, tempimg, imgsrc, i, l,
  239. sname = MiniblogImgPop.sitename,
  240. config = MiniblogImgPop.config;
  241. if (obj.tagName === 'IMG' || obj.tagName === 'img') {
  242. tempimg = obj;
  243. } else {
  244. tempimgs = obj.getElementsByTagName('IMG');
  245. if (!tempimgs || tempimgs.length === 0) {
  246. throw 'cant found the img node.';
  247. }
  248. else{
  249. tempimg = tempimgs[0];
  250. }
  251. }
  252.  
  253. //针对使用额外属性保存大图地址的网站
  254. if (config.bigSrc) {
  255. return tempimg.getAttribute(config.bigSrc) || 'javascript:;';
  256. }
  257.  
  258. //一般处理
  259. imgsrc = tempimg.getAttribute('src');
  260. //console.info(imgsrc);
  261. imgsrc = decodeURIComponent(imgsrc);
  262. if (typeof config.sFrag === 'object') {
  263. for(i=0, l=config.sFrag.length; i<l; i++) {
  264. imgsrc = imgsrc.replace(config.sFrag[i], config.bFrag[i]);
  265. }
  266. }
  267. else{
  268. imgsrc = imgsrc.replace(config.sFrag, config.bFrag);
  269. }
  270. return imgsrc;
  271. }
  272.  
  273. };
  274.  
  275. // 图片上遮罩的阴影
  276. var Mask = {
  277. show: function(e) {
  278. var smallImg = MiniblogImgPop.smallImg,
  279. bigImg = PopImg.img;
  280.  
  281. this.sOffset = offset(smallImg);
  282.  
  283. // 表示放大的倍数
  284. this.scale = (bigImg.height + 14) * 1.0 / this.sOffset.height;
  285.  
  286. // 计算出bar的高度
  287. if (window.innerHeight < bigImg.height) {
  288. this.height = parseInt(window.innerHeight/this.scale, 10);
  289. } else {
  290. this.height = this.sOffset.height;
  291. }
  292.  
  293. // 计算bar的Top值可以允许的范围
  294. this.range = this.sOffset.height - this.height;
  295.  
  296. // 计算 mask 的位置
  297. this.nodes[0].style.left = this.sOffset.x + 'px';
  298. this.nodes[0].style.width = this.sOffset.width + 'px';
  299. this.nodes[0].style.top = this.sOffset.y + 'px';
  300. this.nodes[1].style.left = this.sOffset.x + 'px';
  301. this.nodes[1].style.width = this.sOffset.width + 'px';
  302. this.nodes[1].style.bottom = (window.innerHeight - this.sOffset.y - this.sOffset.height) + 'px';
  303. this.move(e);
  304.  
  305. this.nodes[0].style.opacity = 0.7;
  306. this.nodes[1].style.opacity = 0.7;
  307. },
  308. hide: function() {
  309. this.nodes[0].style.opacity = 0;
  310. this.nodes[1].style.opacity = 0;
  311. this.nodes[0].style.height = 0;
  312. this.nodes[1].style.height = 0;
  313. },
  314. move: function(e) {
  315. // 计算鼠标相对于元素的位置
  316. var x = e.pageX - this.sOffset.x,
  317. y = e.pageY - this.sOffset.y;
  318.  
  319. // 计算bar的top值
  320. var top = y - this.height/2;
  321. top = top < 0 ? 0 : top;
  322. top = top > this.range ? this.range : top;
  323. this.top = top;
  324.  
  325. this.nodes[0].style.height = top + 'px';
  326. this.nodes[1].style.height = (this.sOffset.height - top - this.height) + 'px';
  327. },
  328. init: function() {
  329. var node1 = document.createElement('div');
  330. node1.className = 'miniblogImgPop-mask';
  331. document.body.appendChild(node1);
  332. var node2 = document.createElement('div');
  333. node2.className = 'miniblogImgPop-mask';
  334. document.body.appendChild(node2);
  335. this.nodes = [node1, node2];
  336. }
  337. };
  338.  
  339. var MiniblogImgPop = {
  340.  
  341. preloadImg: function() {
  342. var that = this;
  343. window.setTimeout(function() {
  344. var nodes = $(that.config.feedSelector);
  345. for (var i=0; i<nodes.length; i++) {
  346. var preloadImg = new Image();
  347. preloadImg.src = PopImg.getBigImgsrc(nodes[i]);
  348. }
  349. }, 1500);
  350. },
  351.  
  352. prepare: function() {
  353. this.sitename = this._getSiteName();
  354. this.config = MIPConfig[this.sitename];
  355. },
  356.  
  357. addImgsEventListener: function() {
  358. var that = this;
  359. delegate(document.body, 'mouseover', function(e, node) {
  360. that.smallImg = node;
  361. node.style.opacity = 0.84;
  362. PopImg.show(e);
  363. }, this.config.feedSelector);
  364. delegate(document.body, 'mouseout', function(e, node) {
  365. node.style.opacity = '';
  366. PopImg.hide();
  367. }, this.config.feedSelector);
  368. delegate(document.body, 'mousemove', function(e) {
  369. PopImg.move(e);
  370. }, this.config.feedSelector);
  371. },
  372.  
  373. // 获得当前站点名
  374. _getSiteName: function() {
  375. var i, each;
  376. for(each in MIPConfig) {
  377. if (location.href.indexOf(each) != -1) {
  378. return each;
  379. }
  380. }
  381. return '';
  382. },
  383.  
  384. init: function() {
  385. // 初始化两个节点
  386. PopImg.init();
  387. // 准备必要的数据
  388. this.prepare();
  389. // 绑定imgs hover事件
  390. this.addImgsEventListener();
  391. // 预加载大图
  392. this.preloadImg();
  393. }
  394.  
  395. };
  396.  
  397. // 启动
  398. MiniblogImgPop.init();
  399.  
  400.  
  401. // Helpers
  402. // ---
  403.  
  404. function $(selector) {
  405. return document.querySelectorAll(selector);
  406. }
  407.  
  408. function offset(source) {
  409. var pt = {
  410. x:0,
  411. y:0,
  412. width:source.offsetWidth,
  413. height:source.offsetHeight
  414. };
  415. do {
  416. pt.x += source.offsetLeft;
  417. pt.y += source.offsetTop;
  418. source = source.offsetParent;
  419. } while (source);
  420. return pt;
  421. }
  422.  
  423. function delegate(el, eventType, handler, selector) {
  424. el = el || document;
  425. el.addEventListener(eventType, function(e) {
  426. var node = getHandlerNode(e, selector, el);
  427. node && handler.call(el, e, node);
  428. }, false);
  429.  
  430. function getHandlerNode(e, selector, el) {
  431. //返回我们handler需要的参数
  432. var nodes;
  433. el = el || document;
  434. if (e && e.target && selector) {
  435. nodes = el.querySelectorAll(selector);
  436. for(i=0; i<nodes.length; i++) {
  437. if (e.target == nodes[i] || isInDomChain(e.target, nodes[i], el)) {
  438. return nodes[i];
  439. }
  440. }
  441. return false;
  442. }
  443. }
  444.  
  445. function isInDomChain(target, parent, ancestor, maxDepth) {
  446. ancestor = ancestor || null;
  447. maxDepth = maxDepth || 100;
  448.  
  449. if (target == ancestor) {
  450. return false;
  451. }
  452. if (target == parent) {
  453. return true;
  454. }
  455. var i = 0;//防止过多嵌套
  456. while (target != ancestor && target !== null && (i++ < maxDepth)) {
  457. target = target.parentNode;
  458. if (target == parent) {
  459. return true;
  460. }
  461. }
  462. return false;
  463. }
  464. }
  465.  
  466. /**
  467. * 图片头数据加载就绪事件 - 更快获取图片尺寸
  468. * @version 2011.05.27
  469. * @author TangBin
  470. * @see http://www.planeart.cn/?p=1121
  471. * @param {String} 图片路径
  472. * @param {Function} 尺寸就绪
  473. * @param {Function} 加载完毕 (可选)
  474. * @param {Function} 加载错误 (可选)
  475. * @example imgReady('http://www.google.com.hk/intl/zh-CN/images/logo_cn.png', function () {
  476. alert('size ready: width=' + this.width + '; height=' + this.height);
  477. });
  478. */
  479. var imgReady = (function () {
  480. var list = [], intervalId = null,
  481.  
  482. // 用来执行队列
  483. tick = function () {
  484. var i = 0;
  485. for (; i < list.length; i++) {
  486. list[i].end ? list.splice(i--, 1) : list[i]();
  487. }
  488. !list.length && stop();
  489. },
  490.  
  491. // 停止所有定时器队列
  492. stop = function () {
  493. window.clearInterval(intervalId);
  494. intervalId = null;
  495. };
  496.  
  497. return function (url, ready, load, error) {
  498. var onready, width, height, newWidth, newHeight,
  499. img = new Image();
  500.  
  501. img.src = url;
  502.  
  503. // 如果图片被缓存,则直接返回缓存数据
  504. if (img.complete) {
  505. ready.call(img);
  506. load && load.call(img);
  507. return;
  508. }
  509.  
  510. width = img.width;
  511. height = img.height;
  512.  
  513. // 加载错误后的事件
  514. img.onerror = function () {
  515. error && error.call(img);
  516. onready.end = true;
  517. img = img.onload = img.onerror = null;
  518. };
  519.  
  520. // 图片尺寸就绪
  521. onready = function () {
  522. newWidth = img.width;
  523. newHeight = img.height;
  524. if (newWidth !== width || newHeight !== height ||
  525. // 如果图片已经在其他地方加载可使用面积检测
  526. newWidth * newHeight > 1024
  527. ) {
  528. ready.call(img);
  529. onready.end = true;
  530. }
  531. };
  532. onready();
  533.  
  534. // 完全加载完毕的事件
  535. img.onload = function () {
  536. // onload在定时器时间差范围内可能比onready快
  537. // 这里进行检查并保证onready优先执行
  538. !onready.end && onready();
  539.  
  540. load && load.call(img);
  541.  
  542. // IE gif动画会循环执行onload,置空onload即可
  543. img = img.onload = img.onerror = null;
  544. };
  545.  
  546. // 加入队列中定期执行
  547. if (!onready.end) {
  548. list.push(onready);
  549. // 无论何时只允许出现一个定时器,减少浏览器性能损耗
  550. if (intervalId === null) intervalId = setInterval(tick, 40);
  551. }
  552. };
  553. })();
  554.  
  555. // GM_addStyle function is not existed in chrome 27
  556. var GM_addStyle = GM_addStyle || function(css) {
  557. var style = document.createElement("style");
  558. style.type = "text/css";
  559. style.appendChild(document.createTextNode(css));
  560. document.getElementsByTagName("head")[0].appendChild(style);
  561. };
  562.  
  563. // 增加自定义样式
  564. GM_addStyle("\
  565. #miniblogImgPop {\
  566. border: 7px solid rgba(255,255,255,1);\
  567. box-shadow: 0 1px 30px rgba(0, 0, 0, 0.75), 0 0 40px rgba(0, 0, 0, 0.25) inset;\
  568. z-index: 12345;\
  569. opacity: 0;\
  570. margin-top: 0;\
  571. position: absolute;\
  572. visibility: hidden;\
  573. max-width: 500px;\
  574. transition: opacity 0.2s ease-out 0s, margin-top 0.2s ease-out 0s;\
  575. }\
  576. ");
  577.  
  578. // 增加自定义样式
  579. GM_addStyle("\
  580. .miniblogImgPop-mask {\
  581. background: rgb(0, 0, 0);\
  582. z-index: 999;\
  583. position: absolute;\
  584. transition: opacity 0.4s ease-out 0;\
  585. }\
  586. ");
  587.  
  588. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址