start on virtual list
This commit is contained in:
parent
d5ac34eb73
commit
3ef701fd57
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -6829,9 +6829,7 @@
|
||||||
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
|
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
|
||||||
},
|
},
|
||||||
"svelte": {
|
"svelte": {
|
||||||
"version": "1.51.0",
|
"version": "github:nolanlawson/svelte#c5cd9fc76e069faa364e5c2c6343ddaf2adc4dcf"
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-1.51.0.tgz",
|
|
||||||
"integrity": "sha512-lqa9eAZ4ZQLMWsoyynAogUtib7HhHnrJJaS93uRgZU5cfXquBVR+FkKVK41LdlwffmOfOjbUin6pT8e/LZUwjA=="
|
|
||||||
},
|
},
|
||||||
"svelte-extras": {
|
"svelte-extras": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
|
|
|
@ -31,10 +31,10 @@
|
||||||
"npm-run-all": "^4.1.2",
|
"npm-run-all": "^4.1.2",
|
||||||
"performance-now": "^2.1.0",
|
"performance-now": "^2.1.0",
|
||||||
"pify": "^3.0.0",
|
"pify": "^3.0.0",
|
||||||
"sapper": "^0.3.1",
|
"sapper": "^0.3.2",
|
||||||
"serve-static": "^1.13.1",
|
"serve-static": "^1.13.1",
|
||||||
"style-loader": "^0.19.1",
|
"style-loader": "^0.19.1",
|
||||||
"svelte": "^1.50.0",
|
"svelte": "github:nolanlawson/svelte#master-8057884",
|
||||||
"svelte-extras": "^1.6.0",
|
"svelte-extras": "^1.6.0",
|
||||||
"svelte-loader": "^2.3.3",
|
"svelte-loader": "^2.3.3",
|
||||||
"svelte-transitions": "^1.1.1",
|
"svelte-transitions": "^1.1.1",
|
||||||
|
|
17
routes/_components/StatusListItem.html
Normal file
17
routes/_components/StatusListItem.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<div class="list-item">
|
||||||
|
<Status status="{{virtualProps}}" />
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.list-item {
|
||||||
|
border-bottom: 1px solid var(--main-border);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import Status from './Status.html'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,33 +1,27 @@
|
||||||
<ul>
|
<div class="timeline">
|
||||||
{{#each statuses as status}}
|
<VirtualList component="{{StatusListItem}}" items="{{statuses}}" />
|
||||||
<li>
|
</div>
|
||||||
<Status :status />
|
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
||||||
<style>
|
<style>
|
||||||
ul {
|
.timeline {
|
||||||
list-style: none;
|
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
li {
|
|
||||||
border-bottom: 1px solid var(--main-border);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import { store } from '../_utils/store'
|
import { store } from '../_utils/store'
|
||||||
import { getHomeTimeline } from '../_utils/mastodon/oauth'
|
import { getHomeTimeline } from '../_utils/mastodon/oauth'
|
||||||
import fixture from '../_utils/fixture.json'
|
import fixture from '../_utils/fixture.json'
|
||||||
import Status from './Status.html'
|
import StatusListItem from './StatusListItem.html'
|
||||||
|
import VirtualList from './VirtualList.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data: () => ({
|
data: () => ({
|
||||||
target: 'home',
|
target: 'home',
|
||||||
statuses: fixture
|
statuses: fixture,
|
||||||
|
StatusListItem: StatusListItem
|
||||||
}),
|
}),
|
||||||
store: () => store,
|
store: () => store,
|
||||||
components: {
|
components: {
|
||||||
Status
|
VirtualList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
70
routes/_components/VirtualList.html
Normal file
70
routes/_components/VirtualList.html
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<div class="virtual-list" ref:node style="height: {{height}}px;">
|
||||||
|
{{#each visibleItems as visibleItem, index}}
|
||||||
|
<VirtualListItem :component
|
||||||
|
:intersectionObserver
|
||||||
|
virtualOffset="{{visibleItem.offset}}"
|
||||||
|
virtualProps="{{visibleItem.props}}"
|
||||||
|
virtualIndex="{{index}}" />
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.virtual-list {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import VirtualListItem from './VirtualListItem'
|
||||||
|
|
||||||
|
function sum(arr) {
|
||||||
|
return arr.reduce((a, b) => a + b, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
oncreate() {
|
||||||
|
let intersectionObserver = new IntersectionObserver((entries) => {
|
||||||
|
let totalHeight = sum(entries.map(entry => entry.boundingClientRect.height))
|
||||||
|
let offset = 0
|
||||||
|
let offsets = []
|
||||||
|
entries.forEach(entry => {
|
||||||
|
offsets.push(offset)
|
||||||
|
offset += entry.boundingClientRect.height
|
||||||
|
})
|
||||||
|
this.set({
|
||||||
|
height: totalHeight,
|
||||||
|
offsets: offsets
|
||||||
|
})
|
||||||
|
console.log('entries', entries.map(entry => entry.target.getAttribute('data-virtual-index')))
|
||||||
|
}, {
|
||||||
|
root: this.refs.node
|
||||||
|
})
|
||||||
|
this.set({
|
||||||
|
intersectionObserver: intersectionObserver
|
||||||
|
})
|
||||||
|
},
|
||||||
|
ondestroy() {
|
||||||
|
let intersectionObserver = this.get('intersectionObserver')
|
||||||
|
if (intersectionObserver) {
|
||||||
|
intersectionObserver.disconnect()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
visibleItems: (items, offsets) => {
|
||||||
|
return items.map((item, idx) => ({
|
||||||
|
props: item,
|
||||||
|
offset: offsets[idx]
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
scrollHeight: 0,
|
||||||
|
component: null,
|
||||||
|
intersectionObserver: null,
|
||||||
|
items: [],
|
||||||
|
offsets: [],
|
||||||
|
height: 400
|
||||||
|
}),
|
||||||
|
components: {
|
||||||
|
VirtualListItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
29
routes/_components/VirtualListItem.html
Normal file
29
routes/_components/VirtualListItem.html
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<div class="virtual-list-item"
|
||||||
|
ref:node
|
||||||
|
style="transform: translate3d(0, {{virtualOffset}}px, 0);"
|
||||||
|
data-virtual-index="{{virtualIndex}}">
|
||||||
|
<:Component {component} :virtualProps :virtualIndex :intersectionObserver />
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.virtual-list-item {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
oncreate() {
|
||||||
|
this.observe('intersectionObserver', (intersectionObserver) => {
|
||||||
|
if (intersectionObserver) {
|
||||||
|
intersectionObserver.observe(this.refs.node)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showRefs () {
|
||||||
|
console.log(this.refs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue