UNPKG

db-lgtv-focus-engine

Version:

the Best TV focus engine

127 lines (120 loc) 4.57 kB
import Trunk from "../Trunk" function getRealWidth(el) { let style = getComputedStyle(el) return (parseInt(style.marginRight) + parseInt(style.marginLeft) + el.offsetWidth) } function getRealHeight(el) { let style = getComputedStyle(el) return (parseInt(style.marginTop) + parseInt(style.marginBottom) + el.offsetHeight) } class LongScroll extends Trunk { constructor(engine, el) { super(engine, el) this.key = this.el.getAttribute('db-data') if (!engine) { engine = {} } if (engine[this.key] && engine[this.key].scroll.el === this.el) { return } this.initScroll() } render() { let _o = this.engine[this.key] let current_row = Math.floor((_o.focused_index) / _o.row_sum) let start_index = _o.row_sum * (current_row - _o.column_sum) if (start_index < 0) { start_index = 0 } let end_index = _o.row_sum * (current_row + _o.column_sum + 1) if (end_index > this.engine[this.key].data.length) { end_index = this.engine[this.key].data.length this.el.dispatchEvent(new Event("touchBottom")) } let el_list = _o.data.slice(start_index, end_index).map((_i) => { let stringify = this.key + JSON.stringify(_i) if (!window[stringify]) {window[stringify] = this.convertDataToDom(_i)} return window[stringify] }) let _f = document.createDocumentFragment() let top = document.createElement('div') top.style.width = '100%' top.style.height = `${start_index / _o.row_sum * _o.item_height}px` let bottom = document.createElement('div') bottom.style.width = '100%' bottom.style.height = `50px` _f.appendChild(top) el_list.forEach(_i => { _f.appendChild(_i) }) _f.appendChild(bottom) let if_el_list = _f.querySelectorAll('[db-if]') if_el_list.forEach(element => { if (!eval(element.getAttribute('db-if'))) { element.remove() } }) let style_el_list = _f.querySelectorAll('[db-style]') style_el_list.forEach(element => { element.style.cssText = element.getAttribute('db-style') }) let class_el_list = _f.querySelectorAll('[db-class]') class_el_list.forEach(element => { let oldClass = element.getAttribute('class') || '' let dbClass = ' ' + element.getAttribute('db-class') let newClass = oldClass.concat(dbClass) element.setAttribute('class', newClass) }) this.el.innerHTML = '' this.el.appendChild(_f) this.el.children.forEach((_i, index) => { let real_index = start_index + index - 1 let handler = () => { _o.focused_index = real_index this.render() } if (_i.handler) { _i.removeEventListener('focus', _i.handler) } _i.addEventListener('focus', handler) _i.handler = handler }) return true } convertDataToDom(data) { if (!data) return '' let _d = document.createElement('div') _d.innerHTML = this.engine[this.key].template.replace('db-focus', '').replace(/\[.*?\]/g, function (key) { let res = key.replace(/item/g, 'data').replace(/&amp;/g, '&') let array = res.split('') array.slice(1, array.length - 2) return eval(array.join('')) }) return _d.children[0] } initScroll() { // 重新进入页面 // el被销毁 this.engine[this.key] = { scroll: this, template: this.el.innerHTML, focused_index: 0, row_sum: Math.floor(this.el.offsetWidth / getRealWidth(this.el.children[0])), column_sum: Math.ceil(this.el.offsetHeight / getRealHeight(this.el.children[0])), item_height: getRealHeight(this.el.children[0]), data: [] } this.el.innerHTML = '' Object.defineProperty(this.engine[this.key], 'data', { get: () => { return this.engine['$' + this.el.getAttribute('db-data')] || [] }, set: (_v) => { this.engine['$' + this.el.getAttribute('db-data')] = _v this.render() }, configurable: true }) } } export default LongScroll