首页
Search
1
解决visual studio code (vscode)安装时没有选择安装路径问题
138 阅读
2
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
131 阅读
3
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
107 阅读
4
如何在 Clash for Windows 上配置服务
77 阅读
5
Uniapp如何引入自定义样式文件
75 阅读
clash
服务器
javascript
全部
游戏资讯
登录
Search
加速器之家
累计撰写
1,061
篇文章
累计收到
0
条评论
首页
栏目
clash
服务器
javascript
全部
游戏资讯
页面
搜索到
624
篇与
的结果
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日
4 阅读
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日
3 阅读
0 评论
0 点赞
2024-08-24
纯 CSS 实现浮动介绍
把扩展上传到 Chrome 商店需要在开发者后台填写一系列表单,非常喜欢它对详细介绍的处理,就想着偷师一下。先上效果,下面是模仿的样子。由于详细介绍一般比设置本身要长,它使用了隐藏、按需显示的方式减少了高度。看了开发者后台的代码,它是使用 JavaScript 响应鼠标事件并计算高度和显示。作为 CSS 洁癖,我第一反应当然是先考虑用 CSS 实现。这里主要的问题其实就是如何让鼠标在设置(body)上响应介绍(aside)的显示。在实现 iPhone 滑块开关的时候,就是通过 的 :check 来控制 的变化,方法是利用 + 选择符选择兄弟姐妹元素。像这种控制其它元素的情况都可以用这个方法。.item-aside { z-index: -1; opacity: 0; } .item-body:hover + .item-aside { z-index: 1; opacity: 1; }全部的代码,也火速使(tou)用(shi)在了 Saladit 的设置界面: Lorem. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fugiat, vitae. Nesciunt. Sit doloremque repellat natus libero. Pariatur quibusdam voluptas, vero accusamus itaque. Neque magni autem sunt. Animi! Similique voluptas, sint quam eligendi. Unde repudiandae, mollitia voluptatum similique repellendus eum. Ut, quae! Deleniti. *{ box-sizing: border-box; } .menu{ margin: 15px 10%; } .item{ display: flex; position: relative; margin-bottom: 15px; line-height: 1.6; word-wrap: break-word; } .item-header{ width: 2 / 12 * 100%; padding: 0 10px; text-align: right; font-weight: bold; } .item-body{ flex: 1; width: 10 / 12 * 100%; margin-right: 4 / 12 * 100%; padding: 10px; background-color: #fafafa; &:hover + .item-aside{ z-index: 1; opacity: 1; } } .item-aside{ width: 4 / 12 * 100%; position: absolute; z-index: -1; top: 0; right: 0; padding-left: 10px * 2 + 1px; padding-right: 10px; opacity: 0; transition: all 400ms; // left line &::after{ content: ''; position: absolute; top: 0; bottom: 0; left: 10px; border-left: 1px #ddd solid; } &:hover{ z-index: 1; opacity: 1; } }
2024年08月24日
14 阅读
0 评论
0 点赞
2024-08-24
CSS VFM 中易混淆的名词概念
除了 table box 和 replaced element,block-level box 都是 block container box。Block container box 要么只包含 block-level boxes (宣布了 BFC),要么只包含 inline-level boxes (宣布了 IFC)。(BFC: Block Formatting Context, IFC: Inline Formatting Context)(Block-level box 指的是这个盒子本身,它参与的是 BFC;而 block container box 说的是这个盒子内部,宣布了 BFC 或 IFC)。反过来 block container box 则不一定是 block-level box,还可以是 non-replaced inline block 和 non-replaced table cell(即这些盒子参与 IFC ,内部也可以宣布 BFC 或 IFC)。
2024年08月24日
3 阅读
0 评论
0 点赞
2024-08-24
CSS 属性值计算
属性值的计算可谓是 CSS 101 。然而入门资料从来都是良莠不齐的,当初从畅销书上得来的一些误解,如今整理笔记的时候才发现。这里就结合规范梳理一遍。一个属性的值在计算时会经过 4 个阶段 Specified values Computed values Used values Actual values Specified values这里有 3 种可能,满足一种就可以 计算 cascade 有结果 否则,若这个值可以继承,继承父元素的 computed value(根元素除外) 还是没有,则用默认值 计算 cascade这里就是重点,经历 4 个步骤: 匹配 Media Type 的筛选 按来源排序(低到高) user agent declarations user normal declarations author normal declarations author important declarations user important declarations 同个来源的按权值(specificity)排序,收集选择器里的属性个数比较 "style" 属性(attribute)里的属性 * 1000 ID 属性 * 100 其它属性、类、伪类 * 10 元素名、伪元素 * 1 如果前面得出并列结果,则按位置排序 越靠后越高 import 进来的样式看做在本样式表前面 可以看到来源总共有三个,user agent、user 和 author。User important 最高是因为用户的自定义样式一般是为了覆盖 user agent 作为默认样式,但有时候用户也想覆盖 author 即网站本身的样式,于是让 user important 最高。注意 与 引入的 CSS 同属 author declarations 也就是说两者的等级是一样的,按先后顺序覆盖。HTML 里若有非 CSS 的样式属性(presentational attributes),比如 font 之类,UA 可能将其翻译为 CSS 属性,放在 author style sheet 开端,并赋予权值 0。Computed values在排版前就可以确定的值。在元素定义的 Computed Value 区域可以查到,如 URI 计算绝对路径 'em' 和 'ex' 计算成 px 或绝对长度。 比如body { font-size: 10px; } h1 { font-size: 120%; }h1 先计算 cascade 按继承得到了 10px ,再在本阶段计算得 12px。Used values排版之后才能确定的值,如百分比宽度,必须排版才能知道父容器宽度。Actual values实际用于渲染的值,由于设备环境等因素,一些值可能不能用,需要作出变化。
2024年08月24日
5 阅读
0 评论
0 点赞
1
...
60
61
62
...
125