【问题标题】:In Ionic 3 how do I open all links from dynamically fetched HTML in System Browser?在 Ionic 3 中,如何从系统浏览器中动态获取的 HTML 打开所有链接?
【发布时间】:2018-02-28 11:06:41
【问题描述】:

我正在基于以下Ionic Wordpress App Template 制作一个可与 WP Rest API 配合使用的 Ionic 应用程序。

有一个页面将帖子列表加载为一个对象数组,其中包含由 Wordpress 呈现的帖子的 HTML。

Wordpress Service 的摘录

let url = this.config.wordpressApiUrl + `/wp/v2/posts?${query}&_embed`;
return this.http.get(url)
    .map(result => {
        return result.json();
    });

Wordpress Posts Component 的摘录

export class WordpressPosts implements OnInit {

    posts: any;
    //...
    ngOnInit() {
        this.wordpressService.getPosts()
            .subscribe(
                result => this.posts = result
            );
    }

然后将呈现的 HTML 插入到 DOM 中

Worpress Post HTML 的摘录

<ion-card text-wrap *ngIf="post.content.rendered">
    <p id="postContent" padding [innerHtml]="post.content.rendered"></p>
</ion-card>

我希望将 innerHTML (post.content.rendered) 中的所有链接都用 (click)="openLink($1)" 替换为 openLink() 函数:

openLink(url) {
    window.open(url, '_system');
}

它非常适合在系统浏览器(Chrome 或 Safari)中打开链接,而不是在 InAppBrowser 或更糟糕的情况下,在替换它的应用程序内部。

在 AngularJS 中,我本可以使用 $compile,但因为在 Angular 4 中我不知道有任何替代方法。有没有办法在将 HTML 代码放入 DOM 之前手动调用该 HTML 代码上的 Angular 模板编译器?还是有其他方法可以在系统浏览器中打开该 HTML 中的所有链接?

【问题讨论】:

标签: angular ionic3


【解决方案1】:

将目标属性添加到链接应该可以工作。

<a target="_system" href="http://www.stackoverflow.com">Stack Overflow</a>

如果它不起作用,你有两个额外的选择,而无需编译 Angular。

两个选项的 HTML:

<div #dynamic></div>

选项 1

拥有一组锚元素并将 onclick 事件分配给所有元素。

export class MyPage {
  @ViewChild('dynamic') dynamic: ElementRef;

  constructor() {
    setTimeout(() => {
      let text = '<a href="http://www.stackoverflow.com">Stack Overflow</a>';

      let el = this.dynamic.nativeElement as HTMLElement;
      el.innerHTML = text;
      let arrayOfLinks = el.querySelectorAll('a');;
      for (let i = 0; i < arrayOfLinks.length; i++) {
        let anchor = arrayOfLinks[i];
        anchor.onclick = function(ev) {
          window.open(anchor.href, '_system');
          ev.preventDefault();
          return false;
        };
      };
    }, 1000);
  }

}

选项 2

拥有一个全局 onclick 处理程序并将 HTML 上的 onclick 分配给锚元素。

export class MyPage {
  @ViewChild('dynamic') dynamic: ElementRef;

  constructor() {
    setTimeout(() => {
      let text = '<a onclick="openInNewBrowser()" href="http://www.stackoverflow.com">Stack Overflow</a>';

      let el = this.dynamic.nativeElement as HTMLElement;
      el.innerHTML = text;
    }, 1000);
  }

}

应用中任意位置的全局方法:

window['openInNewBrowser'] = function () {
  let anchor = event.target;
  window.open(anchor['href'], '_system');
  event.preventDefault();
  return false;
}

【讨论】:

  • 我在这里发布之前尝试了第二个解决方案(我不知道如果我通过 jQuery 这样做是否会改变某些东西)我在 script 标签中添加了 JS,并用 window.addEventListener('load', function() { ... } ); 它包围不工作,链接一直在我的 Ionic 应用程序或 InAppBrowser 中打开,而不是在系统浏览器中打开
  • 为什么动态编译 Angular 模板是一种不好的做法?它不是比简单地注入来自目标 div 内的服务器的 HTML 代码完全绕过 Angular 模板引擎更干净吗?如果有办法在将 HTML 注入 div 之前将其注入到 $compile() 中,这正是我所追求的解决方案
  • @KiJéy 我不知道这是否是一种不好的做法,但您可能必须在您的应用程序中包含 Angular 编译器。这会增加您的应用程序大小。我认为您的情况太琐碎,无法采用该解决方案。至于为什么解决方案不起作用,您确定窗口加载脚本运行吗?因为它应该只在页面加载时运行。不是子 DOM 树。
  • 我已经更新了我的问题以更清晰。另外,您能否向我解释一下您使用 @HostListener 的解决方案?我应该把那个代码放在哪里?谢谢
  • @KiJéy (click) 是一个 Angular 的东西,就像我的指令一样。您的模板需要由 Angular 编译才能让 Angular 工作。我不知道一个简单的方法来做到这一点。但是您可以使用onclick 来代替(click),它是一个纯HTML 属性,具有全局函数,例如:function openLink() { window.open(event.target.href, '_system'); return false; }
【解决方案2】:

您如何使用DOMParser,它是一个实验性的 WebApi。您可以解析 html,然后将其推送到查看(可能在 NgZone 中)。您可以在MDN 中找到基本示例:

var parser = new DOMParser();
var doc = parser.parseFromString(stringContainingHTMLSource, "text/html");

然后提取锚标签:

let aElements = doc.getElementsByTagName("a");
for (let i = 0; i < aElements.length; i++) {
  console.log(aElements[i].innerHTML);
}

所以基本上一旦您可以访问a 元素,您就可以更改其属性。 例如要附加一个新闻事件(你必须尝试点击事件,我只尝试过从组件按下),请遵循:

for (let i = 0; i < aElements.length; i++) {
      this.pressGesture = new Gesture(aElements[i].innerHtml);
        this.pressGesture.listen();
        this.pressGesture.on('press', e => { 
            console.log('testing');
        });
}

您必须使用代码,我没有测试过此代码,但它应该可以工作。使用手势,您可以绑定任何原生事件。检查这个 youtube video
其他选项是创建全局事件侦听器并在系统浏览器中打开链接。但是要解决 iOS,您需要使用 InAppBrowser。 安装InAppBrowser,在index.html中使用如下代码

document.body.addEventListener('click', function (event) {
          if(event.srcElement.target == '_system' || event.srcElement.target == '_blank') {
              var url = this.href;
              window.open(url,"_system");
          }
  });

【讨论】:

  • 这有什么帮助?
  • 我已经可以访问所有a 元素,问题是如何添加能够调用控制器中定义的函数的Angular (click) 属性?
  • @KiJéy 检查我更新的答案。使用手势,你可以绑定事件。
  • 问题是仅仅在链接上添加target="_system" 是行不通的。在将代码注入目标 div 之前,我已经通过 regExp 尝试过,我需要通过 (click)(Angular2 的 ng-click)调用控制器中定义的函数
  • @KiJéy 在全局文件中定义了此代码,即index.html。我试过这个,它对我有用,但我在 ionic 1 项目中尝试过。由于它的 JavaScript,所以它应该与 ionic 2 或 3 相同。制作一个演示项目并在 github 或 jsfiddle 上分享会很有帮助
【解决方案3】:

Angularjs 内置了 jquery,所以你可以尝试像下面这样附加一个事件处理程序

$('a').on('click', function(evt) {
  evt.preventDefault();
  var link = $(this).attr('href');
  window.open('link');
});

您可以在将 html 嵌入到 ajax 回调甚至 init 中后附加它。

【讨论】:

  • 是的,但我忘了问你是否在项目中导入 jquery,否则你也可以用纯 javascript 编写。
  • 这不适用于动态元素,因为a 稍后会添加...您需要事件委托...
猜你喜欢
  • 2023-03-09
  • 1970-01-01
  • 2014-02-19
  • 1970-01-01
  • 2017-08-21
  • 2015-09-23
  • 2021-09-29
  • 1970-01-01
  • 2017-01-12
相关资源
最近更新 更多