前言
前段时间给公司分享前端技术, 因为部门中不光是前端,还有后端、数据。 所以选择了分享 浏览器 相关的, 这个不光前端每天在用,研发人员日常也都离不开使用浏览器。 在准备过程中,学习到了两个让我很惊喜的开发技巧,顿感多年前端白干,相见恨晚, 今天先分享浏览器的 workspaces 功能, 完成一个面向浏览器编程, 无限修改浏览器中的样式,即可修改本地代码中样式的功能
1、 源代码面板的 Workspaces
提到源代码管理面板, 大家想到的肯定都是打断点,进行源码调试的地方, 实际上这里的功能远不止于此。 这里浏览器其实还给内置了文件系统, 可以让我们在浏览器中编辑代码,改页面的同时更改本地代码,这不就是面向浏览器编程吗。
Workspaces是什么: 工作区(Workspaces)是源代码管理面板中的一个概念,它提供了一种组织和管理项目代码的方式。一个工作区可以包含一个或多个相关的代码仓库,并帮助团队协作、版本控制和代码审查。
2、 常用的开发模式
讲这个之前,先简单回顾一下,我们之前的开发、包括学习css及html的时候,是不是都是左边一个编辑器,右边一个浏览器,在浏览器的元素审查中,找到元素,对元素进行样式调整后,在复制到编辑器中, 保存,然后回到页面来刷新。(应该不会还有人连浏览器上可以调整完代码,再复制到编辑器吧~)
我们先上一个图,演示一下之前的模式, 上一个最简单的html、css代码
演示如下
代码如下
<style>
.box {
width: 100px;
height: 300px;
background-color: aqua;
color: blue;
}
ul {
}
ul li {
color: red;
font-size: 20px;
}
</style>
<body>
<div class="box">hello world</div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
3. 理想的开发模式
那么, 我们可以直接在浏览器中编辑好,然后不打开编辑器保存代码吗?
答案是可以的, 就是用浏览器源代码面板中的 文件系统功能
添加文件的时候,文件夹最好是英文命名, 然后浏览器会有个提示, 是否允许浏览器有访问权限, 点击允许
我们把刚才新建的包含html文件的文件夹添加到这里,然后在编辑器中安装 Live-sever 插件,使用live-sever 打开
此时我们打开文件系统中的demo.html 文件,在上面编辑,保存, 页面就会同步刷新,然后看一下代码,也已经进行了修改, 那么到此,浏览器已经可以变身成编辑器了, 我们可以在这里进行 command+p 查找文件, command+f查找, 复制粘贴,基本编辑器的功能都可以在这里使用了
但是到此,我们只不过是把编辑器的功能搬到了浏览器, 还是没有很简化我的操作,像我们一开始讲的, 如果我们可以在元素审查的时候更改样式, 直接去修改代码可以实现吗, 答案也是可以的。
为了能一边看元素审查面板,一边看源代码面板。我们把源代码面板移到底部
此时更改,样式文件,会发现,无法生效, 原因是, 如果想通过元素审查里面直接更改样式, 需要我们的样式文件不能是内部样式表,而是外部引入,原理是,修改样式时,浏览器会发送socket请求给html,并且修改html中的css引用,并且会发送新的css引用链接,下面我们会在看这段脚本解释这里。现在我们先把代码修改成link导入,再次启动live sever服务
// 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" />
<title>Document</title>
</head>
<link rel="stylesheet" href="./index.css" />
<body>
<div class="box">hello world</div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</body>
</html
// css
.box {
width: 300px;
height: 400px;
background-color: #ea269b;
color: #3748a7;
font-size: 30px;
}
ul li {
color: #00ff33;
font-size: 20px;
}
此时我们再次进行审查元素, 修改样式,看下面的效果
这时,我们再去元素审查,修改样式代码, 发现样式改了, 浏览器文件系统中的样式代码改了, 编辑器中的样式代码也改了, 我们的需求到现在基本完成了, 但是如果再次修改,我们会发现右下角的文件系统里的样式文件出现了问号,说明现在是socket不通的状态, 并且编辑器中的代码是没有再次进行更改的。 其实这个问题是浏览器本身不支持这样多次更改, 产生 css 缓存后, 就不再进行热更新了, 禁掉缓存后也没有用, 但是我们尝试每次修改后, 强制刷新页面,在进行修改,发现是可以保证每次修改都生效的。
但是这样还要每次手动刷新还是不方便, 那么怎么解决这个问题呢, 其实只需要在每次热更新后, 我们调用一下浏览器的强制刷新即可, 我们在元素审查html文件中查看,会发现浏览器偷偷给我们添加了一段脚本。
我们把这段脚本拿下来看
// <![CDATA[ <-- For SVG support
if ("WebSocket" in window) {
(function () {
function refreshCSS() {
var sheets = [].slice.call(document.getElementsByTagName("link"));
var head = document.getElementsByTagName("head")[0];
for (var i = 0; i < sheets.length; ++i) {
var elem = sheets[i];
var parent = elem.parentElement || head;
parent.removeChild(elem);
var rel = elem.rel;
if (
(elem.href && typeof rel != "string") ||
rel.length == 0 ||
rel.toLowerCase() == "stylesheet"
) {
var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, "");
elem.href =
url +
(url.indexOf("?") >= 0 ? "&" : "?") +
"_cacheOverride=" +
new Date().valueOf();
}
parent.appendChild(elem);
}
}
var protocol =
window.location.protocol === "http:" ? "ws://" : "wss://";
var address =
protocol + window.location.host + window.location.pathname + "/ws";
var socket = new WebSocket(address);
socket.onmessage = function (msg) {
if (msg.data == "reload") window.location.reload();
else if (msg.data == "refreshcss") refreshCSS();
};
if (
sessionStorage &&
!sessionStorage.getItem("IsThisFirstTime_Log_From_LiveServer")
) {
console.log("Live reload enabled.");
sessionStorage.setItem("IsThisFirstTime_Log_From_LiveServer", true);
}
})();
} else {
console.error(
"Upgrade your browser. This Browser is NOT supported WebSocket for Live-Reloading."
);
}
// ]]>
从这段脚本中,就可以大致知道浏览器的元素样式修改后, 为什么加载到最新的修改样式后的代码, 其实就是浏览器修改元素样式后,会发出socket消息, 我们在脚本中就能监听到样式更改的消息, 然后把样式文件饮用的地址后面修改一下时间戳防止缓存, 重新发送样式文件请求,获取最新样式代码, 那么我们既然找到了这个更新时机,那么其实只需要在更新是,增加一个刷新浏览器的操作即可
代码片段如下
//...
socket.onmessage = function (msg) {
if (msg.data == "reload") window.location.reload();
else if (msg.data == "refreshcss") {
refreshCSS();
setTimeout(() => {
window.location.reload();
}, 500);
}
};
//...
这时我们就完整的完成了从 审查元素 > 修改样式 > 代码更改成功 的完整链路, 也大体理清了,浏览器的webwork功能。
3、总结
我们经常用浏览器的源代码面板, 但是文件系统一直在旁边,从来没看关注过, 当我们使用起来才发现,原来chrome是支持代码编辑器功能的,进而我们想到了,能不能直接通过样式审查修改样式的时候,实时更新本地的样式代码,不用再像之前调好后复制在通过类找到代码,在修改保存,再回来刷新检查生没生效。 我们发现是可行的, 我们在启动静态服务时,浏览器会通过socket消息与我们本地的代码进行通讯, 会监听到样式更改后,通过refashCSS修改我们html 中 head 里的样式文件的引用,增加时间戳,防止缓存, 但是不支持多次修改,更新, 我们通过修改浏览器注入的脚本,增加了reload ,达到了最终的。无限修改样式也可以同步更新到本地代码。
4、完整代码
index.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" />
<title>Document</title>
</head>
<link rel="stylesheet" href="./index.css" />
<body>
<div class="box">hello world</div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</body>
<script>
// <![CDATA[ <-- For SVG support
if ("WebSocket" in window) {
(function () {
function refreshCSS() {
var sheets = [].slice.call(document.getElementsByTagName("link"));
var head = document.getElementsByTagName("head")[0];
for (var i = 0; i < sheets.length; ++i) {
var elem = sheets[i];
var parent = elem.parentElement || head;
parent.removeChild(elem);
var rel = elem.rel;
if (
(elem.href && typeof rel != "string") ||
rel.length == 0 ||
rel.toLowerCase() == "stylesheet"
) {
var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, "");
elem.href =
url +
(url.indexOf("?") >= 0 ? "&" : "?") +
"_cacheOverride=" +
new Date().valueOf();
}
parent.appendChild(elem);
}
}
var protocol =
window.location.protocol === "http:" ? "ws://" : "wss://";
var address =
protocol + window.location.host + window.location.pathname + "/ws";
var socket = new WebSocket(address);
socket.onmessage = function (msg) {
if (msg.data == "reload") window.location.reload();
else if (msg.data == "refreshcss") {
refreshCSS();
setTimeout(() => {
window.location.reload();
}, 500);
}
};
if (
sessionStorage &&
!sessionStorage.getItem("IsThisFirstTime_Log_From_LiveServer")
) {
console.log("Live reload enabled.");
sessionStorage.setItem("IsThisFirstTime_Log_From_LiveServer", true);
}
})();
} else {
console.error(
"Upgrade your browser. This Browser is NOT supported WebSocket for Live-Reloading."
);
}
// ]]>
</script>
</html>
index.css
.box {
width: 300px;
height: 400px;
background-color: #5826ea;
color: #a73751;
font-size: 30px;
}
ul li {
color: #ff0090;
font-size: 20px;
}