瀏覽代碼

change how view rerenders

Adam Shaw 6 年之前
父節點
當前提交
e4192b52c8

+ 1 - 1
packages/__tests__/src/legacy/scroll-state.js

@@ -31,7 +31,7 @@ describe('scroll state', function() {
 
   function defineTests() {
 
-    it('should be maintained when moving resizing window', function(done) {
+    it('should be maintained when resizing window', function(done) {
       var scrollEl
       var scroll0
 

+ 9 - 33
packages/core/src/Calendar.ts

@@ -108,7 +108,6 @@ export default class Calendar {
 
   // isDisplaying: boolean = false // installed in DOM? accepting renders?
   needsRerender: boolean = false // needs a render?
-  needsFullRerender: boolean = false
   isRendering: boolean = false // currently in the executeRender function?
   renderingPauseDepth: number = 0
   renderableEventStore: EventStore
@@ -164,11 +163,12 @@ export default class Calendar {
 
   render() {
     if (!this.component) {
+      this.component = new CalendarComponent(this.el)
       this.renderableEventStore = createEmptyEventStore()
       this.bindHandlers()
       this.executeRender()
     } else {
-      this.requestRerender(true)
+      this.requestRerender()
     }
   }
 
@@ -312,13 +312,13 @@ export default class Calendar {
 
       let view = this.component && this.component.view
 
-      if (oldState.eventStore !== newState.eventStore || this.needsFullRerender) {
+      if (oldState.eventStore !== newState.eventStore) {
         if (oldState.eventStore) {
           this.isEventsUpdated = true
         }
       }
 
-      if (oldState.dateProfile !== newState.dateProfile || this.needsFullRerender) {
+      if (oldState.dateProfile !== newState.dateProfile) {
         if (oldState.dateProfile && view) { // why would view be null!?
           this.publiclyTrigger('datesDestroy', [
             {
@@ -330,7 +330,7 @@ export default class Calendar {
         this.isDatesUpdated = true
       }
 
-      if (oldState.viewType !== newState.viewType || this.needsFullRerender) {
+      if (oldState.viewType !== newState.viewType) {
         if (oldState.viewType && view) { // why would view be null!?
           this.publiclyTrigger('viewSkeletonDestroy', [
             {
@@ -356,9 +356,8 @@ export default class Calendar {
   // -----------------------------------------------------------------------------------------------------------------
 
 
-  requestRerender(needsFull = false) {
+  requestRerender() {
     this.needsRerender = true
-    this.needsFullRerender = this.needsFullRerender || needsFull
     this.delayedRerender() // will call a debounced-version of tryRerender
   }
 
@@ -390,14 +389,11 @@ export default class Calendar {
   // -----------------------------------------------------------------------------------------------------------------
 
   executeRender() {
-    let { needsFullRerender } = this // save before clearing
-
     // clear these BEFORE the render so that new values will accumulate during render
     this.needsRerender = false
-    this.needsFullRerender = false
 
     this.isRendering = true
-    this.renderComponent(needsFullRerender)
+    this.renderComponent()
     this.isRendering = false
 
     // received a rerender request while rendering
@@ -409,11 +405,10 @@ export default class Calendar {
   /*
   don't call this directly. use executeRender instead
   */
-  renderComponent(needsFull) {
+  renderComponent() {
     let { state, component } = this
     let { viewType } = state
     let viewSpec = this.viewSpecs[viewType]
-    let savedScroll = (needsFull && component) ? component.view.queryScroll() : null
 
     if (!viewSpec) {
       throw new Error(`View type "${viewType}" is not valid`)
@@ -430,20 +425,6 @@ export default class Calendar {
     let eventUiBySource = this.buildEventUiBySource(state.eventSources)
     let eventUiBases = this.eventUiBases = this.buildEventUiBases(renderableEventStore.defs, eventUiSingleBase, eventUiBySource)
 
-    if (needsFull || !component) {
-
-      if (component) {
-        component.freezeHeight() // next component will unfreeze it
-        component.destroy()
-      }
-
-      component = this.component = new CalendarComponent(this.el)
-
-      this.isViewUpdated = true
-      this.isDatesUpdated = true
-      this.isEventsUpdated = true
-    }
-
     component.receiveProps({
       ...state,
       viewSpec,
@@ -461,10 +442,6 @@ export default class Calendar {
       this.optionsManager.computed
     ))
 
-    if (savedScroll) {
-      component.view.applyScroll(savedScroll, false)
-    }
-
     if (this.isViewUpdated) {
       this.isViewUpdated = false
       this.publiclyTrigger('viewSkeletonRender', [
@@ -559,7 +536,6 @@ export default class Calendar {
 
     if (anyDifficultOptions) {
       this.handleOptions(this.optionsManager.computed)
-      this.needsFullRerender = true
     }
 
     this.batchRendering(() => {
@@ -574,7 +550,7 @@ export default class Calendar {
         }
 
         /* HACK
-        has the same effect as calling this.requestRerender(true)
+        has the same effect as calling this.requestRerender()
         but recomputes the state's dateProfile
         */
         this.dispatch({

+ 49 - 28
packages/core/src/CalendarComponent.ts

@@ -35,11 +35,13 @@ export default class CalendarComponent extends Component<CalendarComponentProps>
   el: HTMLElement
   contentEl: HTMLElement
 
+  elClassNames: string[] = []
+  savedScroll: any // hack
   isHeightAuto: boolean
   viewHeight: number
 
   private renderSkeleton = memoizeRendering(this._renderSkeleton, this._unrenderSkeleton)
-  private renderToolbars = memoizeRendering(this._renderToolbars, null, [ this.renderSkeleton ])
+  private renderToolbars = memoizeRendering(this._renderToolbars, this._unrenderToolbars, [ this.renderSkeleton ])
   private buildComponentContext = memoize(buildComponentContext)
   private buildViewPropTransformers = memoize(buildViewPropTransformers)
 
@@ -83,7 +85,7 @@ export default class CalendarComponent extends Component<CalendarComponentProps>
   }
 
   _renderSkeleton(context: ComponentContext) {
-    this.toggleElClassNames(true, context)
+    this.updateElClassNames(context)
 
     prependToElement(
       this.el,
@@ -98,25 +100,42 @@ export default class CalendarComponent extends Component<CalendarComponentProps>
   }
 
   _unrenderSkeleton() {
-    this.destroyView() // weird to have this here
+
+    // weird to have this here
+    if (this.view) {
+      this.savedScroll = this.view.queryScroll()
+      this.view.destroy()
+      this.view = null
+    }
+
     removeElement(this.contentEl)
-    this.toggleElClassNames(false, this.context)
+    this.removeElClassNames()
   }
 
-  toggleElClassNames(bool: boolean, context: ComponentContext) {
+  removeElClassNames() {
+    let classList = this.el.classList
+
+    for (let className of this.elClassNames) {
+      classList.remove(className)
+    }
+
+    this.elClassNames = []
+  }
+
+  updateElClassNames(context: ComponentContext) {
+    this.removeElClassNames()
+
     let { theme, options } = context
+    this.elClassNames = [
+      'fc',
+      'fc-' + options.dir,
+      theme.getClass('widget')
+    ]
+
     let classList = this.el.classList
-    let dirClassName = 'fc-' + options.dir
-    let themeClassName = theme.getClass('widget')
 
-    if (bool) {
-      classList.add('fc')
-      classList.add(dirClassName)
-      classList.add(themeClassName)
-    } else {
-      classList.remove('fc')
-      classList.remove(dirClassName)
-      classList.remove(themeClassName)
+    for (let className of this.elClassNames) {
+      classList.add(className)
     }
   }
 
@@ -169,6 +188,17 @@ export default class CalendarComponent extends Component<CalendarComponentProps>
     }
   }
 
+  _unrenderToolbars() {
+    if (this.header) {
+      this.header.destroy()
+      this.header = null
+    }
+    if (this.footer) {
+      this.footer.destroy()
+      this.footer = null
+    }
+  }
+
   renderView(props: CalendarComponentProps, title: string) {
     let { view } = this
     let { calendar, options } = this.context
@@ -182,8 +212,10 @@ export default class CalendarComponent extends Component<CalendarComponentProps>
 
       view = this.view = new viewSpec['class'](viewSpec, this.contentEl)
 
-    } else {
-      view.addScroll(view.queryScroll())
+      if (this.savedScroll) {
+        view.addScroll(this.savedScroll, true)
+        this.savedScroll = null
+      }
     }
 
     view.title = title // for the API
@@ -212,13 +244,6 @@ export default class CalendarComponent extends Component<CalendarComponentProps>
     view.receiveProps(viewProps, this.buildComponentContext(this.context, viewSpec, view))
   }
 
-  destroyView() {
-    if (this.view) {
-      this.view.destroy()
-      this.view = null
-    }
-  }
-
 
   // Sizing
   // -----------------------------------------------------------------------------------------------------------------
@@ -230,10 +255,6 @@ export default class CalendarComponent extends Component<CalendarComponentProps>
       return // why?
     }
 
-    if (isResize) {
-      view.addScroll(view.queryScroll())
-    }
-
     if (isResize || this.isHeightAuto == null) {
       this.computeHeightVars()
     }

+ 21 - 7
packages/core/src/View.ts

@@ -114,6 +114,11 @@ export default abstract class View extends DateComponent<ViewProps> {
   }
 
 
+  beforeUpdate() {
+    this.addScroll(this.queryScroll())
+  }
+
+
   destroy() {
     super.destroy()
 
@@ -128,6 +133,10 @@ export default abstract class View extends DateComponent<ViewProps> {
   updateSize(isResize: boolean, viewHeight: number, isAuto: boolean) {
     let { calendar } = this.context
 
+    if (isResize) {
+      this.addScroll(this.queryScroll()) // NOTE: same code as in beforeUpdate
+    }
+
     if (
       isResize || // HACKS...
       calendar.isViewUpdated ||
@@ -138,6 +147,8 @@ export default abstract class View extends DateComponent<ViewProps> {
       // anything that might cause dimension changes
       this.updateBaseSize(isResize, viewHeight, isAuto)
     }
+
+    // NOTE: popScroll is called by CalendarComponent
   }
 
 
@@ -373,10 +384,11 @@ export default abstract class View extends DateComponent<ViewProps> {
   ------------------------------------------------------------------------------------------------------------------*/
 
 
-  addScroll(scroll) {
-    let queuedScroll = this.queuedScroll || (this.queuedScroll = {})
-
-    __assign(queuedScroll, scroll)
+  addScroll(scroll, isForced?: boolean) {
+    if (isForced) {
+      scroll.isForced = isForced
+    }
+    __assign(this.queuedScroll || (this.queuedScroll = {}), scroll)
   }
 
 
@@ -387,7 +399,9 @@ export default abstract class View extends DateComponent<ViewProps> {
 
 
   applyQueuedScroll(isResize: boolean) {
-    this.applyScroll(this.queuedScroll || {}, isResize)
+    if (this.queuedScroll) {
+      this.applyScroll(this.queuedScroll, isResize)
+    }
   }
 
 
@@ -403,9 +417,9 @@ export default abstract class View extends DateComponent<ViewProps> {
 
 
   applyScroll(scroll, isResize: boolean) {
-    let { duration } = scroll
+    let { duration, isForced } = scroll
 
-    if (duration != null) {
+    if (duration != null && !isForced) {
       delete scroll.duration
 
       if (this.props.dateProfile) { // dates rendered yet?

+ 15 - 0
packages/core/src/component/Component.ts

@@ -73,7 +73,16 @@ export default class Component<PropsType> {
     this.props = comboProps
 
     if (anyChanges) {
+
+      if (oldContext) {
+        this.beforeUpdate()
+      }
+
       this.render(comboProps, context)
+
+      if (oldContext) {
+        this.afterUpdate()
+      }
     }
   }
 
@@ -83,6 +92,12 @@ export default class Component<PropsType> {
   firstContext(context: ComponentContext) {
   }
 
+  beforeUpdate() {
+  }
+
+  afterUpdate() {
+  }
+
   // after destroy is called, this component won't ever be used again
   destroy() {
   }