// ==UserScript==
// @name 图片列表全屏
// @namespace http://tampermonkey.net/
// @version 0.1.3
// @description 网页图片全屏查看,缩放, 切换
// @author liangxin
// @match *://*/*
// @grant GM_registerMenuCommand
// ==/UserScript==
(function() {
// 图片数组
let imgs;
// 图片浏览父容器
let div;
// 当前操作的 图片元素;
let img;
// 当前操作图片索引
let imgIndex = 0;
// 图片大小
let imgSize;
// 图片宽高比
let imgAspectRatio;
// 图片缩放比例
let imgZoomNum = 1;
// 初始缩放比例, 即第一次展示时的缩放比例
let initImgZoomNum = 1;
function loading() {
if(!loadImg()){
return;
}
initMenu();
initEvent();
// initDiv();
}
let loadImg=()=>{
// 获取图片元素集合
imgs = Array.from(document.getElementsByTagName("img"));
// 过滤小图片
let min=150
imgs = imgs.filter(img => img.width > min && img.height > min);
if (imgs.length <1) {
return false;
}
return true;
}
/**
* 加载菜单
*/
let initMenu = () => {
// 右键菜单
let msg = `Ctrl + I : 开启图片全屏列表 Shift + I : 重新加载图片全屏列表
ESC : 退出图片全屏
鼠标滚轮: 缩放图片 鼠标拖动: 移动图片
`;
const w = unsafeWindow || window;
GM_registerMenuCommand('图片浏览快捷键表', alert.bind(w, msg));
}
/**
* 加载父级容器
*/
let initDiv = () => {
// 每次初始索引
imgIndex = 0;
// 如果已有 容器, 则不再重新创建
if (div) {
div.style.width = window.innerWidth + "px";
div.style.height = window.innerHeight + "px";
div.style.display = "block";
return;
}
div = document.createElement("div");
div.style.width = window.innerWidth + "px";
div.style.height = window.innerHeight + "px";
div.style.backgroundColor = "#000";
div.style.position = "fixed";
div.style.top = 0;
div.style.left = 0;
div.style.zIndex = 9999999;
div.style.display = "block";
div.style.overflow = "hidden";
document.body.append(div);
}
/**
* 显示图片
*/
let imgShow = () => {
let showImg = new Image();
showImg.src = imgs[imgIndex].src;
showImg.title = imgs[imgIndex].title === "" ? "第" + (imgIndex + 1) +"/"+imgs.length+ "张" : imgs[imgIndex].title;
showImg.style.position = "absolute";
div.innerHTML = showImg.outerHTML;
img = div.querySelector("img");
// 判断是否已加载成功
if (img.complete) {
imgSize = {
"width": img.width,
"height": img.height
};
imgAspectRatio = getImgAspectRatio(img);
imgZoomNum = 1;
setImgSize();
} else {
// 如果还未加载成功, 则将 设置大小的操作,写在 图片的 onload 函数中
img.onload = function() {
imgSize = {
"width": img.width,
"height": img.height
};
imgAspectRatio = getImgAspectRatio(img);
imgZoomNum = 1;
setImgSize();
}
}
imgZoomEvent();
imgMove();
}
/**
* 初始 图片大小
*/
function setImgSize() {
let newHeight = window.innerHeight;
let newWidth = 0;
do {
newHeight = newHeight - 5;
newWidth = calculateWidth(newHeight, imgAspectRatio);
} while (newWidth > window.innerWidth);
imgZoom(newHeight / imgSize.height);
initImgZoomNum = imgZoomNum;
}
/**
* 图片左右居中
*/
function imgCenter() {
img.style.marginLeft = (window.innerWidth - img.width) / 2 + "px";
}
/**
* 根据比例关系, 已知 高度, 计算 宽度
*/
function calculateWidth(heigth, aspectRatio) {
return parseInt(heigth * aspectRatio.width / aspectRatio.height);
}
/**
* 根据比例关系, 已知 宽度, 计算 高度
*/
function calculateHeight(width, aspectRatio) {
return parseInt(width * aspectRatio.height / aspectRatio.width);
}
/**
* 缩放图片
*/
let imgZoom = (zoom = 1) => {
let newHeight = float_calculator.mul(imgSize.height, zoom);
img.height = parseInt(newHeight);
img.width = calculateWidth(newHeight, imgAspectRatio);
imgCenter();
showMsg.show(parseInt(float_calculator.mul(zoom, 100)) + "%");
imgZoomNum = zoom;
return false;
}
/**
* 鼠标滚轮缩放事件
*/
let imgZoomEvent = () => {
// 缩放基数
let zoom = 0.1;
let zoomEvent = (zoomOpt) => {
if (initImgZoomNum == imgZoomNum) {
let i = (imgZoomNum * 100) % (zoom * 100);
if (i > 0) {
imgZoomNum = (imgZoomNum * 100 + zoom * 100 - i) / 100
}
}
if (zoomOpt) {
// 向上 放大
imgZoomNum = float_calculator.add(imgZoomNum, zoom)
} else {
// 向下 // 缩小
imgZoomNum = float_calculator.add(imgZoomNum, -zoom)
}
if (imgZoomNum < zoom) {
imgZoomNum=zoom;
return;
}
imgZoom(imgZoomNum);
return false;
}
div.onmousewheel = function(e) {
zoomEvent(e.wheelDelta > 0);
};
// 双击回复为 初始缩放比例
div.addEventListener("dblclick", e => {
imgZoom(initImgZoomNum);
})
}
let imgMove = () => {
let imgTop = 0;
let imgLeft = 0;
let mx = 0;
let my = 0;
img.ondragstart = e => {
mx = e.screenX;
my = e.screenY;
if (img.style.top === "") {
imgTop = 0;
imgLeft = 0;
}
}
img.ondrag = e => {
if (e.screenY == 0 && e.screenX == 0) {
return
}
imgTop = imgTop + e.screenY - my;
imgLeft = imgLeft + e.screenX - mx;
mx = e.screenX;
my = e.screenY;
img.style.top = imgTop + "px";
img.style.left = imgLeft + "px";
}
}
/**
* 初始化事件
*/
let initEvent = () => {
window.addEventListener("keydown", e => {
// <- 和 -> 切换图片
if (e.keyCode == 37 || e.keyCode == 39) {
if (e.keyCode == 39) {
imgIndex++;
imgIndex = imgIndex >= imgs.length ? 0 : imgIndex;
} else {
imgIndex--;
imgIndex = imgIndex < 0 ? imgs.length - 1 : imgIndex;
}
imgShow();
}
// ESC 键 隐藏
if (e.keyCode == 27) {
div.style.display = "none";
}
// Ctrl + I 开启浏览
if (e.ctrlKey && e.keyCode == 73) {
initDiv();
imgShow();
}
// Shift + I 重新加载图片
if(e.shiftKey & e.keyCode == 73){
loadImg();
initDiv();
imgShow();
}
})
}
window.addEventListener("load",e=>{
loading();
});
//---------------------------- 工具方法 ------------------
/**
* 消息对象
*/
window.showMsg = {
flag: false,
msgSpan: null,
msgTimeOut: null,
show: function(m, s = 2) {
// 如果 已有消息, 则清除, 并清除之前的延迟计时器
if (this.msgSpan) {
this.msgSpan.remove();
clearTimeout(this.msgTimeOut);
}
this.msgSpan = document.createElement("span");
document.body.append(this.msgSpan);
this.msgSpan.innerHTML = m;
this.msgSpan.style.position = "fixed";
this.msgSpan.style.top = "50px"
this.msgSpan.style.left = "49vw";
this.msgSpan.style.backgroundColor = "#000";
this.msgSpan.style.color = "#fff";
this.msgSpan.style.lineHeight = "30px";
this.msgSpan.style.padding = "0 10px";
this.msgSpan.style.opacity = 0.5;
this.msgSpan.style.zIndex = 2147483647;
this.msgSpan.style.display = "block";
this.msgSpan.style.borderRadius = "10px";
this.msgSpan.style.minWidth = "105px";
this.msgSpan.style.textAlign = "center";
// 延迟删除
this.msgTimeOut = setTimeout(() => {
this.msgSpan.remove();
this.flag = false;
}, s * 1000);
}
}
/**
* 获取图片比例 [宽,高]
*/
function getImgAspectRatio(img) {
let i = img.width / img.height;
console.log("比例: " + img.width + " / " + img.height + " = " + i);
return i > 1 ? {
"width": i,
"height": 1
} : {
"width": 1,
"height": 1 / i
};
}
// 自定义高精度浮点数运算
// 对象格式写法
var float_calculator = {
/**
* 1.记录两个运算数小数点后的位数
* 2.将其转化为整数类型进行运算
* 3.移动小数点的位置
**/
add: function(arg1, arg2) {
var r1, r2, m;
try {
//取小数位长度
r1 = arg1.toString().split(".")[1].length;
r2 = arg2.toString().split(".")[1].length;
} catch (e) {
r1 = 0;
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2)); //计算因子
return (arg1 * m + arg2 * m) / m;
},
minus: function(arg1, arg2) {
return this.add(arg1, -arg2);
},
mul: function(arg1, arg2) {
var r1, r2, m;
try {
//取小数位长度
r1 = arg1.toString().split(".")[1].length;
r2 = arg2.toString().split(".")[1].length;
} catch (e) {
r1 = 0;
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2)); //计算因子
return (arg1 * m) * (arg2 * m) / (m * m);
}
};
})();