0

我有一个 Angular 12 应用程序,我正在尝试使用 LTR 和 RTL 语言(例如分别为英语和阿拉伯语),最终用户可以在使用该应用程序时选择和应用它。Bootstrap - 我用于 UI 样式 - 要求我在 HTML 元素上设置 dir 属性,并且当我想显示阿拉伯文本时,我需要从原始 LTR CSS 文件中引用一个单独的 RTL CSS 文件。

我以为我可以像这样设置我的index.html

<app-root></app-root>

然后让我的app-component.html生成 HTML、HEAD、LINK 和 BODY 元素等,如下所示:

<!doctype html>
<html [lang]="lang" [dir]="dir">

<head>
  <meta charset="utf-8">
  <title>{{title}}</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link *ngIf="dir != 'rtl'" href="/assets/styles/bootstrap.css" rel="stylesheet" />
  <link *ngIf="dir == 'rtl'" href="/assets/styles/bootstrap.rtl.css" rel="stylesheet" />
  <script type="text/javascript" src="/assets/lib/jquery/jquery-3.3.1.min.js"></script>
  <script type="text/javascript" src="/assets/scripts/bootstrap5.min.js"></script>
</head>

<body>
  <router-outlet></router-outlet>
</body>

</html>

然而,当我尝试这种布局时,Bootstrap 菜单(和其他与 JavaScript 动作相关的样式)停止工作。我注意到现在,当 Chrome 获取index.html时,Angular 已经在元素之前插入了它的引导脚本。app-root

<link rel="stylesheet" href="styles.css">
<script src="runtime.js" defer></script>
<script src="polyfills.js" defer></script>
<script src="styles.js" defer></script>
<script src="vendor.js" defer></script>
<script src="main.js" defer></script>
<app-root></app-root>

我还从 DevTools Elements 视图中注意到 Chrome 已将我的 HTML 元素嵌套在app-root它自己创建的文档的元素中。

<html>
  <head>
    <link rel="stylesheet" href="styles.css">
    <script src="runtime.js" defer=""></script>
    <script src="polyfills.js" defer=""></script>
    <script src="styles.js" defer=""></script>
    <script src="vendor.js" defer=""></script>
    <script src="main.js" defer=""></script>
  </head>
  <body>
    <app-root _nghost-tyi-c80="" ng-version="12.0.5">
      <html _ngcontent-tyi-c80="" lang="en" dir="ltr">
        <head _ngcontent-tyi-c80="">
          <meta _ngcontent-tyi-c80="" charset="utf-8">
          ...
        </head>
        ...
      </html>
    </app-root>
  </body>
</html>

DevTools 中元素视图的片段

如果我恢复我的更改,那么 Chrome 会获取index.html,我会看到 Angular在元素之后和结束标记之前插入其引导脚本。Bootstrap 喜欢这个并且菜单再次开始工作,但我无法动态选择发出哪个 LTR 或 RTL CSS 链接,以及 HTML 元素是否具有有意义的 LANG 和 DIR 属性,以及对 HEAD 元素(如页面标题)的任何其他更改。app-rootbody

原始 index.html

<!doctype html>
<html lang="en" dir="ltr">

<head>
  <meta charset="utf-8">
  <title>Snappy Title Goes Here</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link href="/assets/styles/bootstrap.css" rel="stylesheet" />
  <script type="text/javascript" src="/assets/lib/jquery/jquery-3.3.1.min.js"></script>
  <script type="text/javascript" src="/assets/scripts/bootstrap5.min.js"></script>
</head>

<body>
  <app-root></app-root>
</body>

</html>

Chrome 看到的内容:

<!doctype html>
<html lang="en" dir="ltr">

<head>
  <meta charset="utf-8">
  <title>Snappy Title Goes Here</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link href="/assets/styles/bootstrap.css" rel="stylesheet" />
  <script type="text/javascript" src="/assets/lib/jquery/jquery-3.3.1.min.js"></script>
  <script type="text/javascript" src="/assets/scripts/bootstrap5.min.js"></script>
  <link rel="stylesheet" href="styles.css">
</head>

<body>
  <app-root></app-root>
  <script src="runtime.js" defer=""></script>
  <script src="polyfills.js" defer=""></script>
  <script src="styles.js" defer=""></script>
  <script src="vendor.js" defer=""></script>
  <script src="main.js" defer=""></script>
</body>

</html>

动态更改这些 HTML 和 HEAD 相关属性和元素的正确方法是什么,以免 Chrome 混淆?

4

1 回答 1

0

您可以index.html通过一项更改保留原始内容,将标签添加dir-change到引导样式表,以便以后找到它。

<link href="/assets/styles/bootstrap.css" dir-change/>

然后在app.component.ts将更新此链接和方向的添加方法中

 changeDirection(dir: 'ltr'| 'rtl'): void {
   const attrName = 'dir-change'
   const originalLink = document.querySelector(`[${attrName}]`);
   const linkAddress = dir === 'ltr' ?
    "/assets/styles/bootstrap.css"
    :"/assets/styles/bootstrap.rtl.css";
   (originalLink as HTMLLinkElement).href = linkAddress;
   document.dir = dir;
 }
于 2022-01-27T18:18:16.137 回答