这位用户还没有留下个人签名。
@老虎会游泳,不是,之前你的版本,最后存活的onclick是viewer的,导致没法点击后加载
@老虎会游泳,我理解错了?https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/script#attr-defer
defer布尔属性被设定用来通知浏览器该脚本将在文档完成解析后,触发DOMContentLoaded (en-US)事件前执行。
有defer属性的脚本会阻止DOMContentLoaded事件,直到脚本被加载并且解析完成。
@老虎会游泳,我好奇为何你的脚本会和图片浏览器(下称viewer)冲突
按说,viewer是defer,在DOMContentLoaded之前执行,(之前)你的在触发后执行,应该是可以由你保存好viewer的onclick,最后存活的onclick是你的啊
@老虎会游泳,我感觉DOMContentLoaded触发后,各个图片都下了一小点了(所以也经常会闪烁一下才消失),也不知道能不能利用上
那些拦截广告的,也不知道怎么做到不会有闪烁就过滤掉广告的,感觉像浏览器解析DOM前,就过滤掉了
@老虎会游泳,噢,看漏了,看成“新上传的图片才有文件大小”了
对外站图片用啥方法好呢
@老虎会游泳,旧图片、外站图片、音乐、视频啥的,好像没有提供文件大小
对这些情况,有啥更好的办法吗(除了HEAD再查询一次)
@老虎会游泳,我用的我7楼的代码,有小概率能用上图片浏览器(此时正常,点击按钮重现图片后也正常),大部分时候被你的 footer.js 代替了,点击图片就新窗口打开
@老虎会游泳,我改写了下,主要更新内容:
感觉还存在以下问题:
不知道有没有直接获取文件大小的方法。
目前是用fetch以HEAD方法再发送一次请求,解析content-length判定文件大小。
HEAD当GET看,直接返回整个文件?还是和图片浏览器插件冲突。
按理说,我保留了原始img节点,onclick啥的应该都还保留着?
@老虎会游泳,有空能指教下,问题出哪儿不?
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script>
const blocks = {
userimg: {type: 'img', icon: 'image'},
iframe_box: {type: 'iframe', icon: 'web'},
audio_box: {type: 'audio', icon: 'audiotrack'},
video_box: {type: 'video', icon: 'movie'},
};
function formatSize(size) {
const i = size && Math.floor(Math.log(size) / Math.log(1024));
return (size / (1 << (10 * i))).toFixed(i && 2) + ' ' + ' KMGT'[i].trim() + 'B';
}
customElements.define('my-button', class extends HTMLElement {
#ref = {};
#orig_node;
#media_src;
#media_node;
#createElementFromObject(obj) {
let el = document.createElement(obj.tag);
for (const k in obj) {
if (k === 'children')
obj.children.forEach(c => el.appendChild(this.#createElementFromObject(c)));
else if (k === 'text')
el.textContent = obj[k];
else if (k === 'ref')
this.#ref[obj[k]] = el;
else if (k !== 'tag')
el.setAttribute(k, obj[k]);
}
return el;
}
constructor() {
super();
// 创建一个 shadow root
let shadow = this.attachShadow({mode: 'open'});
[
{tag: 'link', rel: 'stylesheet', href: 'https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css'},
{tag: 'link', rel: 'stylesheet', href: 'https://fonts.googleapis.com/icon?family=Material+Icons'},
{tag: 'script', src: 'https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js'},
{tag: 'button', class: 'mdc-fab mdc-fab--extended', style: 'margin: 10px', children: [
{tag: 'div', class: 'mdc-fab__ripple'},
{tag: 'span', class: 'material-icons mdc-fab__icon', ref: 'icon'},
{tag: 'span', class: 'mdc-fab__label', ref: 'text'},
]},
{tag: 'style', text: `
:host {
/* --mdc-theme-primary: #e74c3c; */
--mdc-theme-secondary: #fafafa;
/* --mdc-theme-background: #f00; */
/* --mdc-theme-on-primary: #fff; */
--mdc-theme-on-secondary: #2c3e50;
}
`},
].forEach(x => shadow.appendChild(this.#createElementFromObject(x)));
this.onclick = this.recover;
}
get text() {
return this.#ref.text.textContent;
}
set text(s) {
this.#ref.text.textContent = s;
}
get icon() {
return this.#ref.icon.textContent;
}
set icon(s) {
this.#ref.icon.textContent = s;
}
// onclick() { // 为什么不能这样重写方法??
recover() {
this.#media_node.src &&= this.#media_src;
this.parentNode.replaceChild(this.#orig_node, this);
delete this;
}
// 替换掉旧节点,展示本按钮
replace(root_node, media_node) {
this.#orig_node = root_node.parentNode.replaceChild(this, root_node);
this.#media_node = media_node;
this.#media_src = media_node.src;
media_node.src &&= ' ';
// 询问目标链接大小,太大则等待用户选择,较小直接显示
if (this.#media_src) {
fetch(this.#media_src, {method: 'HEAD'}).then(resp => {
if (resp.ok) {
const size = parseInt(resp.headers.get('content-length'));
if (size < (1 << 20) && this.icon === blocks.userimg.icon)
this.recover();
else if (size > 0)
this.text += `(${formatSize(size)})`;
}
});
}
}
});
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll(Object.keys(blocks).map(x => `.${x}`).join()).forEach(x => {
// 获取 element 类型、显示按钮时的图标
const {type, icon} = Object.entries(blocks).find(([k]) => x.classList.contains(k))[1];
// 若图片已下载完毕,就让它显示吧
if (type === 'img' && x.complete)
return;
// 获取真正的多媒体节点
const media_node = ['audio', 'video'].includes(type) ? x.querySelector(type) : x;
// 图片有外层链接,则准备替换整个外层
if (type === 'img' && x.parentNode.href)
x = x.parentNode;
// 创建按钮
let el = document.createElement('my-button');
el.icon = icon;
el.text = type === 'iframe' ? '内嵌网页' : media_node.alt || media_node.src;
el.replace(x, media_node);
});
});
</script>
@大尨,小众插件
@大尨,省流量
防止一打开页面,十几MB的图片、几十MB的音乐视频,哗哗地下,流量刷刷地跑,话费蹭蹭地掉
@老虎会游泳,正常一段话,密文变成一长串零宽字符,均匀跟在每个字后面?
或者其他电子水印?(比如正常影片/图片加暗水印,某些小说站加暗水印?)
@老虎会游泳,加密插件改成映射到 CJK、字母、数字 咋办。。(如 base64?)
@老虎会游泳,听说还有 左至右 U+200E 右至左 U+200F 符?
ASCII里的不可打印字符,有没有零宽的?
@天蓝,换作我,命令行下,如果shell能通吃,就懒得再学门语言了
(windows 上都懒得学 cmd powershell,前者简陋,后者稍显繁冗?)
这个场景,感觉可以 ssh key 免密登录,执行命令后返回(除非要频繁批量登录新主机?)
我的认知里,命令行多用于脚本执行(使用文件或标准输入输出),面向用户就客户端或网页端
所以这类模拟交互的,我就不懂使用场景了
@天蓝,为嘛不搞 ssh key 免密登录呢
@卷心菜,不认识。。
简单搜了搜,命令行界的按键精灵??
听说运营商默认封禁很多端口?
@上善若水,换手机后再折腾,新手机重在稳定使用了
@上善若水,对呀,(旧手机)官方root够用,就没折腾其他的
新小米解bl不难,难的是开发版资格。。
@上善若水,官方root是解了bl锁,刷开发版后,才有的功能
@上善若水,是这样的吗?我好久没捣鼓过了
反正开发版要内测分,还得苦心经营维持,才可保持资格更新
那还不如解个BL锁就去root(咋搞?好久没搞过了)
开发版的root功能也用不了吧
我印象中,除了 system 分区修改不了外,好像官方root还可以吧?
@上善若水,我记得LineageOS也不错?
Linux Deploy是要求 Root 的,所以肯定是开发版或其他 ROM 了
@Sin,真的吗?求交流,想学解决方案,看会不会更好
我具体描述一下:
ssh连接后,一直按着一个字母,会一两秒连续响应后,一两秒卡停一下,如此循环往复)我的解决方案是:
(后面讨论放出,现在放 MD5 值:9fb8fa94dd55c78913ea1d7e37c62b0d)
也写成了个服务,Linux Deploy启动系统后,自动接管上述这些
Linux Deploy?
我知道的:
GCC版本的话,下载并解压MinGW-W64 GCC-8.1.0,环境变量加下bin路径就好注:
cmd里能直接打gccIDE使用,可以直接在IDE里指定Toolchain的路径