From 4582c03dd5f96145122316f2dafd4535879afbdb Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 3 May 2018 16:41:55 -0400 Subject: [PATCH 1/3] update when items change --- src/VirtualList.html | 42 +++++++++++++++++++----------------- test/src/index.js | 51 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 21 deletions(-) diff --git a/src/VirtualList.html b/src/VirtualList.html index 5fcba6d..0230bba 100644 --- a/src/VirtualList.html +++ b/src/VirtualList.html @@ -1,4 +1,4 @@ -
+
{#each visible as item (item.index)}
@@ -38,23 +38,13 @@ const { viewport, container } = this.refs; const viewportHeight = viewport.offsetHeight; - const keys = Object.keys(this.options.data).filter(key => key !== 'items' && key !== 'component' && key !== 'itemHeight'); + const keys = Object.keys(this.options.data).filter(key => key !== 'items' && key !== 'component' && key !== 'height' && key !== 'itemHeight'); if (keys.length) { const state = this.get(); keys.forEach(key => { _props[key] = state[key]; }); this.set({ _props }); - - this.on('state', ({ changed, current }) => { - if (!keys.some(key => changed[key])) return; - - const _props = {}; - keys.forEach(key => { - _props[key] = current[key]; - }); - this.set({ _props }); - }); } this.rows = container.getElementsByClassName('row'); @@ -89,10 +79,28 @@ bottom: (items.length - end) * avg }); } + + this.on('state', ({ changed, previous, current }) => { + if (changed.items || changed.height || changed.itemHeight) { + if (changed.itemHeight || current.items.length !== this.heightMap.length) { + this.heightMap = current.items.map(() => current.itemHeight); + } + + this.refresh(); + } + + if (keys.some(key => changed[key])) { + const _props = {}; + keys.forEach(key => { + _props[key] = current[key]; + }); + this.set({ _props }); + } + }); }, methods: { - handleScroll() { + refresh() { const { items, start, end, itemHeight } = this.get(); const { offsetHeight, scrollTop } = this.refs.viewport; @@ -100,11 +108,7 @@ let offset = 0; let i = 0; - if (itemHeight) { - if (this.heightMap.length !== items.length) { - this.heightMap = items.map(item => itemHeight); - } - } else { + if (!itemHeight) { for (let v = 0; v < this.rows.length; v += 1) { this.heightMap[start + v] = this.rows[v].offsetHeight; } @@ -120,7 +124,7 @@ const newStart = i++; for (; i < items.length; i += 1) { - if (offset > scrollTop + offsetHeight) break; + if (offset >= scrollTop + offsetHeight) break; offset += this.heightMap[i]; } diff --git a/test/src/index.js b/test/src/index.js index 4aeaf1c..cb093d7 100644 --- a/test/src/index.js +++ b/test/src/index.js @@ -83,8 +83,7 @@ test('allows item height to be specified', t => { list.set({ itemHeight: 50 }); - // TODO, run handleScroll when items or itemHeight is updated? Probably not needed. - // t.equal(div.getElementsByClassName('row').length, 3); + t.equal(div.getElementsByClassName('row').length, 3); list.destroy(); }); @@ -134,5 +133,53 @@ test('props are passed to child component', t => { list.destroy(); }); +test('updates when items change', t => { + const Row = svelte.create(` + {foo} + `); + + const list = new VirtualList({ + target, + data: { + items: [{ foo: 'bar'}], + component: Row + } + }); + + t.htmlEqual(target.innerHTML, ` +
+
+
+ bar +
+
+
+ `); + + list.set({ + items: [{ foo: 'bar'}, { foo: 'baz'}, { foo: 'qux'}] + }); + + t.htmlEqual(target.innerHTML, ` +
+
+
+ bar +
+ +
+ baz +
+ +
+ qux +
+
+
+ `); + + list.destroy(); +}); + // this allows us to close puppeteer once tests have completed window.done = done; \ No newline at end of file From 1b23f2dfbeb5979a40fb52cd480e33fa9f1cec1b Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 3 May 2018 17:37:27 -0400 Subject: [PATCH 2/3] add dev task --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index b11edc6..4bbd2fb 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "main": "index.js", "scripts": { "build": "rollup -c", + "dev": "rollup -cw", "prepublishOnly": "npm test", "test": "node test/runner.js", "test:browser": "npm run build && serve test/public", From 00e29f39f5fdbed38365c597f7556baf489bcab7 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 3 May 2018 18:01:39 -0400 Subject: [PATCH 3/3] handle change in items.length from zero to some --- src/VirtualList.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/VirtualList.html b/src/VirtualList.html index 0230bba..6048bd2 100644 --- a/src/VirtualList.html +++ b/src/VirtualList.html @@ -82,7 +82,7 @@ this.on('state', ({ changed, previous, current }) => { if (changed.items || changed.height || changed.itemHeight) { - if (changed.itemHeight || current.items.length !== this.heightMap.length) { + if (current.itemHeight && (changed.itemHeight || current.items.length !== this.heightMap.length)) { this.heightMap = current.items.map(() => current.itemHeight); } @@ -115,6 +115,8 @@ } for (; i < items.length; i += 1) { + if (!(i in this.heightMap)) break; + offset += this.heightMap[i]; if (offset > scrollTop) break;