这是一个关于Angular 2选择器、自定义标签与自定义属性、SEO和浏览器渲染的问题。
当我第一次开始查看Angular 2时,在跟踪他们的快速启动时,我做的第一件事就是将选择器更改为'[my-component]'
(属性选择器)而不是'my-component'
(标记选择器),这样我就可以在HTML中使用<div my-component></div>
而不是<my-component></my-component>
,这是无效的HTML。所以我会按照标准编写HTML。好吧,至少相当接近标准(因为my-component
不是一个有效的HTML属性,但我只能忍受HTML验证错误)
然后,在YouTube上的一段视频中,angular团队的某个人提到,我们应该使用标签选择器,至少在性能方面是这样。
好吧,我说,该死的HTML验证。。。还是我不应该
因此:
-
假设我忽略W3C对我的HTML由于
<custom-tags>
而完全无效的尖叫。事实上,我还有另一个更大、更真实的担忧:这对SEO有何影响
我的意思是,不要只考虑客户端应用程序,因为在现实世界中(对于我的angular 2项目也是如此),我也有服务器端渲染,这有两个非常重要的原因:SEO和在应用程序启动之前,为用户提供网站的快速初始渲染。否则你不可能有一个流量很高的SPA
当然,无论我使用什么标签,谷歌都会抓取我的网站,但在两种情况下,它的排名是否相同:一种是<custom-make-believe-tags>
,另一种只有标准HTML标签? -
让我们谈谈浏览器和CSS:
当我开始在Angular 2中构建我的第一个SPA站点时,我立即面临另一个问题:
假设(在非SPA站点中)我有以下HTML标记:
<header>
<a class="logo">
...
</a>
<div class="widgets">
<form class="frm-quicksearch"> ... </form>
<div class="dropdown">
<!-- a user dropdown menu here -->
</div>
</div>
</header>
<div class="video-listing">
<div class="video-item"> ... </div>
<div class="video-item"> ... </div>
...
</div>
角度2方面,我会有以下组件树:
<header-component>
<logo-component></logo-component>
<widgets-component>
<quicksearch-component></quicksearch-component>
<dropdown-component></dropdown-component>
</widgets-component>
</header-component>
<video-listing-component>
<video-item-component></video-item-component>
...
</video-listing-component>
现在,我有两个选择。让我们以<video-listing-component>
为例,保持简单。。。我要么
A)将我已经拥有的整个标准HTML标记(<div class="video-item"></div>
)放置在<video-item-component>
标记中,一旦渲染,将产生以下结果:
<video-listing-component>
<div class="video-listing>
<video-item-component>
<div class="video-item>...</div>
</video-item-component>
...
...
</div>
</video-listing-component>
或:
B)只将<div class="video-item">
的内容直接放入我的<video-item-component>
组件中,并在组件标签上添加所需的类(class="video-item"
)以进行样式设置,结果如下:
<video-listing-component class="video-listing">
<video-item-component class="video-item"></video-item-component>
<video-item-component class="video-item"></video-item-component>
...
</video-listing-component>
无论哪种方式(A或B),浏览器都会将一切渲染得很好
但是,如果仔细观察(当然,在DOM中呈现所有内容之后),默认情况下,自定义标记不会占用DOM中的任何空间。它们是0px乘0px。只有它们的内容占据了空间。我不明白为什么浏览器仍然按照你想要的方式呈现所有内容,我的意思是在第一种情况下(A):
虽然div class="video-item"
上有float: left; width: 25%;
,但这些div中的每一个都在一个<video-item-component>
标签中,该标签没有任何样式。。。浏览器按照您的期望呈现所有内容,这难道不是一个幸运的副作用吗?所有的<div class="video-item">
相邻浮动,即使它们都在另一个标签内,没有浮动的<video-item-component>
:左?我已经在IE10+、Firefox、Chrome上进行了测试,一切都很好。这是幸运的吗?还是对此有一个可靠的解释,我们可以放心地相信,所有(或至少大多数)浏览器都会像我们所期望的那样呈现这种标记?
第二种情况(B):
如果我们直接在自定义标记(<video-item-component>
)上使用类和样式。。。再说一遍,一切都很好。但据我所知,我们不应该设计自定义组件的样式,对吧?这不也是一个幸运的预期结果吗?或者这也可以吗?我不知道,也许我还活在2009年…是吗
这两种方法(A或B)中的哪一种是推荐的方法?还是两者都很好?
我不知道
由于我的div有float:left,这就是为什么它们所封装的(自定义或非自定义)标签不会扩展它的高度。自从我开始研究Angular 2以来,我似乎已经忘记了CSS是如何工作的。
但有一件事仍然存在:
如果我在块元素上设置一个百分比宽度(称为E),我会假设它占用直接父元素的x%。如果我设置float:left,我希望在直接父级中浮动。在A的情况下,由于直接父标记是一个没有显示类型和宽度的自定义标记,我希望事情会以某种方式中断,但仍然。。。我的E元素的行为就像它们的父元素不是它们各自封装的自定义标记,而是DOM中的下一个标记(在我的例子中是<div class="video-listing>
)。它们占据了其中的x%,并在其中浮动。我不认为这是正常的,我认为这只是一个幸运的效果,我担心有一天,在浏览器更新后。。。我醒来后会发现我所有的Angular 2网站看起来都完全崩溃了。
所以。。。A和B都是同样合适的方法吗?还是在A的情况下我做错了?
EDIT2:
让我们稍微简化一下。当我得到部分问题的答案时,让我们举另一个生成HTML的例子(简化了一点,使用内联CSS):
<footer>
<angular-component-left>
<div style="float: left; width: 50%;">
DIV CONTENT
</div>
</angular-component-left>
<angular-component-right>
<div style="float: left; width: 50%;">
DIV CONTENT
</div>
</angular-component-right>
</footer>
在最初尚未实现的HTML中(如果没有<angular-component-...>
,这些div应该向左浮动,每个div占据<footer>
的50%。令人惊讶的是,一旦它们被<angular-component-...>
自定义标签包裹起来,它们也会做同样的事情:占据页脚的50%。但这对我来说似乎是好运,愚蠢的运气…意外的效果。
那么,这是"愚蠢的运气"吗?
如果我这样写,或者重写,而不是上面的代码,我会有这样的东西:
<footer>
<angular-component-left style="display: block; float: left; width: 50%;">
DIV CONTENT
</angular-component-left>
<angular-component-right style="display: block; float: left; width: 50%;">
DIV CONTENT
</angular-component-right>
</footer>
注意,为了简单起见,这里引入了内联样式,实际上我会有一个类,它将位于文档的<head>
中包含的外部CSS文件中,而不是通过角度组件的style
或styleUrls
。
问题在于HTML验证器。元素名称中的-
是被视为自定义元素的元素所必需的,并且它是有效的HTML5。Angular在元素名称中不需要-
,但这是一种很好的做法。
例如检查https://www.w3.org/TR/custom-elements/#registering-自定义元素(搜索x-foo
)或https://w3c.github.io/webcomponents/spec/custom/#custom-元素自定义标记示例。我确信这个破折号规则是在某个地方指定的,但找不到规范。例如,它在Polymer中是必需的,这取决于元素是正确的自定义元素,而在Angular中这并不重要。据我所知,唯一的区别是,当您查询元素时,当名称中缺少-
时,您会得到HTMLUnknownElement
,而当名称中包含-
时,您将得到HTMLElement
。
另请参阅我几年前问的这个问题:为什么Angular在组件名称中不需要破折号
但如果仔细观察,默认情况下,自定义标记不会占用dom中的任何空间。它们是0px乘0px。只有它们的内容占据了空间。我只是不明白为什么浏览器仍然渲染所有你想看到的
我不确定我是否理解这个问题。Angular处理模板时会动态添加内容。当您在浏览器中看到内容时,它在DOM中也可用,并且具有实际的维度。
搜索引擎爬网程序能够处理由JavaScript生成的页面。如果这还不够,服务器端呈现的页面可以向包含整个视图的爬网程序提供静态HTML。