首页
Search
1
解决visual studio code (vscode)安装时没有选择安装路径问题
314 阅读
2
如何在 Clash for Windows 上配置服务
210 阅读
3
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
150 阅读
4
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
148 阅读
5
uniapp打包app提示通讯录权限问题,如何取消通讯录权限
112 阅读
clash
服务器
javascript
全部
游戏资讯
登录
Search
加速器之家
累计撰写
1,093
篇文章
累计收到
0
条评论
首页
栏目
clash
服务器
javascript
全部
游戏资讯
页面
搜索到
1093
篇与
的结果
2024-08-24
Progressive background-image With Ease
Everyone likes smooth loading. Lately I tried to make the background-image of the menu to load progressively(also to the cover if you view the blog on mobile).If you take a look at how Medium does progressive image loading(or check out this article), you'll notice that they use JavaScript and canvas to blur and store thumbnails. It seems a bit overkill to me. And when you need to do it on a background-image with background-position, things become even more complicated.So I needed to figure out a simpler solution. Here's what I came up with:Blur by defaultAs the article above mentioned:By default, when a browser renders a small image scaled up, it applies a light blur effect to smooth the artefacts of the image. The effect can also be turned off for images like QR codes.But the default blur effect still feels blocky.To make it smoother, I applied blur effect to the thumbnails while generating them, using GraphicsMagick for node:const gm = require('gm') gm(coverPath) .resize(30) // or .resize(null, 30) for portrait .blur(5) .noProfile() .write(thumbnailPath, function (err) { if (err) { console.warn(err) } // ... }) // or to base64 gm(coverPath) .resize(30) // or .resize(null, 30) for portrait .blur(5) .noProfile() .toBuffer(function (err, buffer) { if (err) { console.warn(err) } var base64 = 'data:image/' + ext + ';base64,' + buffer.toString('base64') // ... })This looks acceptable to me. No need for a canvas or blur function. Already felt relieved! :smile:LayersThis method divides a component into four layers: container, thumbnail, mask and content. Container holds the full-size background image. Thumbnail holds the blur thumbnail, as background-image. Mask is a translucent black element, to darken the background. Everything else lives in the content layer. Use z-index to separate the layers.Image onloadWhen full-size image is loaded, hide the thumbnail. You can use this technic(with jQuery/Zepto):var $container = $('.container') // Matchs the "url(...)" var bigBgSrc = $container.css('background-image').match(/url\((.+?)\)/i) if (bigBgSrc) { // Removes quotations bigBgSrc = bigBgSrc[1].replace(/'|"/g, '') $('') .on('load', function () { $container.find('.thumbnail') .addClass('thumbnail--hide') // Hides thumbnail }) .prop('src', bigBgSrc) }A live example:No-jsNo-js support is extremely easy. Just hide the thumbnail.html.no-js .thumbnail { display: none !important; }For my blog I also made a Sass Mixin/Extend with this method.
2024年08月24日
8 阅读
0 评论
0 点赞
2024-08-24
新年新博客!
新博客终于写完啦!给心血们搬了个漂漂亮亮的新家。关于这个博客 :point_left:。
2024年08月24日
6 阅读
0 评论
0 点赞
2024-08-24
获取 DOM 里所有图片(包括背景和iframe)
在写浏览器扩展什么的时候可能会用上。获取 DOM 里的图片主要是在这几个地方里面找: 元素, background-image CSS 属性和 。img如果只想获取 的图片,有两种方式:直接获取所有 img 标签:function getImgs (doc) { return Array.from(doc.getElementsByTagName('img')) .map(img => ({ src: img.currentSrc, // 用 img.src 如果要本来的 src width: img.naturalWidth, height: img.naturalHeight })) } getImgs(document)还可以用 document.images:function getImgs (doc) { return Array.from(doc.images) .map(img => ({ src: img.currentSrc, // img.src if you want the origin width: img.naturalWidth, height: img.naturalHeight })) } getImgs(document)background-image获得背景图片需要查看所有 DOM 节点的 background-image 属性:function getBgImgs (doc) { const srcChecker = /url\(\s*?['"]?\s*?(\S+?)\s*?["']?\s*?\)/i return Array.from( Array.from(doc.querySelectorAll('*')) .reduce((collection, node) => { let prop = window.getComputedStyle(node, null) .getPropertyValue('background-image') // match `url(...)` let match = srcChecker.exec(prop) if (match) { collection.add(match[1]) } return collection }, new Set()) ) } getBgImgs(document)背景图片不能直接得到尺寸信息,如果需要的话要加载一遍。因为搜集的图片很有可能已经在浏览器缓存里,所以加载过程应该很快。function loadImg (src, timeout = 500) { var imgPromise = new Promise((resolve, reject) => { let img = new Image() img.onload = () => { resolve({ src: src, width: img.naturalWidth, height: img.naturalHeight }) } img.onerror = reject img.src = src }) var timer = new Promise((resolve, reject) => { setTimeout(reject, timeout) }) return Promise.race([imgPromise, timer]) } function loadImgAll (imgList, timeout = 500) { return new Promise((resolve, reject) => { Promise.all( imgList .map(src => loadImg(src, timeout)) .map(p => p.catch(e => false)) ).then(results => resolve(results.filter(r => r))) }) } loadImgAll(getBgImgs(document)).then(imgs => console.log(imgs))iframe只需要递归遍历 iframe 的 documentfunction searchIframes (doc) { var imgList = [] doc.querySelectorAll('iframe') .forEach(iframe => { try { iframeDoc = iframe.contentDocument || iframe.contentWindow.document imgList = imgList.concat(getImgs(iframeDoc) || []) // or getBgImgs(iframeDoc) imgList = imgList.concat(searchIframes(iframeDoc) || []) } catch (e) { // 直接忽略错误的 iframe (e.g. cross-origin) } }) return imgList } searchIframes(document)整合一起直接使用就行。function getImgAll (doc) { return new Promise((resolve, reject) => { loadImgAll(Array.from(searchDOM(doc))) .then(resolve, reject) }) function searchDOM (doc) { const srcChecker = /url\(\s*?['"]?\s*?(\S+?)\s*?["']?\s*?\)/i return Array.from(doc.querySelectorAll('*')) .reduce((collection, node) => { // bg src let prop = window.getComputedStyle(node, null) .getPropertyValue('background-image') // match `url(...)` let match = srcChecker.exec(prop) if (match) { collection.add(match[1]) } if (/^img$/i.test(node.tagName)) { // src from img tag collection.add(node.src) } else if (/^frame$/i.test(node.tagName)) { // iframe try { searchDOM(node.contentDocument || node.contentWindow.document) .forEach(img => { if (img) { collection.add(img) } }) } catch (e) {} } return collection }, new Set()) } function loadImg (src, timeout = 500) { var imgPromise = new Promise((resolve, reject) => { let img = new Image() img.onload = () => { resolve({ src: src, width: img.naturalWidth, height: img.naturalHeight }) } img.onerror = reject img.src = src }) var timer = new Promise((resolve, reject) => { setTimeout(reject, timeout) }) return Promise.race([imgPromise, timer]) } function loadImgAll (imgList, timeout = 500) { return new Promise((resolve, reject) => { Promise.all( imgList .map(src => loadImg(src, timeout)) .map(p => p.catch(e => false)) ).then(results => resolve(results.filter(r => r))) }) } } getImgAll(document).then(list => console.log(list))如果是开发 Chrome 插件则不受跨域影响,可以直接使用 probe-image-size,它支持 timeout 参数,就不需要自己写 timer 了。我在写一个 Chrome 扩展时用上了,很方便。
2024年08月24日
7 阅读
0 评论
0 点赞
2024-08-24
Get All Images in DOM (including background)
Quite useful if you are writing an browser extension or something.To get all the images in DOM there are actually three places we are going to look at: element, background-image CSS property and, . Yes, every iframe hides a magical kingdom.imgIf you only want to get images in , two options for you to choose:You can either search the DOM for img tag:function getImgs (doc) { return Array.from(doc.getElementsByTagName('img')) .map(img => ({ src: img.currentSrc, // img.src if you want the origin width: img.naturalWidth, height: img.naturalHeight })) } getImgs(document)Or just use document.images:function getImgs (doc) { return Array.from(doc.images) .map(img => ({ src: img.currentSrc, // img.src if you want the origin width: img.naturalWidth, height: img.naturalHeight })) } getImgs(document)background-imageFor background-image, we need to check every node in DOM:function getBgImgs (doc) { const srcChecker = /url\(\s*?['"]?\s*?(\S+?)\s*?["']?\s*?\)/i return Array.from( Array.from(doc.querySelectorAll('*')) .reduce((collection, node) => { let prop = window.getComputedStyle(node, null) .getPropertyValue('background-image') // match `url(...)` let match = srcChecker.exec(prop) if (match) { collection.add(match[1]) } return collection }, new Set()) ) } getBgImgs(document)We can't simply get the width and height of a background image. If you need them, you have to load it.Since the images you get in DOM are most likely already in the browser cache, the loading process should be fairly quick.function loadImg (src, timeout = 500) { var imgPromise = new Promise((resolve, reject) => { let img = new Image() img.onload = () => { resolve({ src: src, width: img.naturalWidth, height: img.naturalHeight }) } img.onerror = reject img.src = src }) var timer = new Promise((resolve, reject) => { setTimeout(reject, timeout) }) return Promise.race([imgPromise, timer]) } function loadImgAll (imgList, timeout = 500) { return new Promise((resolve, reject) => { Promise.all( imgList .map(src => loadImg(src, timeout)) .map(p => p.catch(e => false)) ).then(results => resolve(results.filter(r => r))) }) } loadImgAll(getBgImgs(document)).then(imgs => console.log(imgs))iframeJust recursively search in all iframesfunction searchIframes (doc) { var imgList = [] doc.querySelectorAll('iframe') .forEach(iframe => { try { iframeDoc = iframe.contentDocument || iframe.contentWindow.document imgList = imgList.concat(getImgs(iframeDoc) || []) // or getBgImgs(iframeDoc) imgList = imgList.concat(searchIframes(iframeDoc) || []) } catch (e) { // simply ignore errors (e.g. cross-origin) } }) return imgList } searchIframes(document)TogetherCan be used out of the box. It was made when I was writing a Chrome Extension.function getImgAll (doc) { return new Promise((resolve, reject) => { loadImgAll(Array.from(searchDOM(doc))) .then(resolve, reject) }) function searchDOM (doc) { const srcChecker = /url\(\s*?['"]?\s*?(\S+?)\s*?["']?\s*?\)/i return Array.from(doc.querySelectorAll('*')) .reduce((collection, node) => { // bg src let prop = window.getComputedStyle(node, null) .getPropertyValue('background-image') // match `url(...)` let match = srcChecker.exec(prop) if (match) { collection.add(match[1]) } if (/^img$/i.test(node.tagName)) { // src from img tag collection.add(node.src) } else if (/^frame$/i.test(node.tagName)) { // iframe try { searchDOM(node.contentDocument || node.contentWindow.document) .forEach(img => { if (img) { collection.add(img) } }) } catch (e) {} } return collection }, new Set()) } function loadImg (src, timeout = 500) { var imgPromise = new Promise((resolve, reject) => { let img = new Image() img.onload = () => { resolve({ src: src, width: img.naturalWidth, height: img.naturalHeight }) } img.onerror = reject img.src = src }) var timer = new Promise((resolve, reject) => { setTimeout(reject, timeout) }) return Promise.race([imgPromise, timer]) } function loadImgAll (imgList, timeout = 500) { return new Promise((resolve, reject) => { Promise.all( imgList .map(src => loadImg(src, timeout)) .map(p => p.catch(e => false)) ).then(results => resolve(results.filter(r => r))) }) } } getImgAll(document).then(list => console.log(list))[EOF]
2024年08月24日
7 阅读
0 评论
0 点赞
2024-08-24
定位与拖动 iframe
定位 iframe在写一个划词翻译扩展 Saladict 时,有一个需求:用户选择一段文本之后,会在鼠标附近显示一些元素。这个初看很简单,监听一个 mouseup 事件,获取 clientX 和 clientY 就行。这也是 Saladict 前几版用的方法。但这个方法有个缺陷:iframe 里的鼠标事件不会传到父窗口上。解决方法也很简单,就难在把它们都联系起来。iframe 里插入脚本在 manifest.json 里,content_scripts 有个选项 all_frames,可以让脚本插入到所有的 frame 里。{ "content_scripts": [ { "js": ["selection.js"], "matches": [""], "all_frames": true } ] }检测点击现在可以检测 iframe 里的点击事件// selection.js document.addEventListener('mouseup', handleMouseUp)上传坐标当点击发生在 iframe 里时,获取的坐标是相对于 iframe 窗口的,所以把这个坐标交给上层,再加上 iframe 本身的坐标,就可以算出点击相对上层的坐标。Chrome 里可以放心使用 postMessage// selection.js function handleMouseUp (evt) { if (window.parent === window) { // 到了顶层 doAwesomeThings(evt.clientX,evt.clientY) } else { // 把坐标传上去 window.parent.postMessage({ msg: 'SALADICT_CLICK', mouseX: evt.clientX, mouseY: evt.clientY }, '*') } }计算偏移上层怎么知道是哪个 iframe 传来坐标?很简单,message 事件里携带了 iframe 的 window,对比一下就可以。// selection.js window.addEventListener('message', evt => { if (evt.data.msg !== 'SALADICT_CLICK') { return } let iframe = Array.from(document.querySelectorAll('iframe')) .filter(f => f.contentWindow === evt.source) [0] if (!iframe) { return } // 计算偏移 let pos = iframe.getBoundingClientRect() let mouseX = evt.data.mouseX + pos.left let mouseY = evt.data.mouseY + pos.top if (window.parent === window) { // 顶层 doAwesomeThings(mouseX, mouseY) } else { // 继续上传 window.parent.postMessage({ msg: 'SALADICT_CLICK', mouseX, mouseY }, '*') } })拖动 iframeSaladict 另外一个需求就是拖动一个 iframe 查词面板。实现拖动的常识实现拖动的一种常用方式就是检测 mousedown, mousemove 和 mouseup。分别对应开始、拖动、结束。然后计算偏移值应用到 left 和 top 上。第一次实现很容易犯的一个错误就是监听元素本身的 mousemove。当然这个也可以正确计算出偏移,问题在于如果鼠标移动稍快超出了元素,拖动就卡掉了。所以应该监听全局的 mousemove 获取偏移值。iframe 特色的拖动iframe 的拖动同理,只是因为发生在 iframe 里的事件不能传到上层,需要手动打包一下。iframe 部分拖动由 iframe 里的某个元素触发,为了节省资源,在触发的时候才监听拖动和结束,并在结束的时候解绑。在 iframe 里监听 mousemove 就是为了把偏移值传回上层,因为上层的 mousemove 事件到这里中断了。// iframe.js var baseMouseX, baseMouseY $dragArea.addEventListener('mousedown', handleDragStart) function handleDragStart (evt) { baseMouseX = evt.clientX baseMouseY = evt.clientY window.parent.postMessage({ msg: 'SALADICT_DRAG_START', mouseX: baseMouseX, mouseY: baseMouseY }, '*') document.addEventListener('mouseup', handleDragEnd) document.addEventListener('mousemove', handleMousemove) } function handleMousemove (evt) { window.parent.postMessage({ msg: 'SALADICT_DRAG_MOUSEMOVE', offsetX: evt.clientX - baseMouseX, offsetY: evt.clientY - baseMouseY }, '*') } function handleDragEnd () { window.parent.postMessage({ msg: 'SALADICT_DRAG_END' }, '*') document.removeEventListener('mouseup', handleDragEnd) document.removeEventListener('mousemove', handleMousemove) }上层部分主要增加了handleFrameMousemove 补上中断的偏移。// parent.js var pageMouseX, pageMouseY var frameTop = 0 var frameLeft = 0 $iframe.style.top = frameTop + 'px' $iframe.style.left = frameLeft + 'px' window.addEventListener('message', evt => { const data = evt.data switch (data.msg) { case 'SALADICT_DRAG_START': handleDragStart(data.mouseX, data.mouseY) break case 'SALADICT_DRAG_MOUSEMOVE': handleFrameMousemove(data.offsetX, data.offsetY) break case 'SALADICT_DRAG_END': handleDragEnd() break } }) function handleDragStart (mouseX, mouseY) { // 得出鼠标在上层的位置 pageMouseX = frameLeft + mouseX pageMouseY = frameTop + mouseY document.addEventListener('mouseup', handleDragEnd) document.addEventListener('mousemove', handlePageMousemove) } function handleDragEnd () { document.removeEventListener('mouseup', handleDragEnd) document.removeEventListener('mousemove', handlePageMousemove) } function handleFrameMousemove (offsetX, offsetY) { frameTop += offsetY frameLeft += offsetX $iframe.style.top = frameTop + 'px' $iframe.style.left = frameLeft + 'px' // 更新鼠标在上层的位置,补上偏移 pageMouseX += offsetX pageMouseY += offsetY } function handlePageMousemove (evt) { frameTop += evt.clientX - pageMouseX frameLeft += evt.clientY - pageMouseY $iframe.style.top = frameTop + 'px' $iframe.style.left = frameLeft + 'px' // 新位置直接可以更新 pageMouseX = evt.clientX pageMouseY = evt.clientY }例子这里实现了一个例子,下面的正方形 iframe 是可以拖动的:兼容性可以看到,这里主要就是传鼠标的坐标偏移值。所以需要兼容老浏览器的话,用繁琐的旧方式与 iframe 交流就行。如果是同域的话也可以直接从 iframe 里获取偏移。
2024年08月24日
6 阅读
0 评论
0 点赞
1
...
141
142
143
...
219