mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 03:00:58 +08:00
refactor(components): update to use shadow DOM and work with css variables
- updates components to use shadow DOM or scoped if they require css variables - moves global styles to an external stylesheet that needs to be imported - adds support for additional colors and removes the Sass loops to generate colors for each component - several property renames, bug fixes, and test updates Co-authored-by: Manu Mtz.-Almeida <manu.mtza@gmail.com> Co-authored-by: Adam Bradley <adambradley25@gmail.com> Co-authored-by: Cam Wiegert <cam@camwiegert.com>
This commit is contained in:
@ -1,8 +1,10 @@
|
||||
import { Component, Element, EventListenerEnable, Listen, Method, Prop, Watch } from '@stencil/core';
|
||||
import { QueueController } from '../../interface';
|
||||
import { Cell, CellType, DomRenderFn, HeaderFn, ItemHeightFn,
|
||||
ItemRenderFn, Range,
|
||||
VirtualNode, calcCells, calcHeightIndex, doRender,
|
||||
import { Component, Element, EventListenerEnable, Listen, Method, Prop, QueueApi, State, Watch } from '@stencil/core';
|
||||
import { Cell, DomRenderFn, HeaderFn, ItemHeightFn, ItemRenderFn, VirtualNode } from '../../interface';
|
||||
import { CellType } from './virtual-scroll-interface';
|
||||
|
||||
import {
|
||||
Range,
|
||||
calcCells, calcHeightIndex, doRender,
|
||||
findCellIndex, getRange, getShouldUpdate, getViewport,
|
||||
inplaceUpdate, positionForIndex, resizeBuffer, updateVDom } from './virtual-scroll-utils';
|
||||
|
||||
@ -24,13 +26,13 @@ export class VirtualScroll {
|
||||
private viewportOffset = 0;
|
||||
private currentScrollTop = 0;
|
||||
private indexDirty = 0;
|
||||
private totalHeight = 0;
|
||||
private heightChanged = false;
|
||||
private lastItemLen = 0;
|
||||
|
||||
@Element() el!: HTMLStencilElement;
|
||||
|
||||
@Prop({ context: 'queue' }) queue!: QueueController;
|
||||
@State() totalHeight = 0;
|
||||
|
||||
@Prop({ context: 'queue' }) queue!: QueueApi;
|
||||
@Prop({ context: 'enableListener' }) enableListener!: EventListenerEnable;
|
||||
@Prop({ context: 'window' }) win!: Window;
|
||||
|
||||
@ -116,13 +118,13 @@ export class VirtualScroll {
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
const scrollEl = this.el.closest('ion-scroll');
|
||||
if (!scrollEl) {
|
||||
const contentEl = this.el.closest('ion-content');
|
||||
if (!contentEl) {
|
||||
console.error('virtual-scroll must be used inside ion-scroll/ion-content');
|
||||
return;
|
||||
}
|
||||
this.scrollEl = scrollEl;
|
||||
scrollEl.componentOnReady().then(() => {
|
||||
contentEl.componentOnReady().then(() => {
|
||||
this.scrollEl = contentEl.getScrollElement();
|
||||
this.calcDimensions();
|
||||
this.calcCells();
|
||||
this.updateState();
|
||||
@ -204,29 +206,33 @@ export class VirtualScroll {
|
||||
}
|
||||
|
||||
private updateVirtualScroll() {
|
||||
// do nothing if there is a scheduled update
|
||||
// do nothing if virtual-scroll is disabled
|
||||
if (!this.isEnabled || !this.scrollEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// unschedule future updates
|
||||
if (this.timerUpdate) {
|
||||
clearTimeout(this.timerUpdate);
|
||||
this.timerUpdate = null;
|
||||
}
|
||||
|
||||
// schedule DOM operations into the stencil queue
|
||||
this.queue.read(this.readVS.bind(this));
|
||||
this.queue.write(this.writeVS.bind(this));
|
||||
}
|
||||
|
||||
private readVS() {
|
||||
const { scrollEl, el } = this;
|
||||
let topOffset = 0;
|
||||
let node: HTMLElement | null = this.el;
|
||||
while (node && node !== this.scrollEl) {
|
||||
let node: HTMLElement | null = el;
|
||||
while (node && node !== scrollEl) {
|
||||
topOffset += node.offsetTop;
|
||||
node = node.parentElement;
|
||||
}
|
||||
this.viewportOffset = topOffset;
|
||||
if (this.scrollEl) {
|
||||
this.currentScrollTop = this.scrollEl.scrollTop;
|
||||
if (scrollEl) {
|
||||
this.currentScrollTop = scrollEl.scrollTop;
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,7 +264,8 @@ export class VirtualScroll {
|
||||
range
|
||||
);
|
||||
|
||||
// write DOM
|
||||
// Write DOM
|
||||
// Different code paths taken depending of the render API used
|
||||
if (this.nodeRender) {
|
||||
doRender(this.el, this.nodeRender, this.virtualDom, this.updateCellHeight.bind(this));
|
||||
} else if (this.domRender) {
|
||||
@ -266,13 +273,9 @@ export class VirtualScroll {
|
||||
} else if (this.renderItem) {
|
||||
this.el.forceUpdate();
|
||||
}
|
||||
if (this.heightChanged) {
|
||||
this.el.style.height = this.totalHeight + 'px';
|
||||
this.heightChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
private updateCellHeight(cell: Cell, node: HTMLStencilElement | HTMLElement) {
|
||||
private updateCellHeight(cell: Cell, node: HTMLElement) {
|
||||
const update = () => {
|
||||
if ((node as any)['$ionCell'] === cell) {
|
||||
const style = this.win.getComputedStyle(node);
|
||||
@ -351,12 +354,8 @@ export class VirtualScroll {
|
||||
private calcHeightIndex(index = 0) {
|
||||
// TODO: optimize, we don't need to calculate all the cells
|
||||
this.heightIndex = resizeBuffer(this.heightIndex, this.cells.length);
|
||||
const totalHeight = calcHeightIndex(this.heightIndex, this.cells, index);
|
||||
if (totalHeight !== this.totalHeight) {
|
||||
console.debug(`[virtual] total height changed: ${this.totalHeight}px -> ${totalHeight}px`);
|
||||
this.totalHeight = totalHeight;
|
||||
this.heightChanged = true;
|
||||
}
|
||||
this.totalHeight = calcHeightIndex(this.heightIndex, this.cells, index);
|
||||
|
||||
console.debug('[virtual] height index recalculated', this.heightIndex.length - index);
|
||||
this.indexDirty = Infinity;
|
||||
}
|
||||
@ -374,15 +373,23 @@ export class VirtualScroll {
|
||||
}
|
||||
}
|
||||
|
||||
renderVirtualNode(node: VirtualNode) {
|
||||
const cell = node.cell;
|
||||
switch (cell.type) {
|
||||
case CellType.Item: return this.renderItem!(cell.value, cell.index);
|
||||
case CellType.Header: return this.renderHeader!(cell.value, cell.index);
|
||||
case CellType.Footer: return this.renderFooter!(cell.value, cell.index);
|
||||
private renderVirtualNode(node: VirtualNode) {
|
||||
const { type, value, index } = node.cell;
|
||||
switch (type) {
|
||||
case CellType.Item: return this.renderItem!(value, index);
|
||||
case CellType.Header: return this.renderHeader!(value, index);
|
||||
case CellType.Footer: return this.renderFooter!(value, index);
|
||||
}
|
||||
}
|
||||
|
||||
hostData() {
|
||||
return {
|
||||
style: {
|
||||
height: `${this.totalHeight}px`
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const renderItem = this.renderItem;
|
||||
if (renderItem) {
|
||||
@ -392,11 +399,10 @@ export class VirtualScroll {
|
||||
if (!item.vattrs) {
|
||||
item.vattrs = {};
|
||||
}
|
||||
item.vattrs.class += ' virtual-item';
|
||||
if (!node.visible) {
|
||||
classes.push('virtual-loading');
|
||||
}
|
||||
item.vattrs.class += ' ' + classes.join(' ');
|
||||
item.vattrs.class += classes.join(' ');
|
||||
if (!item.vattrs.style) {
|
||||
item.vattrs.style = {};
|
||||
}
|
||||
|
Reference in New Issue
Block a user