前言
本功能的主要作用是通过url,将第三方的页面直接嵌入APP中,当成原生页面来展示。这样既可以方便与第三方集成,也避免了自己进行重复开发。
本功能的基本设计思路就是先封装一个自己的浏览器模块,用iframe的形式实现。然后需要展示第三方url时就跳转到该模块,用iframe将url展示出来。这样的话就不需要每个地方都自己写一遍brower模块了,可以最大化进行代码复用。
步骤
1、通用browser模块的开发
browser.html
<ion-header no-shadow>
<ion-navbar class="page-navbar">
<ion-title>{{browser.title}}</ion-title>
<ion-buttons end>
<button ion-button icon-only (click)="presentPopover($event)">
<ion-icon name="more"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content class="content"> <!--scroll="true" overflow-scroll="true"-->
<div class="progress" [hidden]="browser.isLoaded || browser.isWechatPage">
<div class="progress-inner" id="progress"></div>
</div>
<iframe id="iframe" class="iframe"
sandbox="allow-scripts allow-top-navigation allow-pointer-lock allow-same-origin allow-popups allow-forms"
[src]="browser.secUrl"
(load)="loaded()"
[ngClass]="{'logisticsPrice': browser.isLogisticsPrice}"
*ngIf="!browser.isWechatPage">
</iframe>
<div *ngIf="browser.isWechatPage" [innerHtml]="browser.innerHtml">
</div>
</ion-content>
browser.sccc
page-browser {
$progress-height: 0.2rem;
$progress-bg: #77b6ff;
/*.scroll-content {
overflow: hidden;
}*/
.content {
height: 100%;
}
.progress{
position: absolute;
top: 0;
right: 0;
left: 0;
height: $progress-height;
background: #f5f5f5;
z-index: 200;
.progress-inner{
width: 0;
background: $progress-bg;
position: absolute;
top: 0;
left: 0;
bottom: 0;
box-shadow: 0 0 10px rgba(119,182,255,0.7);
-webkit-transition: width 0.4s ease;
transition: width 0.4s ease;
}
}
.iframe {
width: 100%;
height: 100%;
position: absolute;
overflow: auto;
border: none;
}
.logisticsPrice{
height: 120%;
margin-top: -70px;
}
}
browser.ts
import { Component } from '@angular/core';
import { NavController, NavParams, PopoverController } from 'ionic-angular';
import { DomSanitizer } from "@angular/platform-browser";
import {BrowserPopoverPage} from "./browser-popover";
import {Helper} from "../services/helper.service";
@Component({
selector: 'page-browser',
templateUrl: 'browser.html'
})
export class BrowserPage {
browser: any = {
isLoaded: false, // 网页是否被加载
proObj: null, // 进度条对象
progress: 0, // 网页访问的进度条
secUrl: '', // 安全链接
innerHtml: '',
title: '加载中',
url: '',
isWechatPage: false,
isLogisticsPrice: false,
share: null // 是否具有分享功能(传递一个分享对象ShareModel过来)
};
shareConfig: any = {
isShow: false
}; // 分享控制的配置
constructor(public navCtrl: NavController,
private params: NavParams,
private sanitizer: DomSanitizer,
private helper: Helper,
private popoverCtrl: PopoverController) {
let browser = this.params.get('browser');
if(browser) {
this.browser.title = browser.title;
this.browser.isWechatPage = browser.isWechatPage;
this.browser.isLogisticsPrice = browser.isLogisticsPrice;
if(browser.isWechatPage){
this.helper.getResponseFromUrl(browser.url)
.then(ret => {
let html = ret.text();
this.browser.innerHtml = this.sanitizer.bypassSecurityTrustHtml(html);
}
);
} else {
this.browser.url = browser.url;
this.browser.secUrl = this.sanitizer.bypassSecurityTrustResourceUrl(browser.url);
}
if(browser.share) {
this.browser.share = browser.share;
}
} else {
this.browser.secUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.browser.url);
}
if(!browser.isWechatPage){
this.reload();
}
}
ionViewDidLoad() {
if(!this.browser.proObj) {
this.browser.proObj = document.getElementById('progress');
}
this.onprogress();
}
// 生成随机数
private random(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1) + min);
}
// 网页访问进度
private onprogress() {
// 随机时间
let timeout = this.random(10, 30);
let timer = setTimeout(() => {
if(this.browser.isLoaded) {
this.browser.proObj.style.width = '100%';
clearTimeout(timer);
return;
}
// 随机进度
this.browser.progress += this.random(1, 5);
// 随机进度不能超过 90%,以免页面还没加载完毕,进度已经 100% 了
if(this.browser.progress > 90){
this.browser.progress = 90;
}
this.browser.proObj.style.width = this.browser.progress + '%';
this.onprogress();
}, timeout);
}
// 如果iframe页面加载成功后
loaded() {
this.browser.isLoaded = true;
}
// 显示Popver选项
presentPopover(myEvent) {
let cb = {
refresh: () => {
this.reload();
},
close: () => {
this.navCtrl.pop();
},
share: null
};
if(this.browser.share) {
cb.share = () => {
this.share();
}
}
let popover = this.popoverCtrl.create(BrowserPopoverPage, {
callback: cb
});
popover.present({
ev: myEvent
});
}
// 重新加载页面
reload() {
let title = this.browser.title;
let url = this.browser.secUrl;
this.browser.title = '加载中';
this.browser.secUrl = this.sanitizer.bypassSecurityTrustResourceUrl('');
setTimeout(() => {
this.browser.isLoaded = false;
this.browser.progress = 0;
if(!this.browser.proObj) {
this.browser.proObj = document.getElementById('progress');
}
this.onprogress();
this.browser.title = title;
this.browser.secUrl = url;
}, 10);
}
// 分享页面(作为popover的回调)
share() {
this.shareConfig.isShow = true;
/*if(this.browser.share) {
SocialSharing.share(this.browser.share.title, this.browser.share.content, '', this.browser.share.url).then(() => {
}, (err) => {
// Error!
alert('错误:分享失败!' + err);
});
}*/
}
}
3、需要使用的模块导入brower模块
2、使用brower模块进行url展示
gotoLogisticsPricePage() {
this.navCtrl.push(BrowserPage, {
browser: {
title: '查运价',
url: 'http://shipper.huodada.com/freight/list.shtml?startProvince=%E9%99%95%E8%A5%BF%E7%9C%81&startCity=%E6%A6%86%E6%9E%97%E5%B8%82&startCountry=%E7%A5%9E%E6%9C%A8%E5%8E%BF&endProvince=&endCity=&endCountry='
}
});
}
最后
值得注意的一点是,因为微信公众的url不能直接放在iframe里面进行展示,所以使用了div的[innerHtml]="browser.innerHtml"属性,避免了被屏蔽。