From 64f9b0b4625298d1b78d1991636c2d32fe1f422f Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Thu, 13 Nov 2014 01:39:45 -0800 Subject: fixed the perf problems by deferring the sidebar-update while a scroll is happening --- examples/demos/Controller.scala | 127 +++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 61 deletions(-) (limited to 'examples/demos/Controller.scala') diff --git a/examples/demos/Controller.scala b/examples/demos/Controller.scala index e17cde9..6e7df42 100644 --- a/examples/demos/Controller.scala +++ b/examples/demos/Controller.scala @@ -1,13 +1,12 @@ -import japgolly.scalajs.react.React -import japgolly.scalajs.react.vdom.VDomBuilder - import scala.scalajs.js import scala.scalajs.js.annotation.JSExport import org.scalajs.dom import org.scalajs.dom.extensions._ import scala.collection.mutable -import scalatags.JsDom.all._ +import japgolly.scalajs.react._ // React + +import vdom.ReactVDom.all._ // Scalatags html & css (div, h1, textarea, etc.) case class Tree[T](name: T, children: Vector[Tree[T]]) @@ -34,14 +33,21 @@ object Controller{ val structure = upickle.readJs[Tree[String]](upickle.json.readJs(data)) var i = 0 - def recurse(t: Tree[String]): Tree[(String, String, Int)] = { - val curr = (t.name, munge(t.name), i) + def recurse(t: Tree[String], depth: Int): Tree[(Tag, Int)] = { + val curr = + li(paddingLeft := s"${depth * 15}px")( + a( + t.name, + href:=munge("#"+t.name), + cls:="menu-item" + ) + ) + val originalI = i i += 1 - val children = t.children.map(recurse) - Tree(curr, children) + val children = t.children.map(recurse(_, depth + 1)) + Tree(curr -> originalI, children) } - val Seq(main, menu, layout, menuLink) = Seq( "main", "menu", "layout", "menuLink" ).map(dom.document.getElementById) @@ -69,7 +75,7 @@ object Controller{ val menuBar = React.renderComponent( - Menu(recurse(structure)), + Menu(recurse(structure, 0)), menu ) menuLink.onclick = (e: dom.MouseEvent) => { @@ -78,23 +84,28 @@ object Controller{ toggleClass(menuLink, "active") } - var scrolling = false - main.onscroll = (e: dom.UIEvent) => { - if (!scrolling){ - scrolling = true - dom.requestAnimationFrame{(d: Double) => - scrolling = false - val threshold = main.scrollTop + main.clientHeight - - var index = 0 - while(index < headers.length && index >= 0){ - index += 1 - if (headers(index) > threshold) index *= -1 - } - index = -index - menuBar.setState(index) + var x = -1 + def start() = + x = dom.setTimeout(() => { + x = -1 + val threshold = main.scrollTop + main.clientHeight + + var index = 0 + while(index < headers.length && index >= 0){ + index += 1 + if (headers(index) > threshold) index *= -1 } + index = -index + menuBar.setState(index) + + }, 100) + + main.onscroll = (e: dom.UIEvent) => { + if (x != -1){ + dom.clearTimeout(x) + s } + start() } } def isElementInViewport(el: dom.HTMLElement) = { @@ -102,54 +113,48 @@ object Controller{ rect.top >= 0 && rect.bottom <= dom.innerHeight } - import japgolly.scalajs.react._ // React - import vdom.ReactVDom._ // Scalatags → React virtual DOM - import vdom.ReactVDom.all._ // Scalatags html & css (div, h1, textarea, etc.) - val Menu = ReactComponentB[Tree[(String, String, Int)]]("Menu") + + val Menu = ReactComponentB[Tree[(Tag, Int)]]("Menu") .getInitialState(_ => 0) .render{ (structure, _, index) => val contentList = { var i = 0 - def rec1(current: Tree[(String, String, Int)]): Tree[(String, String, Int, Boolean)] = { + val winArray = new js.Array[Boolean](0) + def rec1(current: Tree[(Tag, Int)]): Unit = { val initialI = i i += 1 - val children = current.children.map(rec1) - - val win = i >= index && initialI < index - Tree( - (current.name._1, current.name._2, current.name._3, win), - children - ) + current.children.foreach(rec1) + winArray(current.name._2) = i >= index && initialI < index } - def rec(current: Tree[(String, String, Int, Boolean)], - depth: Int, - classes: String): Iterator[Tag] = { - val winIndex = current.children.indexWhere(_.name._4) + val output = new js.Array[Tag](0) + def rec(current: Tree[(Tag, Int)], + classes: String): Unit = { + + + val winIndex = current.children.indexWhere { x => + winArray(x.name._2) + } val (before, after) = current.children.splitAt(winIndex) - val myCls = - "menu-item" + - (if (depth <= 1) " menu-item-divided" else "") - - val (name, munged, currIndex, win) = current.name - val frag = - li(paddingLeft := s"${depth * 15}px")( - a( - name, - href:="#"+munged, - cls:=myCls - ), - cls:=classes + (if (win) " pure-menu-selected" else "") - ) - val afterCls = if (!win) "hide" else "" - Iterator(frag) ++ - before.flatMap(rec(_, depth+1, "lined")) ++ - after.flatMap(rec(_, depth+1, afterCls)) + val (tag, currIndex) = current.name + + val win = winArray(currIndex) + + val frag = tag( + cls:=classes + (if (win) " pure-menu-selected" else "") + ) + + output.push(frag) + + before.foreach(rec(_, "lined")) + after.foreach(rec(_, if (!win) "hide" else "")) } - rec(rec1(structure), 0, "") + rec1(structure) + rec(structure, "") + output } val frag = div(cls:="pure-menu pure-menu-open")( @@ -157,7 +162,7 @@ object Controller{ "Contents" ), ul(cls:="menu-item-list")( - contentList.drop(1).toVector + contentList.drop(1):_* ) ) frag -- cgit v1.2.3