use rIC in pseudo virtual list
This commit is contained in:
parent
03b055ab20
commit
d1620c3bca
5
package-lock.json
generated
5
package-lock.json
generated
|
@ -7244,6 +7244,11 @@
|
||||||
"setimmediate": "1.0.5"
|
"setimmediate": "1.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tiny-queue": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tiny-queue/-/tiny-queue-0.2.1.tgz",
|
||||||
|
"integrity": "sha1-JaZ/LG4lOyypQZd7XvdELvl6YEY="
|
||||||
|
},
|
||||||
"tmp": {
|
"tmp": {
|
||||||
"version": "0.0.31",
|
"version": "0.0.31",
|
||||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz",
|
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz",
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
"svelte-loader": "^2.3.3",
|
"svelte-loader": "^2.3.3",
|
||||||
"svelte-transitions": "^1.1.1",
|
"svelte-transitions": "^1.1.1",
|
||||||
"svgo": "^1.0.3",
|
"svgo": "^1.0.3",
|
||||||
|
"tiny-queue": "^0.2.1",
|
||||||
"uglifyjs-webpack-plugin": "^1.1.5",
|
"uglifyjs-webpack-plugin": "^1.1.5",
|
||||||
"url-search-params": "^0.10.0",
|
"url-search-params": "^0.10.0",
|
||||||
"webpack": "^3.10.0",
|
"webpack": "^3.10.0",
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
makeProps="{{makeProps}}"
|
makeProps="{{makeProps}}"
|
||||||
key="{{wrappedItem.item}}"
|
key="{{wrappedItem.item}}"
|
||||||
intersectionObserver="{{intersectionObserver}}"
|
intersectionObserver="{{intersectionObserver}}"
|
||||||
hide="{{shouldHide(wrappedItem.item, $intersectionStates)}}"
|
isIntersecting="{{isIntersecting(wrappedItem.item, $intersectionStates)}}"
|
||||||
|
isCached="{{isCached(wrappedItem.item, $intersectionStates)}}"
|
||||||
height="{{getHeight(wrappedItem.item, $intersectionStates)}}"
|
height="{{getHeight(wrappedItem.item, $intersectionStates)}}"
|
||||||
/>
|
/>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
@ -35,7 +36,7 @@
|
||||||
let intersectionStates = this.store.get('intersectionStates')
|
let intersectionStates = this.store.get('intersectionStates')
|
||||||
let keys = Object.keys(intersectionStates)
|
let keys = Object.keys(intersectionStates)
|
||||||
for (let key of keys) {
|
for (let key of keys) {
|
||||||
intersectionStates[key].isIntersecting = false
|
intersectionStates[key].isCached = true
|
||||||
}
|
}
|
||||||
this.store.setForRealm({intersectionStates: intersectionStates})
|
this.store.setForRealm({intersectionStates: intersectionStates})
|
||||||
|
|
||||||
|
@ -60,8 +61,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
helpers: {
|
helpers: {
|
||||||
shouldHide(key, $intersectionStates) {
|
isIntersecting(key, $intersectionStates) {
|
||||||
return !!($intersectionStates[key] && !$intersectionStates[key].isIntersecting)
|
return !!($intersectionStates[key] && $intersectionStates[key].isIntersecting)
|
||||||
|
},
|
||||||
|
isCached(key, $intersectionStates) {
|
||||||
|
return !!($intersectionStates[key] && $intersectionStates[key].isCached)
|
||||||
},
|
},
|
||||||
getHeight(key, $intersectionStates) {
|
getHeight(key, $intersectionStates) {
|
||||||
return $intersectionStates[key] && $intersectionStates[key].rect.height
|
return $intersectionStates[key] && $intersectionStates[key].rect.height
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<div class="pseudo-virtual-list-item"
|
<div class="pseudo-virtual-list-item"
|
||||||
aria-hidden="{{hide}}"
|
aria-hidden="{{hide}}"
|
||||||
pseudo-virtual-list-key="{{key}}"
|
pseudo-virtual-list-key="{{key}}"
|
||||||
style="height: {{hide ? `${height}px` : ''}};"
|
style="height: {{shouldHide ? `${height}px` : ''}};"
|
||||||
ref:node>
|
ref:node>
|
||||||
{{#if !hide}}
|
{{#if !shouldHide}}
|
||||||
<:Component {component}
|
<:Component {component}
|
||||||
virtualProps="{{props}}"
|
virtualProps="{{props}}"
|
||||||
virtualIndex="{{index}}"
|
virtualIndex="{{index}}"
|
||||||
|
@ -13,10 +13,38 @@
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
|
||||||
|
import { mark, stop } from '../../_utils/marks'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate() {
|
oncreate() {
|
||||||
|
this.observe('isIntersecting', isIntersecting => {
|
||||||
|
if (isIntersecting) {
|
||||||
|
mark('render')
|
||||||
|
this.set({hide: false})
|
||||||
|
stop('render')
|
||||||
|
} else {
|
||||||
|
// unrender lazily; it's not a critical UI task
|
||||||
|
scheduleIdleTask(() => {
|
||||||
|
mark('unrender')
|
||||||
|
if (!this.get('isIntersecting')) {
|
||||||
|
this.set({hide: true})
|
||||||
|
}
|
||||||
|
stop('unrender')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
let intersectionObserver = this.get('intersectionObserver')
|
let intersectionObserver = this.get('intersectionObserver')
|
||||||
intersectionObserver.observe(this.refs.node)
|
intersectionObserver.observe(this.refs.node)
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
shouldHide: (isIntersecting, isCached, hide) => {
|
||||||
|
if (isCached) {
|
||||||
|
return true // if it's cached, always unrender immediately until proven it's intersecting
|
||||||
|
}
|
||||||
|
return !isIntersecting && hide
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
:index
|
:index
|
||||||
:scrollToThisItem
|
:scrollToThisItem
|
||||||
:intersectionObserver
|
:intersectionObserver
|
||||||
:hide
|
:isIntersecting
|
||||||
|
:isCached
|
||||||
:height
|
:height
|
||||||
on:scrollToPosition
|
on:scrollToPosition
|
||||||
/>
|
/>
|
||||||
|
|
27
routes/_utils/scheduleIdleTask.js
Normal file
27
routes/_utils/scheduleIdleTask.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Wrapper to call requestIdleCallback() to schedule low-priority work.
|
||||||
|
// See https://developer.mozilla.org/en-US/docs/Web/API/Background_Tasks_API
|
||||||
|
// for a good breakdown of the concepts behind this.
|
||||||
|
|
||||||
|
import Queue from 'tiny-queue'
|
||||||
|
|
||||||
|
const taskQueue = new Queue()
|
||||||
|
let runningRequestIdleCallback = false
|
||||||
|
|
||||||
|
function runTasks(deadline) {
|
||||||
|
while (taskQueue.length && deadline.timeRemaining() > 0) {
|
||||||
|
taskQueue.shift()()
|
||||||
|
}
|
||||||
|
if (taskQueue.length) {
|
||||||
|
requestIdleCallback(runTasks)
|
||||||
|
} else {
|
||||||
|
runningRequestIdleCallback = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function scheduleIdleTask(task) {
|
||||||
|
taskQueue.push(task)
|
||||||
|
if (!runningRequestIdleCallback) {
|
||||||
|
runningRequestIdleCallback = true
|
||||||
|
requestIdleCallback(runTasks)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue