【问题标题】:How "safe" are Angular 2 custom html tags? (selectors: Custom tags vs. Custom attributes)Angular 2 自定义 html 标签有多“安全”? (选择器:自定义标签与自定义属性)
【发布时间】:2016-05-15 15:48:27
【问题描述】:

这是一个关于 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 验证...还是不应该?
所以:

  1. 假设由于<custom-tags>,我忽略了 W3C 对我的 html 完全无效的尖叫。实际上,我还有另一个更大更真实的担忧:这对 SEO 有何影响?
    我的意思是不要只考虑客户端应用程序,因为在现实世界中(以及我的 angular 2 项目)我也有服务器端渲染,原因有两个:SEO 和在应用启动之前,快速初始呈现网站给用户的初始视图。否则,您不能拥有非常高流量的 SPA。
    当然,无论我使用什么标签,谷歌都会抓取我的网站,但它在两种情况下的排名是否相同:一种使用 <custom-make-believe-tags>,另一种仅使用标准 html 标签?

  2. 让我们谈谈浏览器和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>

Angular 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>

现在,我有两个选择。让我们以&lt;video-listing-component&gt; 为例,为了保持简单...我要么
A) 将我已经拥有的整个标准 html 标记 (&lt;div class="video-item"&gt;&lt;/div&gt;) 放在 @987654332 中@标签,并且一旦渲染将导致:

<video-listing-component>
    <div class="video-listing>
        <video-item-component>
            <div class="video-item>...</div>
        </video-item-component>
        ...
        ...
    </div>
</video-listing-component>

B) 仅将 &lt;div class="video-item"&gt; 的内容直接放入我的&lt;video-item-component&gt; 组件中,并在组件标签上添加所需的类(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>

无论哪种方式(AB),浏览器都可以正常呈现所有内容。
但是,如果您仔细查看(当然,在所有内容都在 dom 中呈现之后),默认情况下自定义标签不会占用 dom 中的任何空间。它们是 0px x 0px。只有它们的内容占据空间。我不明白为什么浏览器仍然呈现您希望看到的所有内容,我的意思是在第一种情况下(A):
虽然在div class="video-item" 上有float: left; width: 25%;,但是这些 div 中的每一个都在 within 一个 &lt;video-item-component&gt; 标签中,它没有任何样式......这不只是一个幸运的一面 -浏览器会按照您的预期呈现所有内容吗?随着所有&lt;div class="video-item"&gt; 浮动在彼此旁边,即使它们每个都在另一个标签内,&lt;video-item-component&gt; 没有浮动:左?我已经在 IE10+、Firefox、Chrome 上测试过,一切正常。只是幸运还是对此有可靠的解释,我们可以安全地依赖所有(或至少大多数)浏览器所期望的这种标记来呈现?

第二种情况(B):
如果我们直接在自定义标签 (&lt;video-item-component&gt;) 上使用类和样式......再次,一切都很好。但据我所知,我们不应该设置自定义组件的样式,对吧?这不也是一个幸运的预期结果吗?或者这也可以吗?我不知道,也许我还活在 2009 年……是吗?
这两种方法(AB)中的哪一种是推荐的方法?还是两者都很好?

我不知道!!

编辑
哦,谢谢 Günter Zöchbauer。是的,因为我的 div 有浮动:左,这就是为什么他们包裹的(自定义或非自定义)标签不会扩展它的高度。自从我开始研究 Angular 2 以来,似乎我已经忘记了 css 的工作原理:)
但是还有一件事:
如果我在块元素上设置百分比宽度(称为 E),我会假设它占它 直接父级的 x%。如果我设置浮动:左,我希望在直接父级内浮动。在我的 A 案例中,由于直接父级是没有显示类型和宽度的自定义标签,我希望事情会以某种方式中断,但仍然......我的 E 元素的行为就像它们的父级一样不是它们各自包含的自定义标签,而是 dom 中的下一个标签(在我的例子中是 &lt;div class="video-listing&gt;)。它们占据了其中的 x%,并且在其中浮动。我不认为这是正常的,我认为这只是一个幸运的效果,而且我担心有一天,在浏览器更新之后......我会醒来发现我所有的 Angular 2 网站看起来都完全破碎的。

那么... AB 都是同样合适的方法吗?还是我做错了,以防 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 中(没有 &lt;angular-component-...&gt;,这些 div 应该向左浮动并且每个占据 &lt;footer&gt; 的 50%。令人惊讶的是,一旦它们被包裹在 &lt;angular-component-...&gt; 自定义标签中,它们就会相同:占据页脚的 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>

请注意,为简单起见,此处引入了内联样式,实际上我将有一个类,而不是在我的文档的 &lt;head&gt; 中包含的外部 css 文件中,而不是通过我的 stylestyleUrls角度分量。

【问题讨论】:

  • 我不太明白 A 和 B 之间应该表现出什么本质区别。
  • 我只是在问 A 或 B 中的哪一个是正确的方法。如果 A 发生的情况符合浏览器的预期,或者只是幸运。有一天,我醒来发现这种意外效果已在所有浏览器中得到修复,我的网站看起来很糟糕。另外,我主要做 html/css。我无法将我的头包裹在自定义标签上,更不用说样式化它们了。在我看来,它们简直是不自然的。大多数客户要做的第一件事就是将我生成的任何 html 粘贴到验证器中并说:看,我有警告或错误。我们需要解决这些问题。我必须解决这些问题。
  • 我不是从开发人员的角度思考,而是从将设计实现到 html/css 的人的角度思考。我说的是渲染结果,而不是角度或幕后发生的事情。
  • 我不明白 A 和 B 之间的区别是什么。自定义元素是普通的 HTML,它只是在运行时扩展为完整的 HTML。这种方式更容易创建可重用的片段并允许获取范围样式,这是通过 Angular 重写 CSS 的选择器以仅匹配添加到组件元素的唯一属性(默认)或利用影子 DOM 样式范围(使用Native封装模式)。
  • 您可以将&lt;angular-component-left&gt; 视为具有自定义名称的&lt;div&gt;。如果&lt;angular-component-left&gt;是一个Angular组件,那么组件中指定的template将作为innerHTML添加到&lt;angular-component-left&gt;中。

标签: css angular seo html-validation angular2-components


【解决方案1】:

问题在于您的 HTML 验证器。元素名称中的 - 是元素被视为自定义元素所必需的,并且它是有效的 HTML5。 Angular 在元素名称中不需要 -,但这是一种很好的做法。

检查例如https://www.w3.org/TR/custom-elements/#registering-custom-elements(搜索x-foo)或https://w3c.github.io/webcomponents/spec/custom/#custom-elements-custom-tag-example。我确定这个破折号规则是在某处指定的,但无法找到规范。例如,在 Polymer 中需要依赖元素是适当的自定义元素,而这在 Angular 中并不重要。据我所知,唯一的区别是,当您查询元素时,当名称中缺少- 时,您会得到一个HTMLUnknownElement,而当它包含- 时,您会得到一个HTMLElement

也可以看看我几年前问过的这个问题Why does Angular not need a dash in component name

但是,如果您仔细观察,默认情况下自定义标签不会占用 dom 中的任何空间。它们是 0px x 0px。只有它们的内容占据空间。我只是不明白为什么浏览器仍然呈现您希望看到的所有内容

我不确定我是否理解这个问题。当 Angular 处理模板时,它会动态添加内容。当您在浏览器中看到内容时,它在 DOM 中也可用并且具有实际尺寸。

搜索引擎爬虫能够处理由 JavaScript 生成的页面。如果这还不够,服务器端呈现的页面可以为包含整个视图的爬虫提供静态 HTML。

【讨论】:

  • >它们是 0px x 0px 我的意思是自定义标签在浏览器的视口中是 0px x 0px,它不会像标准的 html 标签那样明显地扩展到它的内容大小。我知道,使它具有大小的唯一方法是显式地给它一个显示类型(块/内联块)以及宽度和高度。但是,在 A 的情况下,它怎么会起作用呢?浏览器是否明确且完全忽略了自定义标签,或者它只是一个幸运的副作用?为什么我的 div 仍然彼此相邻浮动,而实际上它们每个都在另一个没有浮动的单独元素中:左。运气不好还是我们可以依靠它?
  • 如果display 未设置为block,则它们的行为类似于&lt;span&gt; 元素。 inline-block 是默认的 display 值 AFAIR。没有什么特别的。或者 Angular 组件或自定义元素的神奇之处。它们的行为与具有相同样式设置的任何其他元素一样(如提到的display)。如果你启用ViewEncapsulation.Native,组件视图会在已经支持它的浏览器中被包裹在一个影子DOM中,但这也没什么特别的,因为像&lt;input&gt;&lt;video&gt;这样的原生元素……也将它们的视图隐藏在一个阴影中DOM。
  • 这里解释的大概是stackoverflow.com/questions/9024494/…
  • 天啊! :) 感谢那。我已经编辑了我的问题并在最后添加了一段。
  • 我没有这么深的 CSS 知识。我可以肯定地说 Angular 并没有做任何特别的事情。它只是通过 JavaScript 添加到 DOM 的具有自定义名称的 HTML 元素。一些特殊的东西,比如绑定 [attr.prop]="xxx" 在添加到 DOM 之前由 Angular 解析。此类属性永远不会按原样添加到 DOM 中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多