【实用工具】谷歌浏览器插件开发指南-程序员宅基地

技术标签: 前端  软件研发  大数据  

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

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"的dom
    topTool.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.css

body {
  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属性,并组合成tabIds
  const 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属性,并组合成tabIds
        const groupId = await chrome.tabs.group({ tabIds });  // 将tabIds新建成标签组
        await chrome.tabGroups.update(groupId, { title: "菜鸟", color: "yellow" });  // 更新标签组的标题和颜色
    }
});

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

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wenchun001/article/details/133582039

智能推荐

SaaS到底是什么,如何做?这份笔记讲明白了_saas如何开发-程序员宅基地

文章浏览阅读1.3k次。阅读本篇文章,您将可以了解:1、什么是SaaS;2、SaaS的商业模式;3、SaaS的技术架构;4、国内比较好的SaaS平台。_saas如何开发

摄像头接入_大华sdk frealdatacallback码流输出链接-程序员宅基地

文章浏览阅读1.5k次。摄像头接入目前摄像头直播的方案主要有以下几种方式: rtsp方式接入,只能实现视频预览 国标协议接入,实现比较复杂,需要多实现SIP服务器 通过netsdk获取到视频码流,推流到流媒体服务器,通过wsflv,flv,hls等流媒体协议播放,H265不支持 一、采用方案对比后最终采用了第三种方式,java使用jna的方式接入大华netsdk,获取到dav视频码流后去除大华头尾,拿到H264裸码流,通过javacv(对ffmpeg、opencv等库的封装)推送到.._大华sdk frealdatacallback码流输出链接

git-commit-amend踩坑_git remote-tracking 本地commit amend不了-程序员宅基地

文章浏览阅读1.4k次。因为改动比较小,所以我不想重建一个commit,于是我是用了git commit --amend命令,由于之前已经将该commit推送到远程仓库,导致修改后推送失败。百度后发现如果你的commit已经push到了远程仓库,那么使用--amend修改commit后,git push时一定要使用 --force-with-lease 参数来强制推送,否则就会报错。这是我自己推送失败的例子解决方式一、第一种使用后git commit --amend -m "修改Git学习(三)指令"注意:-m “._git remote-tracking 本地commit amend不了

AI实验1——八数码问题_人工智能实验八数码难题-程序员宅基地

文章浏览阅读2.5k次,点赞6次,收藏15次。AI实验1——八数码问题一、实验目的与要求实验目的:1 . 熟悉状态空间表示法;2.掌握深度优先、广度优先和等代价无信息搜索算法;3.掌握启发式函数设计,实现面向实际问题的A*搜索算法;二、实验内容与方法实验内容:利用无信息搜索算法实现八数码难题求解;设计启发式信息函数,利用A*搜索实现八数码难题求解;三、实验步骤与过程1,问题分析在八数码难题中,我们使用状态空间表示法,将八数码矩阵(即矩阵的状态)设置为一个节点类(Node),各个节点之间通过操作集(Operater)[‘U_人工智能实验八数码难题

【Js canvas实现是否透明,抠图等功能原理】_js-demo抠图-程序员宅基地

文章浏览阅读2.8k次,点赞4次,收藏11次。透明背景转jpg格式后变黑我们先看demo,您可以狠狠地点击这里:png图片是否含有透明像素JS检测demo如果是不含透明色的PNG图片,则会提示不含透明;如果是,则提示含透明,如下截图:是否背景透明的检测检测原理是借助canvas的getImageData()方法,关于此方法具体API和使用,可以参见““像素点信息获取”这里的详细介绍。_js-demo抠图

[附源码]java毕业设计高校班主任班级管理系统_高校班级管理系统-程序员宅基地

文章浏览阅读1.1k次。的需求进行调查研究,在对系统进行认真分析之后,得出开发整个系统的各项需求。为降低整个系统的复杂度,而使其更加便于修改,提高代码的可读性,我们会将系统模块化,模块间保持相对独立,且每个模块只完成一个子功能,并且与其他模块通过简单的接口链接,即高内聚低耦合原则,而使整个系统能够拥有一个高性能的结构,这边是系统概要设计最重要的目的。所以该系统的开发实现了最大的意义和价值,在系统完成后,利益是否大过于成本,是否能够达到预期效果,这些方面都要进行可行性分析,再通过分析之后,就可以决定是否开发此系统。_高校班级管理系统

随便推点

html静态页面微信分享带缩略图,【荐】静态页面实现微信分享带缩略图、标题和描述...-程序员宅基地

文章浏览阅读1.2k次。这篇文章主要为大家详细介绍了【荐】静态页面实现微信分享带缩略图、标题和描述,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,有需要的朋友可以收藏方便以后借鉴。静态页面实现微信分享带缩略图、标题和描述,想法很现实,要想实现这样的功能这里就要用到大ajax技术,在这里361源码分享给大家。服务端文件jssdk.php代码:..._html分享链接加图片和描述不需要调用jssdk

VASP学习1入门知识_vaspwiki-程序员宅基地

文章浏览阅读5.9k次,点赞10次,收藏63次。大师兄科研实例使用方法:1从最基本的计算开始,通过示例讲解,结合一些脚本的使用,引导大家思考解决自己的问题。因此,在这本书的学习过程里,每一章节会对应一个例子,大家务必手动搭建模型,输入文件(切忌复制粘贴),然后进行计算,得到和大师兄一致的结果。为了引导大家主动浏览官网解决问题,很多都会采用VASP官网的例子。2如何学习本书,大师兄在学习程序时,受learn_python_the_hard_w..._vaspwiki

想说好多话_好多好多话-程序员宅基地

文章浏览阅读222次。以前觉得深圳好热,可是现在觉得沈阳的风好冷…每天不需要说太多的话,只要敲着喜欢的键盘,默默的清理掉禅道上的bug就好,这样的工作似乎是充实的,却总是少点什么,我也喜欢上了活在自己的小世界里,喜欢上了听歌,喜欢去刷微博,喜欢上去看那些心灵鸡汤和搞笑的博主,喜欢看看最近的陈伟霆是不是有帅了,偶尔碰到一条好玩的微博似乎会笑上一会儿,可能作为一个程序猿,真的比较枯燥叭,有时觉得孤单的像一条_好多好多话

简述计算机维修 维护的基本原则是什么,计算机硬件维护的四大原则-程序员宅基地

文章浏览阅读2.4k次。计算机硬件维护的四大原则近年来,随着社会经济的快速发展和计算机网络技术的广泛应用,如今计算机已经成为生产生活中不可或缺的必需品,随之而来就出现一些问题。下面是YJBYS小编为大家搜索整理的关于计算机硬件维护的四大原则,欢迎参考阅读,希望对大家有所帮助!想了解更多相关信息请持续关注我们应届毕业生培训网!对于计算机而言,主要包括硬件系统与软件系统两部分,其中硬件系统是软件系统功能得以实现的重要基础和前..._硬件维修的基本原则?

java有趣的技术分享ppt,java面试数据结构与算法高频考-程序员宅基地

文章浏览阅读736次。前言本文涵盖了阿里巴巴、腾讯、字节跳动、京东、华为等大厂的Java面试真题,不管你是要面试大厂还是普通的互联网公司,这些面试题对你肯定是有帮助的,毕竟大厂一定是行业的发展方向标杆,很多公司的面试官同样会研究大厂的面试题。与此同时,今年算法面试一定是会被问的,而算法不是光靠背面试题就有用的,它是需要数学逻辑思维的,因此,小编会在文末为大家准备一份非常优质的算法学习手册,重点在于学习思维方法,话不多说,直接开始上精选的大厂面试真题!在校生如果你是在校生,你应该趁着在学校的时间夯实基础(比如计算机系统、_java有趣的技术分享

MapReduce统计以某字母开头的单词的平均长度_mapreduce计算平均单词长度-程序员宅基地

文章浏览阅读1.7k次。MapReduce统计以某字母开头的单词的平均长度用MapReduce编写程序主要的就是编写Map和Reduce函数、main函数java代码如下package section1;import java.io.IOException;import java.util.StringTokenizer;import org.apache.hadoop.conf.Configuratio..._mapreduce计算平均单词长度

推荐文章

热门文章

相关标签