Vue
by Michel Beloshitsky
HTML
<div id="app">
<h2>Todos:</h2>
<ol v-uberscroll:24="todos">
<div>
<li v-for="todo in todos.window">
{{ todo.index }}.
<label>
<input type="checkbox"
v-on:change="toggle(todo)"
v-bind:checked="todo.done">
<del v-if="todo.done">
{{ todo.text }}
</del>
<span v-else>
{{ todo.text }}
</span>
</label>
</li>
</div>
</ol>
</div>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
#app ol {
height: 200px;
overflow-y: auto;
}
li {
height: 24px;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
Vue
Vue.directive('uberscroll', {
inserted (el, { value, arg }) {
const itemHeight = Number(arg)
const updateWindow = () => {
value.offset = Math.ceil(el.scrollTop / itemHeight)
value.limit = Math.ceil(el.clientHeight / itemHeight) * 2
value.window = value.in
.slice(value.offset, value.offset + value.limit)
.map((item, index) => ({ ...item, index: value.offset + index }))
wrapper.style.paddingTop = (value.offset * itemHeight) + 'px'
wrapper.style.paddingBottom = ((value.in.length - (value.offset + value.limit)) * itemHeight) + 'px'
}
el.classList.add('uberscroll')
const wrapper = el.firstChild
el.addEventListener('scroll', updateWindow)
updateWindow()
}
})
const times = (n, arr) => n === 0 ? [] : arr.concat(times(n - 1, arr))
new Vue({
el: "#app",
data: {
todos: {
in: times(1000, [
{ text: "Learn JavaScript", done: false },
{ text: "Learn Vue", done: false },
{ text: "Play around in JSFiddle", done: true },
{ text: "Build something awesome", done: true }
]),
limit: 0,
offset: 0,
window: []
}
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})