作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Juan拥有超过10年的自由用户体验经验. 他的作品植根于完美主义 & 为用户提供最好的体验.
PREVIOUSLY AT
很少有人不喜欢框架, 但即使你是他们中的一员, 您应该注意并采用使生活更轻松的功能.
我反对使用框架 in the past. 然而,最近,我有了和 React and Angular 在我的一些项目中. The first couple of times I opened my code editor and started writing code in Angular it felt weird and unnatural; especially after more than ten years of coding without using any frameworks. 过了一段时间,我决定致力于学习这些技术. 很快,一个很大的区别就显现出来了:操纵DOM非常容易, 所以在需要的时候很容易调整节点的顺序, 它不需要一页又一页的代码来构建一个UI.
尽管我仍然喜欢不依附于框架或体系结构的自由, 我不能忽视这样一个事实:在一个容器中创建DOM元素要方便得多. 所以我开始寻找在普通JS中模仿这种体验的方法. 我的目标是从React中提取出一些想法,并演示如何在普通JavaScript(通常称为vanilla JS)中实现相同的原则,以使开发人员的工作更轻松一点. 为了实现这一点,让我们构建一个简单的应用程序来浏览GitHub项目.
无论我们用哪种方式使用JavaScript构建前端, 我们将访问和操作DOM. 对于我们的应用程序, 我们需要构造每个存储库的表示(缩略图), name, and description), 并将其作为列表元素添加到DOM中. 我们将使用 GitHub Search API 来获取结果. 既然我们讨论的是JavaScript,让我们来搜索JavaScript存储库. When we query the API,我们得到以下JSON响应:
{
“total_count”:398819年,
“incomplete_results”:假的,
"items": [
{
"id": 28457823,
“名称”:“freeCodeCamp”,
:“full_name freeCodeCamp / freeCodeCamp”,
"owner": {
“登录”:“freeCodeCamp”,
"id": 9892522,
:“avatar_url http://avatars0.githubusercontent.com/u/9892522?v=4",
“gravatar_id”:“”,
:“url http://api.github.com/users/freeCodeCamp”,
“site_admin”:假的
},
“私人”:假的,
:“html_url http://github.com/freeCodeCamp/freeCodeCamp”,
description: http://freeCodeCamp.Org开源代码库”+
"and curriculum. 学习编程并帮助非营利组织.",
//更多被省略的信息
}, //...
]
}
React使得将HTML元素写入页面变得非常简单,并且是我在用纯JavaScript编写组件时一直想要的功能之一. React uses JSX,这与常规HTML非常相似.
然而,这不是浏览器读取的内容.
在底层,React将JSX转换为对a的一系列调用 React.createElement
function. 让我们看一个使用GitHub API中的一个项目的JSX示例,看看它转换成什么.
{item.name}
{item.description}
;
;
React.createElement(
"div",
{className: "repository"},
React.createElement(
"div",
null,
item.name
),
React.createElement(
"p",
null,
item.description
),
React.createElement(
"img",
{ src: item.owner.avatar_url }
)
);
JSX非常简单. 编写常规HTML代码,并通过添加大括号从对象注入数据. 括号内的JavaScript代码将被执行, 并将值插入到生成的DOM中. JSX的优点之一是React创建了一个虚拟DOM(页面的虚拟表示)来跟踪更改和更新. 而不是重写整个HTML, 每当信息更新时,React都会修改页面的DOM. 这是创建React要解决的主要问题之一.
开发人员过去经常使用jQuery. 我想在这里提到它,因为它仍然很流行,也因为它非常接近纯JavaScript的解决方案. jQuery通过查询DOM获取对DOM节点(或DOM节点集合)的引用. 它还用修改其内容的各种功能包装了该引用.
而jQuery有自己的DOM构造工具, 我在野外看到的最多的就是HTML连接. 方法将HTML代码插入到选定的节点中 html()
function. According to jQuery文档,如果我们想改变a的内容 div
节点与类 demo-container
我们可以这样做:
$( "div.demo-container”).html( "All new content.You bet!
" );
This approach makes it easy to create DOM elements; however, 当我们需要更新节点时, 我们需要查询所需的节点,或者(更常见的是)在需要更新时退回到重新创建整个代码片段.
浏览器中的JavaScript有一个内置的 DOM API 这使我们能够直接访问页面中的节点的创建、修改和删除. 这反映在React的方法中, 以及通过使用DOM API, 我们离这种方法的好处又近了一步. 我们只修改页面中实际需要更改的元素. 但是,React还跟踪一个单独的虚拟DOM. 通过比较虚拟DOM和实际DOM之间的差异, 然后React能够识别哪些部分需要修改.
这些额外的步骤有时是有用的, but not always, 而直接操作DOM会更有效率. 创建新的DOM节点 _document.createElement_
函数,该函数将返回对所创建节点的引用. 跟踪这些引用为我们提供了一种简单的方法,可以只修改包含需要更新部分的节点.
使用与JSX示例中相同的结构和数据源, 我们可以用下面的方法构造DOM:
Var item =文件.createElement (div);
item.className = 'repository';
var nameNode = document.createElement (div);
nameNode.innerHTML = item.name
item.列表末尾(nameNode);
Var description =文档.createElement(“p”);
description.innerHTML = item.description;
item.列表末尾(描述);
var image = new image ();
Image.src = item.owner.avatar_url;
item.列表末尾(图片);
document.body.列表末尾(项);
如果您唯一考虑的是代码执行的效率,那么这种方法非常好. However, 效率不仅仅是用执行速度来衡量的, 而且也便于维护, scalability, and plasticity. 这种方法的问题是它非常冗长,有时令人费解. 即使我们只是构造一个基本的结构,我们也需要编写一堆函数调用. 第二个大的缺点是创建和跟踪的变量的绝对数量. Let’s say, 您正在使用的组件包含自己的30个DOM元素, 您需要创建和使用30个不同的DOM元素和变量. 您可以重用其中的一些,并以牺牲可维护性和可塑性为代价进行一些杂耍, 但它会变得非常混乱, really quickly.
另一个明显的缺点是由于需要编写的代码行数. 随着时间的推移,将元素从一个父元素移动到另一个父元素变得越来越困难. 这是我非常欣赏React的一点. 我可以查看JSX语法,并在几秒钟内得到包含的节点, where, 并在需要时进行更改. And, 虽然乍一看这没什么大不了的, 大多数项目都有不断的变化,这将促使你寻找更好的方法.
直接使用DOM可以完成工作, 但它也使构建页面变得非常冗长, 特别是当我们需要添加HTML属性和嵌套节点时. So, 我们的想法是获得使用JSX等技术的一些好处,并使我们的生活更简单. 我们试图复制的优势如下:
下面是一个简单的函数,它可以使用一个HTML片段完成这个任务.
Browser.DOM = function (html, scope) {
//创建空节点并注入html字符串using .innerHTML
//如果变量不是字符串,我们假定它已经是一个节点
var node;
if (html.构造函数===字符串){
Var节点=文件.createElement (div);
node.innerHTML = html;
} else {
node = html;
}
//创建用户和对象,我们将为其创建变量
//指向已创建的节点
Var _scope = scope || {};
//将读取每个节点的递归函数
//包含var属性,在scope对象中添加一个引用
函数toScope(节点,作用域){
Var children = node.children;
for (var iChild = 0; iChild < children.length; iChild++) {
如果(儿童(iChild).getAttribute (var)) {
var names = children[icchild].getAttribute(“var”).split('.');
var obj = scope;
while (names.length > 0)
{
Var _property = names.shift();
if (names.length == 0)
{
obj[_property] = children[icchild];
}
else
{
if (!obj.hasOwnProperty (_property)) {
Obj [_property] = {};
}
Obj = Obj [_property];
}
}
}
toScope(儿童(iChild)、范围);
}
}
toScope(节点,_scope);
if (html.constructor != String) {
return html;
}
//如果最高层次结构中的节点是1,则返回它
if (node.childNodes.length == 1) {
//如果没有设置添加节点变量的作用域
//将我们创建的对象附加到最高层次结构节点
//添加nodes属性.
if (!scope) {
node.childNodes[0].nodes = _scope;
}
return node.childNodes[0];
}
//如果最高层次结构中的节点多于一个,则返回一个fragment
Var fragment = document.createDocumentFragment ();
Var children = node.childNodes;
//在DocumentFragment中添加注释
while (children.length > 0) {
if (fragment.append){
fragment.追加(孩子[0]);
}else{
fragment.列表末尾(孩子[0]);
}
}
fragment.nodes = _scope;
return fragment;
}
The idea is simple but powerful; we send the function the HTML we want to create as a string, 在HTML字符串中,我们将var属性添加到我们想要为我们创建引用的节点. 第二个参数是一个对象,这些引用将存储在其中. 如果没有指定,我们将在返回的节点或文档片段上创建一个“nodes”属性(如果最高层次节点多于一个)。. 一切都在不到60行的代码中完成.
该函数分为三个步骤:
那么现在呈现示例的代码是什么样子的呢?
var UI = {};
Var template = ";
template += ''
template += ' ';
template += ' '
template += '
'
template += '';
var item =浏览器.DOM(模板,UI);
UI.name.innerHTML = data.name;
UI.text.innerHTML = data.description;
UI.image.src = data.owner.avatar_url;
首先,定义对象(UI),我们将在其中存储对所创建节点的引用. 然后,我们编写将要使用的HTML模板, as a string, 用“var”属性标记目标节点. 之后,我们调用Browser函数.使用模板和将存储引用的空对象. 最后,我们使用存储的引用将数据放置在节点中.
这种方法还将构建DOM结构和将数据插入到单独的步骤中,这有助于保持代码的组织性和良好的结构. 这使我们能够分别创建DOM结构并在数据可用时填充(或更新)数据.
虽然我们中的一些人不喜欢切换到框架并交出控制权的想法, 认识到这些框架带来的好处是很重要的. 它们如此受欢迎是有原因的.
虽然框架可能并不总是适合您的风格或需求, 可以采用一些功能和技术, 模拟或有时甚至与框架解耦. 有些东西总是会在翻译中丢失, 但是,只需花费框架成本的一小部分,就可以获得和使用很多东西.
JSX是一个React组件,它简化了语法和创建HTML模板和DOM元素的过程. JSX在源代码中以HTML内联形式编写,但被音译为用于DOM构造的JavaScript指令, 这样就能两全其美.
虚拟DOM是React对DOM的表示. 通过将其与页面DOM进行比较,可以跟踪更改并仅修改页面中实际需要修改的部分, 而不是将页面的大部分排队等待解析和重新呈现.
墨西哥瓜达拉哈拉
2016年6月6日加入
Juan拥有超过10年的自由用户体验经验. 他的作品植根于完美主义 & 为用户提供最好的体验.
PREVIOUSLY AT
世界级的文章,每周发一次.
世界级的文章,每周发一次.
Join the Toptal® community.