背景:公司前端开发一直使用angular,后公司想开发移动app应用,便考虑使用Ionic angular使用。项目快结束时上级领导决定不做app,做移动端适配,emmm.....
大的问题不说了,网上都有,说下遇到的奇葩需求;由于使用Ionic框架,用一个做app的框架做了移动端适配,总是有点感觉在浏览器里面套了一个浏览器在装我们的页面,web原来是div高度撑出浏览器显示高度浏览器出现滚动条,但是使用这个确认Ionic有自己的想法,看前端的层级目录发现,在body下上来就是app-root根路径,根路径下就是ion-app,而这个ion-app就限定了高度和手机屏幕高度一致,如图(1-1)所示,即无论ion-app里面页面高如如何都不可能撑出浏览器高度,都会在里面出现滚动条,即对于部分浏览器支持当页面高度撑出浏览器后下滑隐藏浏览器功能键使用该开发的移动web端无法实现,单是需求就是:在不改变使用框架的情况下需要实现下拉隐藏浏览器功能菜单功能;尽管心中一万*在奔腾,但还是要做;
图(1-1)
思路:既然是该ion-app限制了高度,是的内部的ion-content也与其高度保持了一致,那么我将ion-app的高度设置成当前页面的高度,则就可以撑出浏览器高度,如果使用浏览器滚动功能,则需要禁用掉ion-content的在竖直方向上的滚动;
code:
目录层级:
ts代码:
declare const document: any; export class XXXXX implements OnInit, OnDestroy { isLeave = true; constructor(){} ngOnInit(){...} ionViewWillLeave() { this.isLeave = false; document.getElementById("ion-app-auto-height").style.height = ‘100%‘; } ionViewDidEnter() { if (!this.isLeave) { let offsetHeight = document.getElementById("product-detail-t").offsetHeight ‘px‘; document.getElementById("ion-app-auto-height").style.height = offsetHeight; this.isLeave = true; } } ngAfterViewChecked() { if (document.getElementById("product-detail-t").offsetHeight != 0) { let offsetHeight = document.getElementById("product-detail-t").offsetHeight ‘px‘; if (document.getElementById("ion-app-auto-height").style.height !== offsetHeight) { if (this.isLeave) { document.getElementById("ion-app-auto-height").style.height = offsetHeight; } } } }
注意:上述代码标红的位置需要替换成html中ion-app定义的id以及当前页面最外层div定义的id;
特别注意:body需要设置一下属性,否则会导致撑出页面隐藏;
body{ position: unset; overflow: auto }
页面渲染完成,将当前页面div的高度赋值值ion-app的高度,禁用ionic的滚动功能,并且页面撑出浏览器,便可顺利实现需求(在iso和android测试均通过);
问题2:由于改变了展示方式,导致了之前的浏览器滚动到底在在数据无法使用,即ion-infinite-scroll控件失效,这里自己写了一个控件来实现:
2.1目录结构:
html内容:功能占位
<p></p>
scss内容:空
ts文件内容:
import {Component, HostListener, Input, OnDestroy, OnInit} from ‘@angular/core‘; import {TablePageService} from ‘../table-page/table-page.service‘; import {TablePageParams} from ‘../table-page/table-page.service‘; import {debounceTime, take} from ‘rxjs/operators‘; declare const document: any; @Component({ selector: ‘app-infinite-scroll‘, templateUrl: ‘./infinite-scroll.component.html‘, styleUrls: [‘./infinite-scroll.component.scss‘] }) export class InfiniteScrollComponent implements OnInit{ @Input() service: TablePageService<any>; @HostListener(‘window:scroll‘, [‘$event‘]) public onScroll = ($event) => { //客户端高度 var clientH = document.documentElement.clientHeight*1; //body高度 var bodyH = document.getElementById("ion-app-auto-height").style.height.replace(‘px‘,‘‘)*1; //滚动的高度 var scrollTop = (document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset)*1; //滚动到底部60以内 if ((bodyH - clientH - scrollTop)*1 < 100) { if (!this.flag) { if (!this.isLast) { this.query(); } } this.flag = true; } else { this.flag = false; } } flag = false; isLast = false; type = ‘01‘; private data: any[] = []; private tablePageParams: TablePageParams; constructor() { } ngOnInit() { this.service.params.pipe(debounceTime(200)).subscribe(params => { if (this.type != params.type) { this.type = params.type; this.flag = false; this.isLast = false; } this.tablePageParams = new TablePageParams(params, 1); this.data = []; this.query(); }); } query() { this.service.queryPage(this.tablePageParams) .pipe(take(1)) .subscribe(result => { this.tablePageParams.pageNumber ; this.data = this.data.concat(result.result); this.service.result.next(this.data); if (result.currentPageNo === result.totalPageCount || this.data.length > 500) { this.isLast = true; } }); } }
前端定义的TablePageService接口:
import {Subject, ReplaySubject, Observable} from ‘rxjs‘; export abstract class TablePageService<T> { result = new Subject<T[]>(); params = new ReplaySubject<any>(); constructor() { } query(params = {}) { this.params.next(params); } complete() { this.result.complete(); this.params.complete(); } abstract queryPage(params: TablePageParams): Observable<TablePageResult<T>>; }
export class TablePageParams {
pageNumber: number;
pageSize: number;
params: any;
totalPage: number;
constructor(_params: any = {}, _pageNumber = 1, _pageSize = 20, _totalPage = 1) {
this.params = _params;
if (typeof _pageNumber !== ‘number‘) {
_pageNumber = parseInt(_pageNumber, 20);
}
this.pageNumber = _pageNumber > 0 ? _pageNumber : 1;
this.pageSize = _pageSize;
this.totalPage = _totalPage;
}
}
export class TablePageResult<T> {
currentPageNo = 1;
pageSize = 20;
result: T[];
totalCount = 0;
totalPageCount = 1;
constructor() {
}
}
exports出该控件;
2.2 控件使用:
在html中引入控件,并传入service;
在ts文件中,定义该service,
ts文件:
import {Component, OnDestroy, OnInit} from ‘@angular/core‘;
import {Subscription} from ‘rxjs/index‘;
import {OrderProductInfo} from ‘../../../core/aftersales-core/domain/orderform‘;
import {AftersalesTablePageService} from ‘../aftersales-table-page.service‘;
import {AfterSalesIndexService} from ‘../index/after-sales-index-service‘;
declare const document: any;
@Component({
selector: ‘app-aftersales-apply‘,
templateUrl: ‘./aftersales-apply.component.html‘,
styleUrls: [‘./aftersales-apply.component.scss‘],
providers: [AftersalesTablePageService]
})
export class AftersalesApplyComponent implements OnInit, OnDestroy {
orderProductList: OrderProductInfo[] = [];
private subscriptions: Subscription[] = [];
isLeave = true;
constructor(public tableService: AftersalesTablePageService) {
}
ngOnInit() {
const pageSub = this.tableService.result.asObservable().subscribe(result => { //监听result数据的变化
this.orderProductList = result as [];
});
this.subscriptions.push(pageSub);
this.query();
}
query() {
this.tableService.query();
}
ngOnDestroy(): void {
this.subscriptions.forEach(_item => _item.unsubscribe());
}
ionViewWillLeave() {
this.isLeave = false;
document.getElementById("ion-app-auto-height").style.height = ‘100%‘;
}
ionViewDidEnter() {
if (!this.isLeave) {
let offsetHeight = document.getElementById("aftersales-apply-t").offsetHeight ‘px‘;
document.getElementById("ion-app-auto-height").style.height = offsetHeight;
this.isLeave = true;
}
}
ngAfterViewChecked() {
if (document.getElementById("aftersales-apply-t").offsetHeight != 0) {
let offsetHeight = document.getElementById("aftersales-apply-t").offsetHeight ‘px‘;
if (document.getElementById("ion-app-auto-height").style.height !== offsetHeight) {
if (this.isLeave) {
document.getElementById("ion-app-auto-height").style.height = offsetHeight;
}
}
}
}
}
实现service代码示例,具体查询某一接口:
@Injectable({ providedIn: null }) export class AftersalesTablePageService extends TablePageService<any> { constructor(private table: TableService) { super(); } queryPage(tablePageParams: TablePageParams) { return this.table.queryPage<OrderProductInfo>(‘/orderform/getorderproductpage.do‘, tablePageParams); } }
tableService,具体http请求以及返回数据的封装;
最终效果:
实现距离底部100px,加载新数据;