在上一篇文章中,我们讨论了一些已经广泛使用的新HTML5元素 ,即header
, nav
, footer
和article
。 此外,如果我们为这些元素提供样式,然后在现代浏览器中查看它们,我们应该会看到样式的结果。
但是,当我们在Internet Explorer 8及更早版本(我们称为“旧浏览器”)中查看它们时,情况并非如此,某种程度上这些样式似乎并不适用。
让我们看下面的例子:
![ie8预览](https://assets.hongkiat.com/uploads/html5-shiv-polyfills/ie8-preview.jpg?newedit)
之所以会发生这种情况,是因为旧的浏览器不是为HTML5构建的,因此它们无法识别元素,因此样式也不会被应用。
如何解决这个问题呢
我们可以使用这个小脚本document.createElement(elementName)
,它最初是Sjoerd Visscher在他的评论中提到的。 现在,假设我们希望旧的浏览器能够识别header
元素,我们可以编写:
document.createElement('header')
然后,当我们在Internet Explorer中查看它时
header
元素现在已应用样式,而其他元素保持未样式。 例如,此脚本还将应用于无意义的元素;
document.createElement('foo');
即使HTML5中没有这样的元素,上述脚本也可以使Internet Explorer识别foo
元素。 至于页面中的其他元素,我们可以复制并粘贴脚本并指定需要修补的元素,但是当然不需要这样做, 因为HTML5shiv已经完成了。
HTML5 Shiv
上面的脚本实际上是HTML5shiv开发背后的灵感。
HTML5shiv是一个库,用于在旧浏览器中启用所有新HTML5元素和节。 我们只需要将此库链接到我们的文档,并将其放入Internet Explorer条件注释中,如下所示;
<!--[if lt IE 9]>
<script type="text/javascript" src="html5shiv.js"></script>
<![endif]-->
这样,该库将仅在Internet Explorer 8及更低版本中加载 ,因为其他浏览器将不需要它。 现在,当我们在IE中查看网页时,所有元素都应具有其样式。
![html5shiv](https://assets.hongkiat.com/uploads/html5-shiv-polyfills/html5shiv-ie8-preview.jpg?newedit)
填充胶
我们通过HTML5教程多次介绍了Polyfills 。 这个术语最初是由Remy Sharp创造的,他将其描述为: “一段代码(或插件)提供了开发人员希望浏览器本机提供的技术。”
从他的描述中可以看出, Polyfills基本上具有与HTML5shiv相同的目的,但是在这种情况下,Polyfills还将模仿元素的功能。
每个新的浏览器功能都已经有了很多Polyfills, 这是完整列表 。 而且,使用Polyfills的最佳方法是将它与Modernizr一起加载,让我们看下面的示例;
Modernizr.load({
test: Modernizr.placeholder,
nope: 'placeme.js'
});
在此示例中,Modernizr 仅在证明浏览器不支持指定功能的情况下测试placeholder
功能并提供Polyfills。
使用Browserlist和Babel
如今,大多数Internet用户可能正在使用一种常绿的现代浏览器,如今这些浏览器很少需要添加polyfill来填充某些HTML5或CSS3功能。 仍然我们有时仍需要支持某些旧版本的浏览器。 但是现在,我们无需创建和加载多个polyfill脚本,而是可以使用Babel和Browserlist转换新的代码,使其与某些旧版浏览器兼容 。
首先需要在计算机上安装Node.js和NPM,并安装一些NPM模块,即@babel/cli
, @babel/core
, @babel/plugin-transform-runtime
, @babel/preset-env
和@babel/runtime
。
然后,将browserlist
配置添加到package.json
文件。 以下我们预计将支持至少2%使用率的浏览器,Internet Explorer 11和Safari 9或最新版本。
{
"name": "bable-example",
"version": "0.0.1",
"devDependencies": {
"@babel/cli": "^7.8.3",
"@babel/core": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.8.3",
"@babel/preset-env": "^7.8.3"
},
"browserslist": "> 2%, ie 11, safari >= 9",
"dependencies": {
"@babel/runtime": "^7.8.3"
}
}
现在假设我们已经编写了现代语法,例如const
关键字,arrow函数,该语法仅在现代浏览器中有效。
const foo = [ 'bar', 'baz' ];
foo.forEach((val) => console.log(val));
我们可以在下面运行此命令:
npx babel script.js --out-file script-compiled.js
该命令将创建一个新的script.js
文件到script-compiled.js
并将脚本转换为:
var foo = ['bar', 'baz'];
foo.forEach(function (val) {
return console.log(val);
});
让我们得到一个更复杂的示例,该示例在JavaScript中定义一个异步函数,例如:
async function getData() {
console.log('1');
await fetch('http://localhost:3000/foo')
.then(resp => resp.json())
.then(data => console.log(data));
console.log('2');
}
Babel会将这些代码编译成这样,以便可以在其他一些浏览器中使用,而这些浏览器也可以在某些旧版浏览器中使用:
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
function getData() {
return _getData.apply(this, arguments);
}
function _getData() {
_getData = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee() {
return _regenerator["default"].wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
console.log('1');
_context.next = 3;
return fetch('http://localhost:3000/foo').then(function (resp) {
return resp.json();
}).then(function (data) {
return console.log(data);
});
case 3:
console.log('2');
case 4:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return _getData.apply(this, arguments);
}
最后的想法
自大约十年前开始以来,Web开发已经发生了很大的变化。 当我们构建动态应用程序时,不仅是简单的静态页面,我们制作网络的方式也随着需求的发展而发展。
在这里,我们看到了Babel如何转换现代代码以与旧的浏览器兼容。 在实际项目中,您通常会将Babel集成到Webpack,Parcel,Rollup等构建工具中,并且可以查看以下参考资料以获取有关使用Babel的更多信息。