当前位置: 首页 > news >正文

【实用工具】谷歌浏览器插件开发指南

谷歌浏览器插件开发指南涉及以下几个方面:

1. 开发环境准备:首先需要安装Chrome浏览器和开发者工具。进入Chrome应用商店,搜索“Extensions Reloader”和“Manifest Viewer”两个插件进行安装,这两个插件可以方便开发和调试。

2. 创建插件:创建插件的方式有两种。第一种是从零开始创建,需要编写插件的各种文件,包括manifest.json、popup.html等。第二种是使用生成工具,如Yeoman,它可以自动生成插件文件和代码结构。

3. 编写插件代码:插件代码可以使用HTML、CSS、JavaScript等,需要根据插件的功能进行编写。

4. 调试和测试:在Chrome浏览器中可以使用开发者工具进行调试和测试,可以查看插件的运行状态,以及对代码进行修改和调试。

5. 发布和分发:发布插件需要一个Google开发者账号,并进行相应的审核和测试。插件发布后可以通过Chrome应用商店进行分发和安装。

总的来说,谷歌浏览器插件开发需要学习HTML、CSS、JavaScript等相关知识,并掌握Chrome插件开发的基本流程和技能。

Chrome插件本质上也是一个web页面的功能开发,因此需要熟悉以下基本的技能:

  • HTML:页面内容标记。
  • CSS:页面样式设置。
  • JavaScript:处理页面逻辑的脚本。
  • WebPlatformAPI:web平台的标准API。

下面开始正题。

Chrome插件基础概念

ChromeAPI

ChromeAPI是Chrome浏览器提供的JavaScriptAPI,在插件开发中使用这些API可以调用Chrome浏览器的提供的诸多功能,完成我们定制化的需求。

manifest.json

也叫插件清单,可以把它理解为整个插件的配置文件。manifest文件一定要放在根目录下,不可或缺,主要记录了插件的重要元数据、资源定义、权限声明,以及指定要在后台运行和页面运行的文件等。

// manifest.json文件{"manifest_version": 3,"name": "Reading time","version": "1.0","description": "Add the reading time to Chrome Extension documentation articles"
}

其中manifest_version​、name​、version​是必须的。

Service worker

也就是后台服务,主要是负责处理和监听浏览器的各类事件。后台服务可以使用所有ChromeAPI,但是不能直接与网页内容交互。

要使用后台服务,需要先在manifest文件中注册background:

{..."background": {"service_worker": "background.js"}
}

后台服务在浏览器运行起来后,就会一直在后台运行back.js脚本。

Content Script

也叫内容脚本。上面提到后台服务无法直接与网页内容进行交互,而内容脚本便来接替了这部分工作。内容脚本可以读取、修改或注入页面DOM,也可以使用一部分的ChromeAPI,但是不可使用的那部分ChromeAPI可以通过与后台服务的通讯来完成数据或消息的传递交互。

要使用内容脚本,需要先在manifest文件中注册content_scripts:

{..."content_scripts": [{"js": ["scripts/content.js"],"matches": ["https://developer.chrome.com/docs/extensions/*","https://developer.chrome.com/docs/webstore/*"]}]
}

其中,matches表示匹配的网站,js表示执行的脚本。即如果网站地址在matches列表中,则会执行js列表中的脚本。

pages

页面包含了popup的弹窗页面、option页面以及其他页面,这些页面也是就是前端开发中的HTML文件。这些页面都可以访问ChromeAPI。

以上便是Chrome插件开发中很重要且必要的几个概念,也是一个插件工程中主要的几个文件,因此请务必记住这几个概念。接下来,我们将一步一步开发一个插件,来逐步的了解Chrome插件开发的工作。

实际案例

插件开发

需求

开发前,我们先来看看这个插件需要完成那些功能。

1、阅读时间:

    • 在指定的页面上某个位置显示出当前页面预计阅览完成所需要的时间。此处我们已百度百科页面为例,在页面开头位置显示当前页面阅览完成大概需要长时间。
    • 阅读时间的预估规则我们这里简单计算下,使用页面文本的字数除以每分钟200个文字,并取整表示。

2、聚焦模式:

    • 对于某些页面的侧边栏、广告栏等区域做隐藏,实现聚焦主体内容的阅读。

3、标签管理:

    • 组织扩展文档选项卡,实现对特定域名的标签页组合成标签组。

阅读时间功能开发

思路:在内容脚本中使用js统计当前页面的文字数count,并假设阅读速度是500个/分钟,计算出预估时间:

time=count/500

先配置manifest文件:

{"manifest_version": 3,  // 版本号,目前2版本已经停止支持,推广的是3版本"name": "toolKits",  // 插件名称"description": "小工具集",  // 插件描述"version": "1.0",  // 插件开发的版本号,自定义即可"icons": {  // 插件的图标"16": "images/icon-16.png","32": "images/icon-32.png","48": "images/icon-48.png","128": "images/icon-128.png"},"content_scripts": [  // 内容脚本注册{"js": ["scripts/baikeReadTime.js"],"matches": ["https://baike.baidu.com/item/*"]}]
}

从配置中可得知内容脚本的注册规则:当网址匹配上“https://baike.baidu.com/item/*”时,运行scripts/baikeReadTime.js脚本。

编写内容脚本,内容脚本是往页面中注入预估的阅读时间元素,代码如下:

// baikeReadTime.js// 通过检查百度百科页面元素,确定大部分内容都是在class="main-content J-content"的div标签中,因此先获取到内容标签的dom
const mainContent = document.getElementsByClassName("main-content J-content")[0]// 如果对应内容dom存在
if (mainContent) {const text = mainContent.textContent;  // 获取内容dom中所有的文本内容const chineseWordRegExp = /[\u4e00-\u9fa5]/g;  // 通过正则表达式匹配出所有的汉字const chineseWords = text.matchAll(chineseWordRegExp);const count = [...chineseWords].length;  // 计算汉字长度const readTime = Math.round(count / 500);  // 计算预计阅读时间const badge = document.createElement('span');  // 创建一个<span>标签badge.classList.add('collect-text');  // 给<spn>标签添加样式 样式尽量跟周围的标签样式一致badge.textContent = `⏱️ 总字数约${count}, 预计阅读耗时:${readTime} 分钟`;  // 给<span>标签添加文本内容const topTool = document.getElementsByClassName("top-tool")[0]  // 找到class="top-tool"的domtopTool.insertAdjacentElement('beforebegin', badge);  // 把<span>标签插入到topTool的dom前面
}

演示:打开Chrome浏览器,安装插件后,打开任意百度百科的内容页,即可看到我们注入到页面的预估阅读时间元素。比如我们打开百度百科,搜索“亚运会”,页面展示图待更新。

聚焦模式功能开发

还是以百度百科页面为例,我们通过插件实现去掉右侧边栏和底部广告栏的信息

思路:分析页面元素,找到右侧边栏和底部广告栏的元素,再通过内容脚本对其进行样式隐藏即可。

1、首先给插件的图标设置一个徽标,用于展示聚焦模式的开关状态。

因为聚集模式的状态应该是在浏览器打开的时候就显示,因此设置状态徽标的逻辑应该放在background.js脚本中。具体代码如下:

chrome.runtime.onInstalled.addListener(() => {chrome.action.setBadgeText({ "text": "OFF" })
})

调用ChromeAPI,给插件设置徽标。大致意思就是添加一个安装事件的监控器,当插件安装后就给插件设置一个徽标,内容是“OFF”。

监听插件的点击事件。当点击插件的时候,判断当前浏览器标签页(tab页)的网址,如果符合要求,就将插件徽标设置为“ON”。继续在background.js脚本中添加以下代码:

...
const baike = "baike.baidu.com/item/"chrome.action.onClicked.addListener(async (tab) => {if (tab.url.includes(baike)) {  // 如果标签页的网址中包含baike的网址,则将插件徽标设置为“ON”const prevState = await chrome.action.getBadgeText({ tabId: tab.id })const nextState = prevState === "ON" ? "OFF" : "ON"await chrome.action.setBadgeText({tabId: tab.id,text: nextState})}})

以上两步使用到了Chrome的activeTab权限和scripting权限,因此我们需要再manifest文件中配置权限声明:

{..."permissions": ["activeTab","scripting"],...
}

此时,重新加载插件后,如果当前标签页是百科页面,点击插件,就能看到切换徽标状态的效果的。

2、注入css,隐藏元素。

当徽标状态为ON时,给百科页面注入css,隐藏掉右侧边栏。继续在background.js脚本中添加以下代码:

...
chrome.action.onClicked.addListener(async (tab) => {if (tab.url.includes(baike)) {...if (nextState === "ON") {await chrome.scripting.insertCSS({files: ["focus-mode.css"],target: { tabId: tab.id },});} else if (nextState === "OFF") {await chrome.scripting.removeCSS({files: ["focus-mode.css"],target: { tabId: tab.id },});}}})

判断徽标状态,如果是“ON”,则往目标标签页插入css文件,否则就移除掉插入到目标页的css文件。上例中插入了focus-mode.css

编写注入的css文件,已达到隐藏侧边栏和底部广告栏的目的。通过分析网页的html代码可知,class="side-content"的标签即为侧边栏的元素标签,id="tashuo_bottom"的标签即为底部广告栏的标签,因此代码如下:

// focus-mode.css.content {.side-content {display: none;}
}#tashuo_bottom {display: none;
}

3、演示:

浏览器中重新加载插件后,在百科页点击插件,就能看到默认插件的聚集模式是“OFF”状态,点击后徽标更新为“ON”状态,且页面的侧边栏和底部栏都消失了,图待更新。

标签管理功能开发

上面两个案例,我们分别体验了内容脚本和后台服务脚本的能力,接下来我们看看插件打开的页面相关的能力。

该功能我们期望点击插件,能打开一个弹窗页,在这个弹窗页中展示当前浏览器窗口的所有标签页,然后我们可以选择某些标签页将他们放在一个标签组中。

思路:实现popup页面,并在页面中展示当前浏览器窗口的所有标签页,然后页面中有按钮,可创建一个标签组,并将选中的标签页放到这个标签组中。

1、首先我们需要一个popup页面

html代码如下:

# popup.html<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><link rel="stylesheet" href="./popup.css" /></head><body><template id="li_template"><li><a><h3 class="title">Tab Title</h3><p class="pathname">Tab Pathname</p></a></li></template><h1>Google Dev Docs</h1><button>新建/取消组合</button><ul></ul><script src="./popup.js" type="module"></script></body>
</html>

需要注意的是:这个popup.html无法运行内联 JavaScript,因此我们只能通过导入的方式,引入JavaScript脚本。

css代码如下:

# popup.cssbody {width: 20rem;
}ul {list-style-type: none;padding-inline-start: 0;margin: 1rem 0;
}li {padding: 0.25rem;
}
li:nth-child(odd) {background: #80808030;
}
li:nth-child(even) {background: #ffffff;
}h3,
p {margin: 0;
}

2、点击插件,触发弹窗

要实现点击插件就能打开popup弹窗页,有两中方式:

方法1:可以在manifest文件中的action字段中配置默认弹窗,代码如下:

{..."action": {"default_popup": "popup.html"},...
}

该配置意思是点击插件时默认打开的弹窗就是“popup.html”文件。

方法2:后台脚本中通过监听点击事件,然后调用ChromeActionAPI的setPopup​方法实现。本插件因为之前实现了百度百科页面的聚焦模式功能,因此采用这种方式触发弹窗。对之前的代码做了些调整,具体如下:

// background.js// 监听运行时和安装完成的事件
chrome.runtime.onInstalled.addListener(async () => {// 获取当前浏览器窗口激活的标签页tabs = await chrome.tabs.query({active: true, currentWindow: true})// 如果标签页的url中包含百度百科的地址,就设置徽标,否则不设置徽标if(tabs[0].url.includes("baike.baidu.com/item/")){chrome.action.setBadgeText({ "text": "OFF" })}
})// 监听点击事件
chrome.action.onClicked.addListener(async (tab) => {// 如果当前页面是百度百科的页面,就更新徽标状态,并完成聚焦模式的相关功能if (tab.url.includes("baike.baidu.com/item/")) {const prevState = await chrome.action.getBadgeText({ tabId: tab.id })const nextState = prevState === "ON" ? "OFF" : "ON"await chrome.action.setBadgeText({tabId: tab.id,text: nextState})if (nextState === "ON") {await chrome.scripting.insertCSS({files: ["focus-mode.css"],target: { tabId: tab.id },});} else if (nextState === "OFF") {await chrome.scripting.removeCSS({files: ["focus-mode.css"],target: { tabId: tab.id },});}}// 如果当前页是菜鸟教程网站的页面,就弹出popup弹窗else if(tab.url.includes("www.runoob.com/")){chrome.action.setPopup({ popup: "popup/popup.html" })}})

tips:如果在manifest文件中配置了点击默认弹窗页面,那么action.onClicked事件将不会生效。

3、将所有的标签页的title和path展示在popup弹窗页中

交互逻辑通过popup.js实现
3.1 调用ChromeAPI查询当前浏览器窗口中的所有标签页:

// poppu.js// 查询符合条件的所有tabs
const tabs = await chrome.tabs.query({currentWindow: true,url: ["https://www.runoob.com/*"]
});
...

3.2 将标签页列表插入到popup页面的元素中:

...
// 按照默认顺序对tabs列表中的元素进行排序
const collator = new Intl.Collator();
tabs.sort((a, b) => collator.compare(a.title, b.title));const template = document.getElementById("li_template");  // 从页面获取模版节点
const elements = new Set();
for (const tab of tabs) {const element = template.content.firstElementChild.cloneNode(true);  // 复制模版第一个节点const title = tab.title.split("-")[0].trim();  // 获取tab中的标题const pathname = new URL(tab.url).pathname.slice("/docs".length);  // 获取tab中的路径element.querySelector(".title").textContent = title;  // 复制出来的节点中class=“title”的子节点,写入内容element.querySelector(".pathname").textContent = pathname;  // 复制出来的节点中class=“pathname”的子节点,写入内容element.querySelector("a").addEventListener("click", async () => {  // 复制出来的节点中<a>标签子节点添加点击事件// 点击的时候,更新对应的tab和窗口为激活状态await chrome.tabs.update(tab.id, { active: true });await chrome.windows.update(tab.windowId, { focused: true });});elements.add(element);
}
document.querySelector("ul").append(...elements);

以上代码中使用到了ChromeTabsAPI,该API 中的许多方法无需请求任何权限即可使用。但是,如果要访问标签页的标题和 URL这些敏感属性,就需要声明授权许可。如果我们请求“标签页”权限,导致所有标签页的敏感属性都有权限访问,但是由于我们仅仅管理特定网站的选项卡,因此我们请求更小范围的host权限。

host权限可以授权我们获取指定网站的敏感信息(包含title和URL),以此来缩小权限范围,进而保护用户隐私。在manifest文件中配置host权限:

{..."host_permissions": ["https://www.runoob.com/*"],...
}

注意:如果插件中使用了tabs权限或host权限,那么用户在安装插件时都会有弹窗提示。如下图:

3.3 ​对标签页进行分组

该功能需要使用到ChromeTabGroupsAPI,该API将允许插件对标签组进行命名和设置颜色。同样的,要使用该API也需要在manifest文件中声明权限:

{..."permissions": [..."tabGroups"]...
}

3.4 实现按钮的交互

在 popup.js 中,创建一个按钮,该按钮将使用 tabs.group() 对所有选项卡进行分组并将它们移动到当前窗口中。具体代码如下:

...
const button = document.querySelector("button");  // 获取button标签
// 给button标签添加点击事件
button.addEventListener("click", async () => {const tabIds = tabs.map(({ id }) => id);  // 解构出tabs中每个对象的id属性,并组合成tabIdsconst group = await chrome.tabs.group({ tabIds });  // 将tabIds新建成标签组await chrome.tabGroups.update(groupId, { title: "菜鸟", color: "yellow" });  // 更新标签组的标题和颜色
});

如果标签页已经在分组中,则移出分组

要将标签页移出分组需要使用到ChomeTabsAPI,因此要在manifest文件中声明tabs权限:

{..."permissions": [..."tabGroups","tabs"]...
}

因为在点击按钮时需要先判断是否已经有标签组了,所以对popo.js做如下改造:

...
const button = document.querySelector("button");  // 获取添加组合的button标签
// 给button标签添加点击事件
button.addEventListener("click", async () => {const tabGroups = await chrome.tabGroups.query({ title: "菜鸟" }) // 找到菜鸟标签组// 如果菜鸟标签组存在,则取消标签组,否则添加菜鸟标签组if (tabGroups.length) {const tabs = await chrome.tabs.query({ groupId: tabGroups[0].id })const tabIds = tabs.map(({ id }) => id)await chrome.tabs.ungroup(tabIds)} else {const tabIds = tabs.map(({ id }) => id);  // 解构出tabs中每个对象的id属性,并组合成tabIdsconst groupId = await chrome.tabs.group({ tabIds });  // 将tabIds新建成标签组await chrome.tabGroups.update(groupId, { title: "菜鸟", color: "yellow" });  // 更新标签组的标题和颜色}
});

------但是在调试过程中发现,后台服务中的点击事件存在一些Bug,点击事件中如果有根据网站来判断弹哪个页面的话,第一个条件规则触发后,后面的条件规则将不会覆盖第一个条件规则。目前没有找到原因,后续再继续研究下官方文档。

参考文档:zhuanlan.zhihu.com/p/655456499

相关文章:

【实用工具】谷歌浏览器插件开发指南

谷歌浏览器插件开发指南涉及以下几个方面&#xff1a; 1. 开发环境准备&#xff1a;首先需要安装Chrome浏览器和开发者工具。进入Chrome应用商店&#xff0c;搜索“Extensions Reloader”和“Manifest Viewer”两个插件进行安装&#xff0c;这两个插件可以方便开发和调试。 2…...

应用层协议——DNS、DHCP、HTTP、FTP

目录 1、DNS 协议 1-1&#xff09;Hosts 文件 1-2&#xff09;DNS 系统 1-3&#xff09;域名的组成、分类和树状结构 1-4&#xff09;DNS 域名服务器类型 1-5&#xff09;DNS 查询方式 1-6&#xff09;DNS 域名解析的一般步骤 1-7&#xff09;对象类型与资源记录 2、D…...

XML文件读写

0、.pro文件添加依赖 QT xml1、使用 QDomDocument 方式 #include <QtXml/QDomDocument> #include <QtXml/QDomProcessingInstruction> #include <QtXml/QDomElement> #include <QFile> #include <QTextStream> #include <QDebug>bo…...

Win11 安装 Vim

安装包&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1Ru7HhTSotz9mteHug-Yhpw?pwd6666 提取码&#xff1a;6666 双击安装包&#xff0c;一直下一步。 配置环境变量&#xff1a; 先配置系统变量中的path&#xff1a; 接着配置用户变量&#xff1a; 在 cmd 中输入…...

Mac电脑BIM建模软件 Archicad 26 for Mac最新

ARCHICAD 软件特色 智能化 在2D CAD中&#xff0c;所有的建筑构件都由线条构成和表现&#xff0c;仅仅是一些线条的组合而已&#xff0c;当我们阅读图纸的时候是按照制图规范来读取这些信息。我们用一组线条表示平面中的窗&#xff0c;再用另一组不同的线条在立面中表示同一个…...

JavaEE-网络编程套接字(UDP/TCP)

下面写一个简单的UDP客户端服务器流程 思路&#xff1a; 对于服务器端&#xff1a;读取请求&#xff0c;并解析–> 根据解析出的请求&#xff0c;做出响应(这里是一个回显&#xff0c;)–>把响应写回客户端 对于客户端&#xff1a;从控制台读取用户输入的内容–>从控制…...

微服务技术栈-Gateway服务网关

文章目录 前言一、为什么需要网关二、Spring Cloud Gateway三、断言工厂和过滤器1.断言工厂2.过滤器3.全局过滤器4.过滤器执行顺序 四、跨域问题总结 前言 在之前的文章中我们已经介绍了微服务技术中eureka、nacos、ribbon、Feign这几个组件&#xff0c;接下来将介绍另外一个组…...

函数形状有几种定义方式;操作符infer的作用

在 TypeScript 中&#xff0c;函数形状可以用多种方式进行定义。下面介绍了几种常用的函数形状定义方式&#xff1a; 函数声明&#xff1a; function add(a: number, b: number): number {return a b; }在函数声明中&#xff0c;我们直接使用 function 关键字来声明函数&…...

Java / MybatisPlus:JSON处理器的应用,在实体对象中设置对象属性,对象嵌套对象

1、数据库设计 2、定义内部的实体类 /*** Author lgz* Description* Date 2023/9/30.*/ Data // 静态构造staticName&#xff0c;方便构造对象并赋予属性 AllArgsConstructor(staticName "of") NoArgsConstructor ApiModel(value "亲友", description …...

力扣 -- 1027. 最长等差数列

解题步骤&#xff1a; 参考代码&#xff1a; class Solution { public:int longestArithSeqLength(vector<int>& nums) {int nnums.size();int ret2;unordered_map<int,int> hash;//这里可以先把nums[0]存进哈希表中&#xff0c;方便后面i从1开始遍历hash[num…...

正则验证用户名和跨域postmessage

正则验证用户名 字母数字符号大小写8-14匹配用户名的 <!DOCTYPE html> <html> <head><meta charset"utf-8"><meta name"viewport" content"widthdevice-width, initial-scale1"><title>form</title> …...

jsbridge实战1:xcode swift 构建iOS app

[[toc]] 环境安装 macOs: 10.15.5 xcode: 11.6 demo:app 创建 hello world iOS app 创建工程步骤 选择&#xff1a;Create a new Xcode project选择&#xff1a;iOS-> single View App填写&#xff1a; project name: swift-app-helloidentifer: smile 包名language: s…...

零基础部署nginx mysql springboot

参考&#xff1a;写给开发人员看的Docker干货&#xff0c;零基础部署nginx mysql springboot 一、连接linux 阿里云 参考&#xff1a;部署到Linux 可能需要购买&#xff1a;购买链接 二、安装docker # 先切换到root用户下 sudo su# 更新apt-get&#xff0c;保证apt-get最新…...

6-3 模式匹配

description 给出主串s和模式串t&#xff0c;其长度均不超过1000。本题要求实现一个函数BF(string s, string t)&#xff0c;求出模式串t在主串s中第一次出现的位置&#xff08;从0开始计算&#xff09;&#xff0c;如果在s中找不到t&#xff0c;则输出-1。 函数接口定义&…...

SQL JOIN 时 USING 和 ON 的异同

在数据表做 join 时&#xff0c;即可以用 using&#xff0c;也可以用 on。有什么异同点呢。 ON 是更加普遍的用法&#xff0c;可以连接表 On 一个字段&#xff0c;多个字段&#xff0c;甚至一个条件表达式。举例 SELECT * FROM world.City JOIN world.Country ON (City.Cou…...

安全学习_开发相关_JNDI介绍(注入)RMILDAP服务

文章目录 参考&本节目的JNDI概念-RMI&LDAP服务调用检索&#xff1a;在RMI服务中调用了InitialContext.lookup()的常用类有&#xff1a;在LDAP服务中调用了InitialContext.lookup()的常用类有&#xff1a; JNDI注入-使用工具生成远程调用JNDI远程调用-工具&#xff08;j…...

C#学生选课及成绩查询系统

一、项目背景 学生选课及成绩查询系统是一个学校不可缺少的部分&#xff0c;传统的人工管理档案的方式存在着很多的缺点&#xff0c;如&#xff1a;效率低、保密性差等&#xff0c;所以开发一套综合教务系统管理软件很有必要&#xff0c;它应该具有传统的手工管理所无法比拟的…...

【C语言】利用数组处理批量数据(一维数组和二维数组)

前言:在前面学习的程序中使用的变量都属于基本类型&#xff0c;例如整型、字符型、浮点型数据&#xff0c;这些都是简单的数据类型。对于简单的问题&#xff0c;使用这些简单的数据类型就可以了。但是对于有些需要处理的数据&#xff0c;只用以上简单的数据类型是不够的&#x…...

WPF中, 如何将控件的触发事件绑定到ViewModel

在DataGrid 等控件中, 有很多这种带闪电符号的触发事件. 如果用传统的事件驱动, 则直接在后台中建立 一个private PropertyChanged(Sender s, EventAgars Args) 即可. 但是如果需要绑定到ViewModel的话? 应该怎么做? 带闪电符号的触发事件 实现viewModel绑定前端触发事件的…...

解决Qt msvc编译器 中文显示乱码问题

第一步&#xff1a;代码文件选择用utf8编码带bom。第二步&#xff1a;在有中文汉字的代码文件顶部加一行&#xff08;一般是cpp文件&#xff09; #pragma execution_character_set(“utf-8”) 可以考虑放在head.h中&#xff0c;然后需要的地方就引入head头文件就行&#xff0c;…...

JAVA面经整理(7)

一)什么是AQS&#xff1f; 1)AQS也被称之为是抽象同步队列&#xff0c;它是JUC包底下的多个组件的底层实现&#xff0c;Lock&#xff0c;CountDownLatch和Semphore底层都使用到了AQS AQS的核心思想就是给予一个等待队列和同步状态来实现的&#xff0c;它的内部使用一个先进先出…...

CentOS7使用技巧

1、防火墙相关 关闭防火墙 systemctl stop firewalld 关闭防火墙开机自启 systemctl disable firewalld.service 查看防火墙状态 systemctl status firewalld...

Nature Machine Intelligence | “化学元素知识+功能提示”双驱动,探索分子预测新方法

论文题目&#xff1a;Knowledge graph-enhanced molecular contrastive learning with functional prompt 论文链接&#xff1a;https://doi.org/10.1038/s42256-023-00654-0 项目地址&#xff1a;GitHub - HICAI-ZJU/KANO: Code and data for the Nature Machine Intelligence…...

CppCheck静态代码检查工具教程【Windows和Linux端】

目录 1、背景 2、特性介绍 2.1、检查结果 2.2、检查范围 2.3、支持的检查规则&#xff08;列举一些&#xff09;: 2.4、自定义规则 3、linux 端 4、windows 端 1、背景 最近调研了几款 c/c 代码静态检查工具&#xff0c;包括 cppcheck、cpplint、cppdepend、splint、ts…...

W25Q128芯片手册精读

文章目录 前言1. 概述2. 特性3. 封装类型和引脚配置3.1 8焊盘WSON 8x6 mm3.2其他封装 4. 引脚描述4.1 片选4.2 串行数据输入输出4.3 写保护4.4 保持脚4.5 时钟 5. 块图6. 功能描述6.1 SPI功能6.1.1 标准SPI6.1.2 双通道SPI6.1.3 四通道SPI6.1.4 保持功能 6.2 写保护6.2.1 写保护…...

QT商业播放器

QT商业播放器 总体架构图 架构优点&#xff1a;解耦&#xff0c;采用生产者消费者设计模式&#xff0c;各个线程各司其职&#xff0c;通过消息队列高效协作 这个项目是一个基于ijkplayer和ffplayer.c的QT商业播放器, 项目有5部分构成&#xff1a; 前端QT用户界面 后端是集成了…...

Python的函数

近期遇到了一个没怎么看懂的Python函数的形式。 def twoSum(self, nums: List[int], target: int) -> List[int]: 后来上网查了资料。...

【物联网】STM32的中断机制不清楚?看这篇文章就足够了

在嵌入式系统中&#xff0c;中断是一种重要的机制&#xff0c;用于处理来自外部设备的异步事件。STM32系列微控制器提供了强大的中断控制器&#xff0c;可以方便地处理各种外部中断和内部中断。本文将详细介绍STM32中断的结构和使用方法。 文章目录 1. 什么叫中断2. 中断优先级…...

深入剖析红黑树:优雅地平衡二叉搜索树

目录 一.红黑树的概念二.插入操作三.与AVL树的比较 一.红黑树的概念 在之前的学习中&#xff0c;我们了解了二叉搜索平衡树&#xff0c;AVL树通过控制每个结点中的平衡因子的绝对值不超过1&#xff0c;实现了一个高性能的树。而相较于AVL的高度平衡&#xff0c;红黑树觉得AVL为…...

C10K问题:高并发模型设计

一、循环服务器模型 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> #include <sys/socket.h> //*******// #include &l…...

布吉商城网站建设基本流程/企业seo如何优化

场景介绍app 里有一个有一个UITabBarController&#xff0c;在进入UITabBarController之前要验证用户是否已经登陆&#xff0c;如果没有登陆就弹出一个对话框&#xff0c;让用户输入登陆信息。实现方式1.在appDelegate。h里声明一个变量&#xff0c;用来绑定UITableController&…...

北京网站建设 降龙网/个人博客登录首页

github:https://github.com/zhoushengmufc/iosselect webapp模仿ios下拉菜单 html下拉菜单select在安卓和IOS下表现不一样&#xff0c;iosselect正是为统一下拉菜单样式而生 我们以IOS下select的交互和样式为蓝本&#xff0c;开发了这一组件 先看效果&#xff1a; 特点 可以做到…...

网站建设套餐报价/如何写软文

记得第一次接触数据透视表还是在2013年在名古屋SAP项目组&#xff0c;觉得有点难以驾驭&#xff08;没用过&#xff09;&#xff0c;旁边的SAP顾问似乎有点鄙视我的感觉。 后来&#xff0c;工作中需要维护透视表&#xff0c;慢慢的多了一些了解。 数据透视表&#xff08;Pivo…...

电商网站有那些/线下实体店如何推广引流

循环用于重复执行一组语句。循环可分为三类&#xff1a;一类在条件变为 False 之前重复执行语句&#xff0c;一类在条件变为 True 之前重复执行语句&#xff0c;另一类按照指定的次数重复执行语句。 在 VBScript 中可使用下列循环语句&#xff1a; Do...Loop&#xff1a; 当&am…...

西安年网站建设/重庆网站建设与制作

基于springboot和vue实现地方美食分享网站演示开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包…...

网站做任务给钱的/国内打开google网页的方法

大家在登录网站的时候&#xff0c;大部分时候是通过一个表单提交登录信息。但是有时候浏览器会弹出一个登录验证的对话框&#xff0c;如下图&#xff0c;这就是使用HTTP基本认证。下面来看看一看这个认证的工作过程:第一步:客户端发送http request 给服务器,服务器验证该用户是…...