SEPG框架-核心组件使用手册

返回目录

SEPG框架-核心组件使用手册

  • 框架版本: 2.1.0
  • 文档版本: 1.0.0
  • 生成时间: 2026-03-19 10:58:18

1. 概述

SEPG框架是一个EPG(电子节目指南)开发框架,主要用于电视、机顶盒等大屏设备的EPG系统页面开发。核心组件包括:

注意:核心组件中AreaFloorPage等类都提供了统一的构建API方法,开发者应通过框架提供的API方法生成对应的实例对象。例如,使用createFloor方法生成一个楼层区域实例;使用getPageInstance方法获取当前页面单实例;

SEPG框架提供esm模块和umd模块两种使用方式,开发者可以根据项目需求选择合适的引入方式。
esm版本包含sepg.d.tssepg.js文件;umd版本包含sepg.d.tssepg.jssepg.var.js文件,引入时需要先引入sepg.js文件,再引入sepg.var.js文件,sepg.var.js是将框架中的功能模块通过全局对象的方式暴露,方便直接使用,因此新定义变量时需要注意不要覆盖暴露的全局对象;sepg.d.ts文件作为类型声明文件,在开发环境提供类型提示,代码中不需要引入。

模块化开发优先使用esm版本,可以使用最新的ES6+语法特性,生产环境通过打包工具将代码转化为ES5-代码。
非模块化开发使用umd版本,可以直接通过script标签引入,由于不经过打包工具处理,为了更好的兼容性只能使用ES5-语法开发。

2. 基础约定

2.1 焦点元素

焦点元素item)就是页面中可获取焦点的元素,在元素获取焦点后,页面上有明显的显示,提示用户当前焦点位置,与用户完成各种交互的元素。 在研发阶段,设计出图给到我们的静态页面中都会标明。 焦点元素具有多种显示状态,一般我们使用 'item' 的class类名作为初始状态'item item_focus' 的class类名作为获焦状态'item item_select' 的class类名作为驻留状态,通过修改class类名就能实现焦点的切换、驻留等显示状态。当然框架支持自定义普通、获焦、驻留的class类名,具体配置方式详见区域融合配置全局元素样式类配置

2.2 容器元素

容器元素container)就是焦点元素的父级或祖先元素(一般为父级元素),每个区域都有一个容器元素,容器元素包含了该区域所有的焦点元素。框架中针对区域的滑动等配置,默认的滑动dom也是容器元素。

2.3 页面拆分

在以往的EPG研发过程中,我们倾向于将整个EPG页面拆分为多个逻辑模块,然后通过模块分区依次对各个业务模块进行逻辑开发工作。我们一般会将页面划分为多个区域,根据实际的业务场景对各个区域做定制化的逻辑开发。

下面将以常见EPG页面为例,讲解使用SEPG框架开发前需要做的拆分工作。

example

可以见上图,其中红色框中的元素即为EPG页面中需要焦点逻辑的dom元素。我们的拆分思路是,按元素的业务功能接口数据获取布局位置等方面进行页面区域拆分。如图,根据元素业务功能和布局位置,可知A区域B区域的元素在功能和布局位置上具有相似逻辑;根据接口数据获取和布局位置,可知C区域D区域的元素在接口数据获取和布局位置上具有相似逻辑,因此将它们统一归入一个区域进行处理。

:::warning
本例只是多种拆分逻辑中的一种常见处理方式,具体拆分处理需要根据实际的业务场景决定。
:::

2.4 SEPG的分区逻辑

在完成上面的拆分逻辑后,即可开始规划SEPG中的各个控制器模块。首先,将各个区域交给区域控制器 Area 或楼层类 Floor 实例管理,区域控制器实例上可以完成该区域的定制配置以及区域的各种事件的监听, 然后将整个页面交给页面控制器 Page 实例统一管理,进行事件的监听、分发等处理。
:::tip
焦点元素归为同一区域的原则是,将元素放入同一个容器, 即父级元素(层级不限)中即可。
:::
例如:

<!-- container即为父级容器, item为焦点元素 -->
<!-- 单层级 -->
<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>
<!-- 多层级 -->
<div class="container">
  <div class="wrapper">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
  </div>
</div>

3. Area区域控制器

Area类是SEPG框架的核心基础类,负责管理焦点区域的基本行为。

3.1 主要属性

3.1.1 私有属性

属性名
类型
默认值
属性说明
layout `'row' 'col'` -
loader Loader - 区域加载器实例
domMoveStrategy DomMoveStrategy - dom级别移动策略定制
childList Area[] - 联动的下级区域控制器列表
parentList Area[] - 联动的上级区域控制器列表
autoInit boolean true 是否自动初始化dom元素id

3.1.2 公共属性

属性名
类型
默认值
属性说明
throttleTime number - 区域长按时的按键节流时间
lazyTimer number - 图片延迟懒加载定时器
rectSeted boolean - 是否已记录rect数据
loaded number[] - 分页加载已加载页数
data any - 分页加载的数据
moveToRecord MoveToRecord - 指定移动索引记忆
loadKey number - 加载配置标识(用于比较加载版本对加载结果做取舍)
loadOptions AreaLoadConfig - 加载配置
popup boolean - 是否为弹窗模式
keepFocus boolean - 当前区域实例是否始终持有焦点(适用于弹窗场景下需要保持焦点的状态)
complete boolean - 配置的load函数是否已完成加载
skipHide boolean true 是否跳过隐藏元素
disableShake boolean false 是否禁用边界抖动
customClass boolean false 是否自定义class类名(影响page.setCommonClass判断)
longPressHide boolean false 长按时隐藏焦点
customSlide NumberOrNumbers - 指定当前区域在页面滑动中的滑动量
fromArea Area - 焦点来源区域控制器实例
prevArea Area - 前一个区域控制器实例
nextArea Area - 后一个区域控制器实例
viewPoint boolean - 是否已进入视口
viewPointOnce boolean - 是否已经进入过视口
virtual boolean - 是否为虚拟区域(一般作为占位,需要获取区域的同等逻辑,但是不需要焦点元素,常见实例比如: 进度条、滚动条、浮层等等)
emptyCorrect boolean - 当渲染或切换焦点到当前区域,而当前区域容器未激活或区域无焦点元素时,是否自动矫正焦点到前一个有效区域
along boolean - 区域跨界时是否按当前区域索引顺移(适用于多元素列表焦点需要同步移动的场景)
rightAlign boolean - 区域元素是否为右浮动布局
stack boolean - 堆叠区域布局(区域内异型布局)
reverse boolean - 是否为反向布局(即纵向布局)
cyclicMoveH boolean - 横向是否循环移动焦点(需明确指定区域行列数)
cyclicMoveV boolean - 纵向是否循环移动焦点(需明确指定区域行列数)
cyclicRollingConfig CyclicRollingConfig - 循环滚动配置
scrollConfig ScrollConfig - scroll滚动配置
slideFocusConfig SlideFocusConfig - 滑动焦点配置
pageSize number - 每一页的数量
totalPage number - 总页数
currentPage number - 当前页
cyclicTurnPage boolean - 页数是否循环切换
openRightFix boolean - 是否开启向右焦点矫正,即尾元素向右矫正到倒数第二排的(this.currentIndex+1)索引处
closeDownFix boolean - 是否关闭向下焦点矫正
nearby DirBoolean - 是否关闭就近原则
dirLock DirBoolean - 方向锁
crossLock boolean - 处理区域越界时,区域为空时的跨界锁,锁定时即使区域为空依然不做跨界,解锁时当区域为空可以自动递归跨界到下一个区域
id number 0 区域id,即索引值
openMarquee boolean - 是否开启文字滚动
marqueeClass string 'txt' 文字滚动元素基础类名
marqueeConfig MarqueeConfig - 文字滚动配置
marqueeObj `Marquee null` -
currentIndex number 0 当前焦点索引
triggerIndex number 0 联动触发的当前焦点索引
rowCount number 1 总行数
colCount number 1 总列数
totalCount number 1 元素总个数(手动初始化时需要手动传入)
lastIndex number 0 最后一个焦点索引
commonClass string 'item' 通用样式,元素公共类,用于焦点dom查找
normalClass string 'item' 初始化显示类名
focusClass string 'item item_focus' 上焦类
blurClass string 'item' 失焦类
containerId string - 容器id
container ExtendHTMLElement document.body 容器元素
containerDOMRect SafeDOMRect - 初始化时容器的位置信息集合
containerTranslate number 0 容器元素的偏移量
containerMaxTranslate number 0 容器元素的最大偏移量
itemId string 'item' 上焦元素id前缀
closeInsideBoundary boolean true 是否关闭区域内越界
insideUpside boolean - 颠倒内部越界
record boolean - 是否记忆焦点
recordIndex number 0 记忆的焦点索引
select boolean - 是否显示select选中类样式
alwaysSelect boolean - 是否总是显示选中状态
manualSelect boolean - 手动选择选中状态(跨界不自动记录暗焦点,需手动选择)
selectClass string 'item item_select' select选中的类(驻留样式类)
outMoveDir OutMoveDir - 越界指向区域id
checked number[] - 选取的元素索引数组
checkedClass string - 选取的类名
page Page - 附属的页面控制器
slideAlign `'top' 'middle' 'bottom'`
subPage Page & { range?: Element } - 子级页面控制器

3.2 主要方法

初始化与更新

init

函数签名:

init() => Area

功能说明:
初始化容器下 item, 赋值 id 及计算 totalCount
返回值: 当前区域对象实例
示例:

// 初始化当前区域的元素和属性
area.init();
updateContainer

函数签名:

updateContainer(container: string | ExtendHTMLElement, scrollContainer?: string | ExtendHTMLElement) => Area

功能说明:
更新容器元素
参数:

// 更新当前区域的容器为新的 DOM 元素
const newContainer = $('new-container');
area.updateContainer(newContainer);
refresh

函数签名:

refresh(index?: number) => Area

功能说明:
区域更新
参数:

// 刷新当前区域,不指定索引则更新所有元素
area.refresh();
// 刷新当前区域,指定索引位置
area.refresh(5);
render

函数签名:

render(h: Content, container?: ExtendHTMLElement, type?: 'append' | 'prepend' | 'replace') => Area

功能说明:
渲染到容器
参数:

// 渲染一个新元素到当前区域的容器
area.render('<div>New Content</div>');
// 以追加方式渲染一个新元素到指定的容器
const newContainer = $('new-container');
area.render('<div>New Content</div>', newContainer, 'append');
// 以函数返回dom字符串的方式渲染
area.render(() => '<div>Dynamic Content</div>');
// 以函数返回dom节点的方式渲染
area.render(() => document.createElement('div'));

子页面控制器相关

createSubPage

函数签名:

createSubPage(range: Element, forceNew?: boolean, currentAreaId?: number, currentIndex?: number) => Page

功能说明:
创建子级页面控制器
参数:

// 创建子页面控制器,并强制新建
const rangeElement = $('sub-page-range');
const subPage = area.createSubPage(rangeElement, true);
subPageIsActive

函数签名:

subPageIsActive(area?: Area, dom?: Element) => boolean

功能说明:
当前子页面控制器是否达到激活条件
参数:

// 检查当前子页面控制器是否处于激活状态
const isSubPageActive = area.subPageIsActive();
if (isSubPageActive) {
  console.log('子页面已激活');
} else {
  console.log('子页面未激活');
}

移动策略相关

setDomMoveStrategy

函数签名:

setDomMoveStrategy(index: number, dir: TKeyDir, handler: number | number[] | Function) => Area

功能说明:
设置 dom 移动策略
参数:

// 设置当前焦点向右移动时,下一个焦点为本区域的索引2
area.setDomMoveStrategy(area.currentIndex, 'right', 2);
// 设置当前焦点向右移动时,跨界到索引为3的区域的目标索引4
area.setDomMoveStrategy(area.currentIndex, 'right', [3, 4]);
// 设置当前焦点向右移动时,执行自定义处理函数
area.setDomMoveStrategy(area.currentIndex, 'right', () => {
  console.log('自定义移动逻辑');
});
getDomMoveStrategy

函数签名:

getDomMoveStrategy(index: number, dir: TKeyDir) => (number | number[] | Function | undefined)

功能说明:
获取 dom 移动策略
参数:

// 获取当前焦点向上移动时的移动策略
const strategy = area.getDomMoveStrategy(area.currentIndex, 'up');
removeDomMoveStrategy

函数签名:

removeDomMoveStrategy(index: number, dir: TKeyDir) => Area

功能说明:
移除某方向 dom 移动策略
参数:

// 移除当前焦点向右移动的策略
area.removeDomMoveStrategy(area.currentIndex, 'right');
clearDomMoveStrategy

函数签名:

clearDomMoveStrategy(index: number) => Area

功能说明:
移除某 dom 移动策略
参数:

// 清空当前焦点的所有移动策略
area.clearDomMoveStrategy(area.currentIndex);
clearAllDomMoveStrategy

函数签名:

clearAllDomMoveStrategy() => Area

功能说明:
清空所有 dom 移动策略
返回值: 当前区域对象
示例:

// 清空所有区域的移动策略
area.clearAllDomMoveStrategy();
urdlStrategy

函数签名:

urdlStrategy(dom: ExtendHTMLElement, index: number, urdl?: string) => Area

功能说明:
快速设置本区域 dom 移动策略 urdl(上右下左)
参数:

// 设置当前焦点向上、向右、向下、向左移动时的目标索引(上:0, 右:1, 下:-1, 左:2)
const currentIndex = area.currentIndex;
const currentDOM = area.getCurrentDom();
if (currentDOM) {
  area.urdlStrategy(currentDOM, currentIndex, '0,1,-1,2');
}

还支持通过dom的urdl属性来设置,例如:

<div class="item" urdl="0,1,-1,2"></div>
moveLeftTo

函数签名:

moveLeftTo(from: number, to: NumberOrNumbers) => Area

功能说明:
指定某元素左移到目标区域索引
参数:

// 将当前焦点的下一个元素向左移动到本区域的第三个索引位置
area.moveLeftTo(area.currentIndex + 1, 3);
// 将当前焦点的上一个元素向左移动到索引为3的区域的目标索引4
area.moveLeftTo(area.currentIndex - 1, [3, 4]);
moveRightTo

函数签名:

moveRightTo(from: number, to: NumberOrNumbers) => Area

功能说明:
指定某元素右移到目标区域索引
参数:

// 将当前焦点的上一个元素向右移动到本区域的倒数第二个索引位置
area.moveRightTo(area.currentIndex - 1, area.totalCount - 2);
// 将当前焦点的下一个元素向右移动到索引为3的区域的目标索引4
area.moveRightTo(area.currentIndex + 1, [3, 4]);
moveUpTo

函数签名:

moveUpTo(from: number, to: NumberOrNumbers) => Area

功能说明:
指定某元素上移到目标区域索引
参数:

// 将当前焦点的下一个元素向上移动到本区域的倒数第一个索引位置
area.moveUpTo(area.currentIndex + 1, area.totalCount - 1);
// 将当前焦点的上一个元素向上移动到索引为3的区域的目标索引4
area.moveUpTo(area.currentIndex - 1, [3, 4]);
moveDownTo

函数签名:

moveDownTo(from: number, to: NumberOrNumbers) => Area

功能说明:
指定某元素下移到目标区域索引
参数:

// 将当前焦点的上一个元素向下移动到本区域的第二个索引位置
area.moveDownTo(area.currentIndex - 1, 2);
// 将当前焦点的下一个元素向下移动到索引为3的区域的目标索引4
area.moveDownTo(area.currentIndex + 1, [3, 4]);

焦点状态查询

startNow

函数签名:

startNow() => boolean

功能说明:
当前焦点是否处于首索引
返回值: 布尔值,表示是否为首索引
示例:

// 检查当前焦点是否位于第一个元素上
if (area.startNow()) {
  console.log('当前焦点在首个元素');
} else {
  console.log('当前焦点不在首个元素');
}
endNow

函数签名:

endNow() => boolean

功能说明:
当前焦点是否处于尾索引
返回值: 布尔值,表示是否为尾索引
示例:

// 检查当前焦点是否位于最后一个元素上
if (area.endNow()) {
  console.log('当前焦点在末个元素');
} else {
  console.log('当前焦点不在末个元素');
}
lightNow

函数签名:

lightNow() => boolean

功能说明:
当前区域是否为焦点区域(未注册到页面控制器为独立区域时无效)
返回值: 布尔值,表示是否为焦点区域
示例:

// 检查当前区域是否为焦点区域
if (area.lightNow()) {
  console.log('当前区域为焦点区域');
} else {
  console.log('当前区域不是焦点区域');
}
effectNow

函数签名:

effectNow() => boolean

功能说明:
当前区域是否有效
返回值: 布尔值,表示是否有效
示例:

// 检查当前区域是否有效
if (area.effectNow()) {
  console.log('当前区域有效');
} else {
  console.log('当前区域无效');
}

多选模式

setCheckBox

函数签名:

setCheckBox(checkedIndex: NumberOrNumbers, checkedClass?: string) => Area

功能说明:
配置多选模式
参数:

// 选择当前区域的第1个和第3个元素为已选择状态
area.setCheckBox([0, 2]);
getChecked

函数签名:

getChecked() => number[]

功能说明:
获取当前选择的元素索引
返回值: 已选择元素的索引数组
示例:

// 获取所有已选择的元素索引
const selectedIndexes = area.getChecked();
console.log('已选择的元素索引:', selectedIndexes);
clearChecked

函数签名:

clearChecked() => Area

功能说明:
清空选择元素索引
返回值: 当前区域对象
示例:

// 清空所有已选择的元素
area.clearChecked();

文字滚动

setMarqueeConfig

函数签名:

setMarqueeConfig(config?: Omit<MarqueeConfig, 'element'>) => MarqueeConfig

功能说明:
配置文字滚动
参数:

// 配置文字滚动速度为30,文字从右向左滚动
const marqueeConfig = area.setMarqueeConfig({
  speed: 30, direction: DIR.RIGHT
});
startMarquee

函数签名:

startMarquee() => Area

功能说明:
开始文字滚动
返回值: 当前区域对象
示例:

// 开始文字滚动
area.startMarquee();
stopMarquee

函数签名:

stopMarquee(remove?: boolean) => Area

功能说明:
停止文字滚动
参数:

// 停止文字滚动并移除
area.stopMarquee(true);

stack及锁定开关

stackOn

函数签名:

stackOn() => Area

功能说明:
启用 stack
返回值: 当前区域对象
示例:

// 启用 stack 功能
area.stackOn();
stackOff

函数签名:

stackOff() => Area

功能说明:
关闭 stack
返回值: 当前区域对象
示例:

// 关闭 stack 功能
area.stackOff();
closeNearby

函数签名:

closeNearby(dir: TKeyDir | 'all', bool?: boolean) => Area

功能说明:
是否关闭某一方向的就近原则
参数:

// 关闭右移的就近原则
area.closeNearby('right');
// 在所有方向上关闭就近原则
area.closeNearby('all');
lockOnLeft

函数签名

lockOnLeft() => Area

功能说明:
锁定左移
返回值: 当前区域对象
示例:

// 锁定左移
area.lockOnLeft();
lockOnRight

函数签名:

lockOnRight() => Area

功能说明:
锁定右移
返回值: 当前区域对象
示例:

// 锁定右移
area.lockOnRight();
lockOnUp

函数签名:

lockOnUp() => Area

功能说明:
锁定上移
返回值: 当前区域对象
示例:

// 锁定上移
area.lockOnUp();
lockOnDown

函数签名:

lockOnDown() => Area

功能说明:
锁定下移
返回值: 当前区域对象
示例:

// 锁定下移
area.lockOnDown();
lockOffLeft

函数签名:

lockOffLeft() => Area

功能说明:
解锁左移
返回值: 当前区域对象
示例:

// 解锁左移
area.lockOffLeft();
lockOffRight

函数签名:

lockOffRight() => Area

功能说明:
解锁右移
返回值: 当前区域对象
示例:

// 解锁右移
area.lockOffRight();
lockOffUp

函数签名:

lockOffUp() => Area

功能说明:
解锁上移
返回值: 当前区域对象
示例:

// 解锁上移
area.lockOffUp();
lockOffDown

函数签名:

lockOffDown() => Area

功能说明:
解锁下移
返回值: 当前区域对象
示例:

// 解锁下移
area.lockOffDown();
lockOnH

函数签名:

lockOnH() => Area

功能说明:
锁定横向移动
返回值: 当前区域对象
示例:

// 锁定横向移动
area.lockOnH();
lockOnV

函数签名:

lockOnV() => Area

功能说明:
锁定纵向移动
返回值: 当前区域对象
示例:

// 锁定纵向移动
area.lockOnV();
lockOffH

函数签名:

lockOffH() => Area

功能说明:
解锁横向移动
返回值: 当前区域对象
示例:

// 解锁横向移动
area.lockOffH();
lockOffV

函数签名:

lockOffV() => Area

功能说明:
解锁纵向移动
返回值: 当前区域对象
示例:

// 解锁纵向移动
area.lockOffV();
lockOn

函数签名:

lockOn() => Area

功能说明:
全部锁定
返回值: 当前区域对象
示例:

// 全部锁定
area.lockOn();
lockOff

函数签名:

lockOff() => Area

功能说明:
全部解锁
返回值: 当前区域对象
示例:

// 全部解锁
area.lockOff();
crossLockOn

函数签名:

crossLockOn() => Area

功能说明:
锁定跨界
返回值: 当前区域对象
示例:

// 锁定跨界
area.crossLockOn();
crossLockOff

函数签名:

crossLockOff() => Area

功能说明:
解锁跨界
返回值: 当前区域对象
示例:

// 解锁跨界
area.crossLockOff();

配置管理

fusionConfig

函数签名:

fusionConfig(options?: Partial<Pick<Area, AreaPick>>, replace?: boolean) => Area

功能说明:
融合配置
参数:

// 融合部分配置
area.fusionConfig({ closeDownFix: true, openMarquee: true });
// 替换原有配置
area.fusionConfig({ record: true, closeDownFix: true, openMarquee: true }, true);
// 自定义普通、获焦、驻留等样式
area.fusionConfig({
  focusClass: 'focus-class', // 获焦样式
  blurClass: 'blur-class', // 失焦样式
  selectClass: 'select-class', // 驻留样式
  normalClass: 'normal-class', // 普通样式
  commonClass: 'common-class' // 通用样式,元素公共类,用于焦点dom查找
});
setCustomSlide

函数签名:

setCustomSlide(value: NumberOrNumbers) => Area

功能说明:
定制当前区域的页面滑动量
参数:

// 设置自定义滑动量为向上250px
area.setCustomSlide(-250);
setOutMoveDir

函数签名:

setOutMoveDir(outMoveDir?: OutMoveDir | INumbers) => Area

功能说明:
设置越界指向区域 id
参数:

// 设置数组格式越界指向区域id
area.setOutMoveDir([1, 2, [3, 4], 5]);
// 设置对象格式越界指向区域id
area.setOutMoveDir({ up: 1, left: [2, 3], down: [4, 5], right: -1 });
turnPageConfig

函数签名:

turnPageConfig(pageSize?: number, totalPage?: number, cyclicTurnPage?: boolean) => Area

功能说明:
区域翻页配置
参数:

// 配置每页显示10个元素,总页数为5,不循环翻页
area.turnPageConfig(10, 5);

加载配置

loadConfig

函数签名:

loadConfig(config: AreaLoadConfig) => Area

功能说明:
区域加载逻辑配置
参数:

// 普通加载配置
area.loadConfig({
  load: () => {
    return {
      data: [/** 区域数据 */],
      content: `<div>渲染的内容</div>`
    }
  },
  loaded: () => {
    console.log('加载完成');
  }
});
// 使用回调的加载配置
area.loadConfig({
  load: (/** 加载回调函数 */ handleCallBack) => {
    handleCallBack({
      data: [/** 区域数据 */],
      content: `<div>渲染的内容</div>`
    });
  }
});
// 延迟加载配置
area.loadConfig({
  delay: 1000,
  load: () => {
    return {
      data: [/** 区域数据 */],
      content: `<div>渲染的内容</div>`
    }
  }
});
// 主动执行加载逻辑
area.activeLoad();
// 分页加载配置
area.loadConfig({
  size: 10,
  load: (/** 当前加载的页数 */ pageIndex) => {
    return {
      data: [/** 区域数据 */],
      content: `<div>渲染的内容</div>`,
      pageIndex: pageIndex,
      total: 100
    }
  },
  firstLoaded: () => {
    console.log('首次加载完成');
  },
  loaded: (/** 当前加载的页数 */ pageIndex, /** 是否来自当前页加载数据 */ current) => {
    console.log(`加载第${pageIndex}页数据完成,是否来自当前页:${current}`);
  }
});
// 使用回调的分页加载配置
area.loadConfig({
  size: 10,
  load: (/** 当前加载的页数 */ pageIndex, /** 加载回调函数 */ handleCallBack) => {
    handleCallBack({
      data: [/** 区域数据 */],
      content: `<div>渲染的内容</div>`,
      pageIndex: pageIndex,
      total: 100
    });
  }
});
changeLoadConfig

函数签名:

changeLoadConfig(config: AreaLoadConfig) => Area

功能说明:
改变加载配置
参数:

// 改变加载配置
area.changeLoadConfig({
  container: $('newContainer'), // 改变加载内容的容器元素
  lazyLoad: 500 // 懒加载区域图片的延迟时间改为500ms
});
activeLoad

函数签名:

activeLoad(cb?: Function) => Area

功能说明:
主动执行加载逻辑
参数:

// 主动执行加载逻辑
area.activeLoad();
// 主动执行加载逻辑,并回调
area.activeLoad(() => {
  console.log('加载完成');
});
connect

函数签名:

connect(area: Area) => Area

功能说明:
连接联动的下级区域控制器,联动后当父区域加载完成后,子区域的加载逻辑也会被触发。
参数:

// 连接联动的下级区域控制器
parentArea.connect(childArea);
parentArea.loadConfig({
  load: () => {
    return {
      data: [/** 区域数据 */],
      content: `<div>渲染的内容</div>`
    }
  }
});
childArea.loadConfig({
  load: () => {
    return {
      data: [/** 区域数据 */],
      content: `<div>渲染的内容</div>`
    }
  }
});
lazyLoadImg

函数签名:

lazyLoadImg(imageClass?: string, error?: string | ((image: ExtendHTMLElement) => string), force?: boolean) => Area

功能说明:
懒加载区域图片,加载完成后自动为图片元素添加 'loaded' 类名。
参数:

// 懒加载区域类名默认为img的图片元素
area.lazyLoadImg();
// 使用自定义的图片类名和错误处理方式
area.lazyLoadImg('custom-class', () => 'error-image.png');
<!-- 通过元素属性配置异常加载图片 -->
<img class="img" error-src="error-image.png">
setLoader

函数签名:

setLoader(config?: LoaderConfig) => Area

功能说明:
配置区域加载器
参数:

// 配置区域加载器
area.setLoader({
  width: 100, height: 100, color: 'red', content: () => '加载中...'
});
showLoader

函数签名:

showLoader() => Area

功能说明:
显示 loader
返回值: 当前区域对象
示例:

// 显示 loader
area.showLoader();
hideLoader

函数签名:

hideLoader() => Area

功能说明:
隐藏 loader
返回值: 当前区域对象
示例:

// 隐藏 loader
area.hideLoader();
removeLoader

函数签名:

removeLoader() => Area

功能说明:
移除 loader
返回值: 当前区域对象
示例:

// 移除 loader
area.removeLoader();
loadMore

函数签名:

loadMore(currentIndex?: number, callback?: () => void) => Area

功能说明:
分页加载更多
参数:

// 基于当前索引分页加载更多
area.loadMore();
// 基于指定索引分页加载更多
area.loadMore(1, () => console.log('加载完成'));
resetLoaded

函数签名:

resetLoaded(emptyContainer?: ExtendHTMLElement) => Area

功能说明:
重置分页加载
参数:

// 重置分页加载
area.resetLoaded();
// 重置分页加载,并清空指定容器
area.resetLoaded($('container'));

数据操作

getDomList

函数签名:

getDomList() => ExtendHTMLElement[]

功能说明:
获取区域下存在的 dom 列表
返回值: dom 元素数组
示例:

// 获取区域下存在的 dom 列表
const doms = area.getDomList();
getCurrentDom

函数签名:

getCurrentDom() => ExtendHTMLElement

功能说明:
获取当前焦点 dom 元素
返回值: 当前焦点的 dom 元素
示例:

// 获取当前焦点 dom 元素
const currentDom = area.getCurrentDom();
getTargetDom

函数签名:

getTargetDom(index?: number) => ExtendHTMLElement

功能说明:
获取目标索引 dom 元素
参数:

// 获取第一个元素的 dom 元素
const firstDom = area.getTargetDom(0);
getCurrentRow

函数签名:

getCurrentRow() => number

功能说明:
获取当前焦点在当前区域的行数 (仅在启用行列分区时生效)
返回值: 当前焦点的行数
示例:

// 获取当前焦点在当前区域的行数
const currentRow = area.getCurrentRow();
getCurrentCol

函数签名:

getCurrentCol() => number

功能说明:
获取当前焦点在当前区域的列数 (仅在启用行列分区时生效)
返回值: 当前焦点的列数
示例:

// 获取当前焦点在当前区域的列数
const currentCol = area.getCurrentCol();
getDataByIndex

函数签名:

getDataByIndex(index?: number) => any

功能说明:
根据索引获取数据
参数:

// 根据索引获取数据
const data = area.getDataByIndex(5);
// 获取当前索引的数据
const currentData = area.getDataByIndex();
setDataByPage

函数签名:

setDataByPage(data: any[], pageIndex?: number) => Area

功能说明:
设置指定页的数据
参数:

// 设置第一页的数据
area.setDataByPage([{ id: 1, name: '张三' }]);
// 设置第二页的数据
area.setDataByPage([{ id: 2, name: '李四' }], 2);
getDataByPage

函数签名:

getDataByPage(pageIndex?: number) => any

功能说明:
获取指定页的数据
参数:

// 获取第一页的数据
const pageData = area.getDataByPage(1);
calcNearby

函数签名:

calcNearby(dir: TKeyDir) => Nearest

功能说明:
跨界区域及焦点索引计算
参数:

// 计算上移的跨界信息,返回跨界区域及索引信息
const { nearestArea, nearestIndex } = area.calcNearby('up');

焦点控制

showFocus

函数签名:

showFocus() => Area

功能说明:
显示焦点
返回值: 当前区域对象
示例:

// 显示焦点
area.showFocus();
focusTo

函数签名:

focusTo(index?: number) => void

功能说明:
切换焦点到目标索引
参数:

// 切换焦点到第一个元素
area.focusTo(0);
focus

函数签名:

focus() => Area

功能说明:
上焦
返回值: 当前区域对象
示例:

// 上焦
area.focus();
blur

函数签名:

blur(ignore?: boolean) => Area

功能说明:
失焦
参数:

// 失焦
area.blur();
normal

函数签名:

normal() => Area

功能说明:
恢复原状
返回值: 当前区域对象
示例:

// 恢复原状
area.normal();
setRecord

函数签名:

setRecord(index?: number) => Area

功能说明:
设置记录索引
参数:

// 设置第一个元素为驻留元素
area.setRecord(0);
clearRecord

函数签名:

clearRecord() => Area

功能说明:
清除记录索引
返回值: 当前区域对象
示例:

// 清除驻留元素
area.clearRecord();
setSelect

函数签名:

setSelect(forceSelect?: boolean) => Area

功能说明:
设置 select 类
参数:

// 设置当前焦点为选中状态
area.setSelect();
changeSelect

函数签名:

changeSelect(index?: number) => Area

功能说明:
切换驻留元素

注意:该方法会清除驻留并设置记忆焦点,同时会滚动到指定索引位置,并设置驻留。如果当前是焦点区域且记忆焦点存在,则会清除驻留并设置为上焦状态。如果不是焦点区域,则只滚动到指定索引位置并设置驻留。

参数:

// 切换驻留元素到第一个
area.changeSelect(0);
clearSelect

函数签名:

clearSelect(index?: number) => Area

功能说明:
清除 select 类
参数:

// 清除第一个元素的选中状态
area.clearSelect(0);

滚动控制

setScrollConfig

函数签名:

setScrollConfig(config?: ScrollConfig) => Area

功能说明:
滑动配置
参数:

// 设置滚动配置
area.fusionConfig({
  colCount: 5, // 滑动配置为fixed模式下需要区域明确指定焦点元素的列数
}).setScrollConfig({
  /** 模式 auto-到达边界触发滑动 computed-自动计算滑动量 fixed-指定起始位置 screen-按元素所在屏整屏滑动 cycle-列表循环滚动 rate-按视口长度比例计算滚动 item-按焦点元素位置自动计算位置, 默认fixed(注意:fixed模式滑动失效时请指定明确的行列数或maxCount值)*/
  mode: 'fixed',
  scrollDir: 'v', // 滑动方向,可选 'v' | 'h', 默认垂直滚动
  maxCount: 2, // 可视区最大行列数,纵向滑动时看行数,横向滑动时看列数
  step: 240, // 滑动步长
  // 满足滑动的条件, 不传则没有限制, 传入数值时按指定数值量滑动
  condition: (value) => {
    return 100; // 使用指定滑动值,实际开发场景下为动态计算的值
    return true; // 使用默认的value滑动
  }
});
scrollMove

函数签名:

scrollMove(speed?: number) => Area

功能说明:
执行容器滚动
参数:

// 执行容器滚动
area.scrollMove();
scrollTo

函数签名:

scrollTo(index: number, speed?: number) => Area

功能说明:
指定滑动位置
参数:

// 滑动到第三个元素的位置
area.scrollTo(2);
resetScroll

函数签名:

resetScroll(speed?: number) => Area

功能说明:
重置区域容器滑动
参数:

// 重置区域容器滑动
area.resetScroll();
setSlideFocusConfig

函数签名:

setSlideFocusConfig(config: SlideFocusConfig) => Area

功能说明:
设置焦点框滑动
参数:

// 设置焦点框滑动
area.setSlideFocusConfig({
  slide: true, borderWidth: 3, borderType: 'dashed', borderColor: '#f00'
});
setCyclicRollingConfig

函数签名:

setCyclicRollingConfig(config?: CyclicRollingConfig) => Area

功能说明:
设置循环滚动
参数:

// 设置循环滚动配置 
area.setCyclicRolling({ scroll: true, scrollDir: 'h', headCycle: true });
setCyclic

函数签名:

setCyclic(index: number, speed?: number) => Area

功能说明:
指定滚动定位索引
参数:

// 设置循环滚动到第三个元素的位置
area.setCyclic(2);

事件监听及功能钩子

defaultLeft

函数签名:

defaultLeft() => Area

功能说明:
默认左移处理
返回值: 当前区域对象
示例:

// 执行默认左移处理
area.defaultLeft();
moveLeft

函数签名:

moveLeft() => Area

功能说明:
左移
返回值: 当前区域对象
示例:

// 左移
area.moveLeft();
defaultRight

函数签名:

defaultRight() => Area

功能说明:
默认右移处理
返回值: 当前区域对象
示例:

// 执行默认右移处理
area.defaultRight();
moveRight

函数签名:

moveRight() => Area

功能说明:
右移
返回值: 当前区域对象
示例:

// 右移
area.moveRight();
defaultUp

函数签名:

defaultUp() => Area

功能说明:
默认上移处理
返回值: 当前区域对象
示例:

// 执行默认上移处理
area.defaultUp();
moveUp

函数签名:

moveUp() => Area

功能说明:
上移
返回值: 当前区域对象
示例:

// 上移
area.moveUp();
defaultDown

函数签名:

defaultDown() => Area

功能说明:
默认下移处理
返回值: 当前区域对象
示例:

// 执行默认下移处理
area.defaultDown();
moveDown

函数签名:

moveDown() => Area

功能说明:
下移
返回值: 当前区域对象
示例:

// 下移
area.moveDown();
pagingListener

函数签名:

pagingListener(currentPage: number, totalPage: number) => void

功能说明:
监听页数变化
参数:

// 设置页数变化监听
area.setPagingListener((currentPage, totalPage) => {
  console.log(`当前页面: ${currentPage}, 总页面数: ${totalPage}`);
});
setSelectListener

函数签名:

setSelectListener(listener: Function) => Area

功能说明:
设置驻留事件监听
参数:

// 设置驻留事件监听
area.setSelectListener((dom, recordIndex) => {
  console.log('当前驻留的DOM:', dom);
  console.log('记录索引:', recordIndex);
});
scrollListener

函数签名:

scrollListener(outcrop: boolean, reach: boolean) => void

功能说明:
监听滑动事件
参数:

// 设置滑动事件监听
area.fusionConfig({
  scrollListener: (outcrop, reach) => {
    if (outcrop) {
      console.log('有滑动偏移');
    }
    if (reach) {
      console.log('到达最大偏移量');
    }
  }
});
setScrollListener

函数签名:

setScrollListener(listener: Function) => Area

功能说明:
设置滑动事件监听
参数:

// 设置滑动事件监听
area.setScrollListener((outcrop, reach) => {
  if (outcrop) {
    console.log('有滑动偏移');
  }
  if (reach) {
    console.log('到达最大偏移量');
  }
});
areaIn

函数签名:

areaIn(index: number) => void

功能说明:
进区域事件
参数:

// 进区域事件处理
area.fusionConfig({
  areaIn: (currentIndex) => {
    console.log('进区域事件', currentIndex);
  }
});
areaOut

函数签名:

areaOut(index: number) => void

功能说明:
出区域事件
参数:

// 出区域事件处理
area.fusionConfig({
  areaOut: (currentIndex) => {
    console.log('出区域事件', currentIndex);
  }
});
borderLeft

函数签名:

borderLeft(currentIndex: number) => boolean

功能说明:
左边界事件
参数:

// 左边界事件处理,不执行默认左边界事件
area.fusionConfig({
  borderLeft: (currentIndex) => {
    console.log('自定义左边界事件', currentIndex);
  }
});
// 左边界事件处理,执行默认左边界事件
area.fusionConfig({
  borderLeft: (currentIndex) => {
    console.log('自定义左边界事件', currentIndex);
    return true; // 执行默认左边界事件
  }
});
borderRight

函数签名:

borderRight(currentIndex: number) => boolean

功能说明:
右边界事件
参数:

// 右边界事件处理,不执行默认右边界事件
area.fusionConfig({
  borderRight: (currentIndex) => {
    console.log('自定义右边界事件', currentIndex);
  }
});
// 右边界事件处理,执行默认右边界事件
area.fusionConfig({
  borderRight: (currentIndex) => {
    console.log('自定义右边界事件', currentIndex);
    return true; // 执行默认右边界事件
  }
});
borderUp

函数签名:

borderUp(currentIndex: number) => boolean

功能说明:
上边界事件
参数:

// 上边界事件处理,不执行默认上边界事件
area.fusionConfig({
  borderUp: (currentIndex) => {
    console.log('自定义上边界事件', currentIndex);
  }
});
// 上边界事件处理,执行默认上边界事件
area.fusionConfig({
  borderUp: (currentIndex) => {
    console.log('自定义上边界事件', currentIndex);
    return true; // 执行默认上边界事件
  }
});
borderDown

函数签名:

borderDown(currentIndex: number) => boolean

功能说明:
下边界事件
参数:

// 下边界事件处理,不执行默认下边界事件
area.fusionConfig({
  borderDown: (currentIndex) => {
    console.log('自定义下边界事件', currentIndex);
  }
});
// 下边界事件处理,执行默认下边界事件
area.fusionConfig({
  borderDown: (currentIndex) => {
    console.log('自定义下边界事件', currentIndex);
    return true; // 执行默认下边界事件
  }
});
customLeft

函数签名:

customLeft(currentIndex: number) => boolean

功能:
自定义左移
参数:

// 自定义左移,不执行默认左移
area.fusionConfig({
  customLeft: (currentIndex) => {
    console.log('自定义左移', currentIndex);
  }
});
// 自定义左移,执行默认左移
area.fusionConfig({
  customLeft: (currentIndex) => {
    console.log('自定义左移', currentIndex);
    return true; // 执行默认左移
  }
});
customRight

函数签名:

customRight(currentIndex: number) => boolean

功能:
自定义右移
参数:

// 自定义右移,不执行默认右移
area.fusionConfig({
  customRight: (currentIndex) => {
    console.log('自定义右移', currentIndex);
  }
});
// 自定义右移,执行默认右移
area.fusionConfig({
  customRight: (currentIndex) => {
    console.log('自定义右移', currentIndex);
    return true; // 执行默认右移
  }
});
customUp

函数签名:

customUp(currentIndex: number) => boolean

功能:
自定义上移
参数:

// 自定义上移,不执行默认上移
area.fusionConfig({
  customUp: (currentIndex) => {
    console.log('自定义上移', currentIndex);
  }
});
// 自定义上移,执行默认上移
area.fusionConfig({
  customUp: (currentIndex) => {
    console.log('自定义上移', currentIndex);
    return true; // 执行默认上移
  }
});
customDown

函数签名:

customDown(currentIndex: number) => boolean

功能:
自定义下移
参数:

// 自定义下移,不执行默认下移
area.fusionConfig({
  customDown: (currentIndex) => {
    console.log('自定义下移', currentIndex);
  }
});
// 自定义下移,执行默认下移
area.fusionConfig({
  customDown: (currentIndex) => {
    console.log('自定义下移', currentIndex);
    return true; // 执行默认下移
  }
});
keyOk

函数签名:

keyOk(currentIndex: number) => any

功能说明:
确认键
参数:

// 确认键不拦截页面控制默认确认事件
area.fusionConfig({
  keyOk: (currentIndex) => {
    console.log('确认键', currentIndex);
  }
});
// 确认键拦截页面控制默认确认事件
area.fusionConfig({
  keyOk: (currentIndex) => {
    console.log('确认键', currentIndex);
    return true; // 拦截页面控制默认确认逻辑
  }
});
keyBack

函数签名:

keyBack(currentIndex: number) => any

功能说明:
返回键
参数:

// 返回键不拦截页面控制默认返回事件
area.fusionConfig({
  keyBack: (currentIndex) => {
    console.log('返回键', currentIndex);
  }
});
// 返回键拦截页面控制默认返回事件
area.fusionConfig({
  keyBack: (currentIndex) => {
    console.log('返回键', currentIndex);
    return true; // 拦截页面控制默认返回逻辑
  }
});
keyPrevPage

函数签名:

keyPrevPage(currentPage: number) => void

功能说明:
上一页
参数:

// 上一页
area.fusionConfig({
  keyPrevPage: (currentPage) => {
    console.log('上一页', currentPage);
  }
});
keyNextPage

函数签名:

keyNextPage(currentPage: number) => void

功能说明:
下一页
参数:

// 下一页
area.fusionConfig({
  keyNextPage: (currentPage) => {
    console.log('下一页', currentPage);
  }
});
focusBefore

函数签名:

focusBefore(currentIndex: number) => void

功能说明:
上焦前回调钩子
参数:

// 上焦前回调钩子
area.fusionConfig({
  focusBefore: (currentIndex) => {
    console.log('上焦前', currentIndex);
  }
});
focusAfter

函数签名:

focusAfter(currentIndex: number) => void

功能说明:
上焦后回调钩子
参数:

// 上焦后回调钩子
area.fusionConfig({
  focusAfter: (currentIndex) => {
    console.log('上焦后', currentIndex);
  }
});
blurBefore

函数签名:

blurBefore(currentIndex: number) => void

功能说明:
失焦前回调钩子
参数:

// 失焦前回调钩子
area.fusionConfig({
  blurBefore: (currentIndex) => {
    console.log('失焦前', currentIndex);
  }
});
blurAfter

函数签名:

blurAfter(currentIndex: number) => void

功能说明:
失焦后回调钩子
参数:

// 失焦后回调钩子
area.fusionConfig({
  blurAfter: (currentIndex) => {
    console.log('失焦后', currentIndex);
  }
});
cyclicRollingAfter

函数签名:

cyclicRollingAfter(both: Both) => void

功能说明:
循环焦点切换后的最小与最大位置索引
参数:

// 循环焦点切换后的最小与最大位置索引
area.fusionConfig({
  cyclicRollingAfter: (both) => {
    console.log('最小位置索引', both.minIndex);
    console.log('最大位置索引', both.maxIndex);
  }
});
inViewPoint

函数签名:

inViewPoint(viewPointOnce: boolean) => void

功能说明:
进入视口
参数:

// 进入视口
area.fusionConfig({
  inViewPoint: (viewPointOnce) => {
    console.log('进入视口', viewPointOnce);
  }
});
outViewPoint

函数签名:

outViewPoint() => void

功能说明:
离开视口
示例:

// 离开视口
area.fusionConfig({
  outViewPoint: () => {
    console.log('离开视口');
  }
});
moveViewPoint

函数签名:

moveViewPoint() => void

功能说明:
在视口内移动
示例:

// 在视口内移动
area.fusionConfig({
  moveViewPoint: () => {
    console.log('视口移动');
  }
});

4. Floor楼层类

Floor类继承自Area,用于简化区域实例的生成及事件管理。

4.1 主要方法

setOutMoveFloor

函数签名:

setOutMoveFloor(outMoveDir: FloorOutMoveDir) => Floor

功能说明:
设置楼层在各方向指向的楼层。
参数:

// 设置楼层在各方向指向的楼层
floor.setOutMoveFloor({
  up: prevFloor,
  down: nextFloor
});

pile_v

函数签名:

pile_v(floor: Floor, type: 'push' | 'replace' = 'replace') => Floor

功能说明:
纵向堆叠楼层。
参数:

// 纵向堆叠楼层
floor.pile_v(nextFloor);

pile_h

函数签名:

pile_h(floor: Floor, type: 'push' | 'replace' = 'replace') => Floor

功能说明:
横向堆叠楼层。
参数:

// 横向堆叠楼层
floor.pile_h(nextFloor);

remove

函数签名:

remove() => Floor

功能说明:
从楼层管理器中移除当前楼层。
示例:

// 从楼层管理器中移除当前楼层
floor.remove();

build

函数签名:

build(page = getPageInstance()) => Floor

功能说明:
构建楼层、加入FloorManager并注册楼层区域到指定页面控制器。
参数:

// 构建楼层
floor.build();

5. Page页面控制器

Page类负责页面级别的焦点导航管理,与Area类协同工作。

5.1 主要属性

属性名 类型 默认值 属性说明
maxSlideValue number 0 页面滑动容器最大滑动量
keepArea Area - 始终持有焦点的区域记忆的区域控制器
supArea Area - 父级区域控制器
operated boolean false 是否有过按键交互行为
firstLoad boolean true 首次加载标志
longPress boolean false 长按标识
moveLock boolean false 移动按键锁 (只针对方向键)
moveHLock boolean false 横向按键锁
moveVLock boolean false 纵向按键锁
lock boolean false 全局按键锁
currentAreaId number 0 当前区域索引
currentIndex number 0 当前焦点索引
areas Area[] [] 持有的区域控制器
slideBox ExtendHTMLElement - 当前的滑动的焦点 dom
slideContainer ExtendHTMLElement - 页面滑动容器
slideValue number 0 页面滑动容器当前滑动量
slideConfig SlideConfig - 滑动配置
direction TKeyDir - 当前按键方向
slideDir TScrollDir - 滑动容器当前滑动方向
screenIndex number 0 当前屏索引
screenConfig ScreenConfig - 切屏配置
shakeConfig ShakeConfig - 边界抖动配置
total number 0 持有的区域控制器总数

5.2 主要方法

区域管理

setAreas

函数签名:

setAreas(areas: Area[]) => Page

功能说明:
设置页面持有的区域控制器数组。
参数:

// 设置页面持有的区域控制器
page.setAreas([area1, area2]);
addAreas

函数签名:

addAreas(areas: Area[]) => Page

功能说明:
向页面添加区域控制器。
参数:

// 向页面添加区域控制器
page.addAreas([area3, area4]);
removeAreas

函数签名:

removeAreas(areas: Area[]) => Page

功能说明:
从页面移除区域控制器。
参数:

// 从页面移除区域控制器
page.removeAreas([area1]);
setCommonClass

函数签名:

setCommonClass(config: CommonClassConfig) => Page

功能说明:
统一所有区域控制器元素样式类配置。
参数:

// 设置通用类
page.setCommonClass({
  excludeAreaIds: [1, 2],
  focusClass: 'item on_focus',
  blurClass: 'item'
});
getCurrentArea

函数签名:

getCurrentArea() => Area | null

功能说明:
获取当前区域控制器。
返回值: 当前区域控制器或null,如果没有找到则返回null。
示例:

// 获取当前区域控制器
const currentArea = page.getCurrentArea();
if (currentArea) {
  console.log('当前区域', currentArea);
} else {
  console.log('未找到当前区域');
}
getLastArea

函数签名:

getLastArea() => Area | null

功能说明:
获取末位区域控制器。
返回值: 末位区域控制器或null,如果没有找到则返回null。
示例:

// 获取末位区域控制器
const lastArea = page.getLastArea();
if (lastArea) {
  console.log('末位区域', lastArea);
} else {
  console.log('未找到末位区域');
}

锁状态管理

lockOn

函数签名:

lockOn() => Page

功能说明:
启用全局按键锁。
返回值: Page实例,支持链式调用。
示例:

// 启用全局按键锁
page.lockOn();
lockOff

函数签名:

lockOff() => Page

功能说明:
关闭全局按键锁。
返回值: Page实例,支持链式调用。
示例:

// 关闭全局按键锁
page.lockOff();
moveLockOn

函数签名:

moveLockOn() => Page

功能说明:
启用移动按键锁(只针对方向键)。
返回值: Page实例,支持链式调用。
示例:

// 启用移动按键锁
page.moveLockOn();
moveLockOff

函数签名:

moveLockOff() => Page

功能说明:
关闭移动按键锁。
返回值: Page实例,支持链式调用。
示例:

// 关闭移动按键锁
page.moveLockOff();
moveHLockOn

函数签名:

moveHLockOn() => Page

功能说明:
启用横向按键锁。
返回值: Page实例,支持链式调用。
示例:

// 启用横向按键锁
page.moveHLockOn();
moveHLockOff

函数签名:

moveHLockOff() => Page

功能说明:
关闭横向按键锁。
返回值: Page实例,支持链式调用。
示例:

// 关闭横向按键锁
page.moveHLockOff();
moveVLockOn

函数签名:

moveVLockOn() => Page

功能说明:
启用纵向按键锁。
返回值: Page实例,支持链式调用。
示例:

// 启用纵向按键锁
page.moveVLockOn();
moveVLockOff

函数签名:

moveVLockOff() => Page

功能说明:
关闭纵向按键锁。
返回值: Page实例,支持链式调用。
示例:

// 关闭纵向按键锁
page.moveVLockOff();

焦点控制

moveLeft

函数签名:

moveLeft() => Page

功能说明:
向左移动焦点。
返回值: Page实例,支持链式调用。
示例:

// 向左移动焦点
page.moveLeft();
moveRight

函数签名:

moveRight() => Page

功能说明:
向右移动焦点。
返回值: Page实例,支持链式调用。
示例:

// 向右移动焦点
page.moveRight();
moveUp

函数签名:

moveUp() => Page

功能说明:
向上移动焦点。
返回值: Page实例,支持链式调用。
示例:

// 向上移动焦点
page.moveUp();
moveDown

函数签名:

moveDown() => Page

功能说明:
向下移动焦点。
返回值: Page实例,支持链式调用。
示例:

// 向下移动焦点
page.moveDown();
changeFocus

函数签名:

changeFocus(areaId?: number, areaIndex?: number, uncheck?: boolean, correct?: boolean, normal?: boolean) => Page

功能说明:
强制焦点移动。
参数:

// 强制焦点切换到指定位置
page.changeFocus(1, 2);

滑动控制

setSlidePage

函数签名:

setSlidePage(slideContainer: string | ExtendHTMLElement, slideConfig?: SlideConfig) => Page

功能说明:
设置页面跨区域滑动。
参数:

// 设置页面跨区域滑动
page.setSlidePage('my-container', { 
  slideDir: 'v', // 滑动方向为垂直
  speed: 100, // 滑动速度为100
  condition: (value) => value > 100 // 当滑动值大于100时满足条件
  complete: (value) => console.log('滑动结束', value) // 滑动结束回调
});
setSlideFocusConfig

函数签名:

setSlideFocusConfig(config: SlideFocusConfig) => Page

功能说明:
全局设置滑动焦点。
参数:

// 全局设置滑动焦点
page.setSlideFocusConfig({
  excludeAreaIds: [1, 2],
  slide: true,
  borderWidth: 2,
  borderType: 'solid',
  borderColor: '#000'
});
getSlideValue

函数签名:

getSlideValue(area: Area | number) => any

功能说明:
获取指定区域的滑动值。
参数:

// 获取第一个区域的滑动值
const value = page.getSlideValue(0);
console.log('滑动值', value);
slidePage

函数签名:

slidePage(completeSlide?: Function) => Page

功能说明:
执行页面滑动,一般由框架自动调用,无需手动调用。
参数:

// 执行页面滑动并设置滑动结束回调
page.slidePage((value) => console.log('滑动结束', value));
slideTo

函数签名:

slideTo(value: Area | number, completeSlide?: Function) => Page

功能说明:
页面滑动到指定区域。
参数:

// 页面滑动到第一个区域并设置滑动结束回调
page.slideTo(0, (value) => console.log('滑动结束', value));
resetSlidePage

函数签名:

resetSlidePage() => Page

功能说明:
重置页面滑动。
返回值: Page实例,支持链式调用。
示例:

// 重置页面滑动
page.resetSlidePage();
resetScrollArea

函数签名:

resetScrollArea(excludeAreaIds?: number[], speed?: number) => Page

功能说明:
重置所有区域滑动。
参数:

// 重置除第一个和第二个区域的滚动并设置滑动速度为100
page.resetScrollArea([1, 2], 100);

切屏管理

setScreenConfig

函数签名:

setScreenConfig(config: ScreenConfig) => Page

功能说明:
设置切屏配置。
参数:

// 设置切屏配置
page.setScreenConfig({
  slideDir: 'h', // 滑动方向为水平
  speed: 100, // 切屏速度为100
  area: navArea, // 关联的区域控制器
  start: (index) => console.log('开始切换', index), // 开始切换回调
  complete: (index) => console.log('切换完成', index) // 切换完成回调
});
changeScreen

函数签名:

changeScreen(index: number, speed?: number, callback?: Function) => Page

功能说明:
执行页面切屏。
参数:

// 执行页面切屏到第二个屏幕并设置切换速度和回调
page.changeScreen(1, 100, () => console.log('切换完成'));
prevScreen

函数签名:

prevScreen(speed?: number) => Page

功能说明:
前一屏。
参数:

// 前一屏并设置切换速度
page.prevScreen(100);
nextScreen

函数签名:

nextScreen(speed?: number) => Page

功能说明:
后一屏。
参数:

// 后一屏并设置切换速度
page.nextScreen(100);

抖动配置

注意:在焦点元素添加shake-disabled属性可以禁用当前焦点元素的抖动效果。

<div class="item" shake-disabled>...</div>
setShakeConfig

函数签名:

setShakeConfig(config: ShakeConfig) => Page

功能说明:
设置抖动配置。
参数:

// 设置抖动配置
page.setShakeConfig({
  horizontal: 'my-horizontal', // 水平方向抖动类名为'my-horizontal'
  vertical: 'my-vertical', // 垂直方向抖动类名为'my-vertical'
  shakeClass: 'my-shake', // 抖动元素类名为'my-shake'
  duration: 500, // 动画时间为500毫秒
  progress: (direction) => console.log('抖动中', direction) // 抖动过程中再执行的回调
});
setShakeWrapper

函数签名:

setShakeWrapper(area: Area) => Page

功能说明:
为指定区域设置抖动包裹容器。
参数:

// 为第一个区域设置抖动包裹容器
page.setShakeWrapper(areas[0]);

事件监听及功能钩子

pageInit

函数签名:

pageInit(floor?: number | Area, index?: number) => Page

功能说明:
初始化全局按键监听。
参数:

// 初始化页面并设置默认落焦到第一个区域的第二个元素
page.pageInit(0, 1);
checkViewpoint

函数签名:

checkViewpoint() => Page

功能说明:
检测视口变化。
返回值: Page实例,支持链式调用。
示例:

// 执行视口变化检测
page.checkViewpoint();
inViewListener

函数签名:

inViewListener(areas: Area[]) => void

功能说明:
监听进入视口的区域。
参数:

// 实现进入视口区域的监听
page.inViewListener = (areas) => {
  console.log('进入视口的区域', areas);
};
outViewListener

函数签名:

outViewListener(areas: Area[]) => void

功能说明:
监听离开视口的区域。
参数:

// 实现离开视口区域的监听
page.outViewListener = (areas) => {
  console.log('离开视口的区域', areas);
};
moveViewListener

函数签名:

moveViewListener(areas: Area[]) => void

功能说明:
监听在视口内的区域。
参数:

// 实现在视口内区域的监听
page.moveViewListener = (areas) => {
  console.log('在视口内的区域', areas);
};
areaChange

函数签名:

areaChange(from: Area, to: Area) => void

功能说明:
区域实例切换。
参数:

// 实现区域切换监听
page.areaChange = (from, to) => {
  console.log(`从${from.id}切换到${to.id}`);
};
focusListener

函数签名:

focusListener(currentAreaId: number, currentIndex: number) => void

功能说明:
监听焦点变化。
参数:

// 实现焦点变化的监听
page.focusListener = (areaId, index) => {
  console.log(`当前聚焦在区域${areaId}, 第${index}个元素`);
};
borderListener

函数签名:

borderListener(area: Area, dir: TKeyDir) => void

功能说明:
监听边界事件。
参数:

// 实现边界事件的监听
page.borderListener = (area, direction) => {
  console.log(`区域${area.id},在${direction}边界触发`);
};
keyLongPress

函数签名:

keyLongPress() => void

功能说明:
长按事件。
示例:

// 实现长按事件的监听
page.keyLongPress = () => {
  console.log('按键被长按');
};
keyLongPressEnd

函数签名:

keyLongPressEnd() => void

功能说明:
长按结束事件。
示例:

// 实现长按结束的监听
page.keyLongPressEnd = () => {
  console.log('长按结束');
};
getKeyCode

函数签名:

getKeyCode(keyCode: number) => void

功能说明:
获取当前键值。
参数:

// 实现按键监听
page.getKeyCode = (code) => {
  console.log(`捕获到${code}号按键`);
};
dispatchKey

函数签名:

dispatchKey(keyCode: number) => boolean

功能说明:
分发按键事件。
参数:

// 实现按键事件的分发处理
page.dispatchKey = (code) => {
  console.log(`分发${code}号按键`);
  return true; // 表示继续向后分发
};
// 不继续分发
page.dispatchKey = (code) => {
  console.log(`分发${code}号按键`);
};
handleEventByCode

函数签名:

handleEventByCode(keyCode: number, ev?: Event) => Page

功能说明:
根据键值处理对应事件,不可覆写。
参数:

// 传入指定键值处理事件
page.handleEventByCode(stbKeys.KEY_OK);
page.handleEventByCode(stbKeys.KEY_UP, event);
unhandledEvents

函数签名:

unhandledEvents(ev?: Event) => void

功能说明:
未处理的事件。
参数:

// 处理未捕获的事件
page.unhandledEvents = (event) => {
  console.error('未处理的键盘事件', event);
};

按键事件

keyOk

函数签名:

keyOk(currentAreaId: number, currentIndex: number) => void

功能说明:
确认键事件。
参数:

// 实现全局确认键事件
page.keyOk = (areaId, index) => {
  console.log(`确认键在区域${areaId}, 第${index}个元素`);
};
keyBack

函数签名:

keyBack() => void

功能说明:
返回键事件。
示例:

// 实现全局返回键事件
page.keyBack = () => {
  console.log('返回键被触发');
};
keyPrevPage

函数签名:

keyPrevPage() => void

功能说明:
上一页事件。
示例:

// 实现全局上一页事件
page.keyPrevPage = () => {
  console.log('触发上一页');
};
keyNextPage

函数签名:

keyNextPage() => void

功能说明:
下一页事件。
示例:

// 实现全局下一页事件
page.keyNextPage = () => {
  console.log('触发下一页');
};
keyNumber

函数签名:

keyNumber(num: number) => void

功能说明:
数字键事件。
参数:

// 实现全局数字键事件
page.keyNumber = (number) => {
  console.log(`触发${number}号数字键`);
};
keyVolumeUp

函数签名:

keyVolumeUp() => void

功能说明:
音量增加事件。
示例:

// 实现全局音量增加键事件
page.keyVolumeUp = () => {
  console.log('触发音量增加');
};
keyVolumeDown

函数签名:

keyVolumeDown() => void

功能说明:
音量减少事件。
示例:

// 实现全局音量减少键事件
page.keyVolumeDown = () => {
  console.log('触发音量减少');
};
keyVolumeMute

函数签名:

keyVolumeMute() => void

功能说明:
静音/取消静音事件。
示例:

// 实现全局静音/取消静音事件
page.keyVolumeMute = () => {
  console.log('触发静音/取消静音');
};
keyPrevChannel

函数签名:

keyPrevChannel() => void

功能说明:
上一频道事件。
示例:

// 实现全局上一频道事件
page.keyPrevChannel = () => {
  console.log('触发上一频道');
};
keyNextChannel

函数签名:

keyNextChannel() => void

功能说明:
下一频道事件。
示例:

// 实现全局下一频道事件
page.keyNextChannel = () => {
  console.log('触发下一频道');
};
keyHome

函数签名:

keyHome() => void

功能说明:
主页键事件。
示例:

// 实现全局主页键事件
page.keyHome = () => {
  console.log('触发主页键');
};
keyMenu

函数签名:

keyMenu() => void

功能说明:
菜单键事件。
示例:

// 实现全局菜单键事件
page.keyMenu = () => {
  console.log('触发菜单键');
};
keyFastForward

函数签名:

keyFastForward() => void

功能说明:
快进事件,加速倍率。
示例:

// 实现全局快进键事件
page.keyFastForward = () => {
  console.log('触发快进');
};
keyFastRewind

函数签名:

keyFastRewind() => void

功能说明:
快退事件,减速倍率。
示例:

// 实现全局快退键事件
page.keyFastRewind = () => {
  console.log('触发快退');
};
keyPause

函数签名:

keyPause() => void

功能说明:
暂停/播放事件。
示例:

// 实现全局暂停/播放键事件
page.keyPause = () => {
  console.log('触发暂停/播放');
};
keyCollect

函数签名:

keyCollect() => void

功能说明:
收藏事件。
示例:

// 实现全局收藏键事件
page.keyCollect = () => {
  console.log('触发收藏');
};
keyStop

函数签名:

keyStop() => void

功能说明:
停止事件。
示例:

// 实现全局停止键事件
page.keyStop = () => {
  console.log('触发停止');
};
keySearch

函数签名:

keySearch() => void

功能说明:
搜索事件。
示例:

// 实现全局搜索键事件
page.keySearch = () => {
  console.log('触发搜索');
};
keyDel

函数签名:

keyDel() => void

功能说明:
删除事件。
示例:

// 实现全局删除键事件
page.keyDel = () => {
  console.log('触发删除');
};
keyApp

函数签名:

keyApp() => void

功能说明:
应用键事件。
示例:

// 实现全局应用键事件
page.keyApp = () => {
  console.log('触发应用键');
};
keyLive

函数签名:

keyLive() => void

功能说明:
直播事件。
示例:

// 实现全局直播键事件
page.keyLive = () => {
  console.log('触发直播');
};
keyTvod

函数签名:

keyTvod() => void

功能说明:
回看事件。
示例:

// 实现全局时移视频键事件
page.keyTvod = () => {
  console.log('触发回看');
};
keyVod

函数签名:

keyVod() => void

功能说明:
点播视频事件。
示例:

// 实现全局点播视频键事件
page.keyVod = () => {
  console.log('触发点播视频');
};
keyInfo

函数签名:

keyInfo() => void

功能说明:
信息键事件。
示例:

// 实现全局信息键事件
page.keyInfo = () => {
  console.log('触发信息键');
};
keyVirtual

函数签名:

keyVirtual(type?: string) => void

功能说明:
虚拟事件。
参数:

// 实现全局虚拟键事件
page.keyVirtual = (type) => {
  console.log(`触发${type}虚拟键事件`);
};

6. FloorManager楼层管理器

6.1 属性及方法

floors

类型: Floor[]
说明: 存储所有楼层实例的数组。

create

函数签名:

create(container: Content, options?: Partial<Pick<Area, AreaPick>>) => Floor

功能说明: 创建楼层实例,同createFloor
参数:

// 创建楼层实例
const floor = FloorManager.create('my-floor', {
  // 楼层配置...
});
pile

函数签名:

pile(orientation: 'h' | 'v' = 'v') => FloorManager

功能说明: 楼层堆叠。
参数:

// 全楼层默认纵向堆叠
FloorManager.pile();
// 全楼层横向堆叠
FloorManager.pile('h');
getFocusFloor

函数签名:

getFocusFloor() => Floor | undefined

功能说明: 获取当前焦点的楼层实例。
返回值: 当前焦点楼层的实例,如果没有则返回undefined
示例:

// 获取并使用当前焦点楼层
const focusFloor = FloorManager.getFocusFloor();
if (focusFloor) {
  console.log(`当前焦点楼层: ${focusFloor}`);
} else {
  console.log('没有找到焦点楼层');
}
focusTo

函数签名:

focusTo(floor: Floor, index?: number) => FloorManager

功能说明: 焦点切换到目标楼层或列表。
参数:

// 将焦点切换到特定楼层和位置
FloorManager.focusTo(targetFloor, targetIndex);
setFloors

函数签名:

setFloors(floors: Floor[]) => FloorManager

功能说明: 设置持有的全部楼层。
参数: floors: 楼层实例数组
返回值: 返回自身实例以支持链式调用
示例:

// 设置多个楼层
FloorManager.setFloors([floor1, floor2]);
addFloors

函数签名:

addFloors(floors: Floor[]) => FloorManager

功能说明: 批量添加楼层。
参数: floors: 楼层实例数组
返回值: 返回自身实例以支持链式调用
示例:

// 批量添加多个楼层
FloorManager.addFloors([floor1, floor2]);
removeFloors

函数签名:

removeFloors(floors: Floor[]) => FloorManager

功能说明: 批量移除楼层。
参数: floors: 需要移除的楼层实例数组
返回值: 返回自身实例以支持链式调用
示例:

// 批量移除多个楼层
FloorManager.removeFloors([floor1, floor2]);

7. FocusSaver焦点保存器

注意:框架内部会自动使用焦点保存器的saveread方法,一般不需要手动调用。只有需要定制标识键或特殊逻辑时,才需要手动调用。

7.1 主要方法

uniqueKey

函数签名:

uniqueKey(mark?: string) => void

功能说明: 按照指定标识生成保存键。
参数: mark: 指定标识(可选)
示例:

// 为特定操作设置唯一保存键
FocusSaver.uniqueKey('my-operation');

has

函数签名:

has() => boolean

功能说明: 检测是否有保存的焦点数据。
返回值: 如果有保存的数据,返回true;否则,返回false
示例:

if (FocusSaver.has()) {
  console.log('有保存的焦点数据');
} else {
  console.log('没有保存的焦点数据');
}

remove

函数签名:

remove(mark?: string) => void

功能说明: 移除保存的焦点数据。
参数: mark: 指定标识(可选)
示例:

// 移除当前保存的焦点数据
FocusSaver.remove();
// 移除特定标识的焦点数据
FocusSaver.remove('my-operation');

clear

函数签名:

clear() => void

功能说明: 清除保存的全部焦点数据。
示例:

// 清除所有保存的焦点数据
FocusSaver.clear();

save

函数签名:

save() => void

功能说明: 保存当前焦点数据。
示例:

// 保存当前的焦点状态
FocusSaver.save();

read

函数签名:

read() => FocusList | undefined

功能说明: 读取保存的焦点数据。
返回值: 如果存在,返回焦点列表;否则,返回undefined
示例:

const savedFocus = FocusSaver.read();
if (savedFocus) {
  console.log('已加载保存的焦点数据');
} else {
  console.log('没有找到保存的焦点数据');
}

8. 全局导出模块

8.1 全局对象

DIR

类型: DIR
说明: 方向枚举(只读),包含LEFT、RIGHT、UP、DOWN。

type DIR = { LEFT: 'left', RIGHT: 'right', UP: 'up', DOWN: 'down' }

SepgEvent

类型: SepgEvent
说明: 框架内事件枚举,包含PageFirstLoaded、PageSlide、PageSlideEnd、KeyUp、KeyDown。

type SepgEvent = {
  PageFirstLoaded: string; // 页面首次加载完成事件
  PageSlide: string; // 页面滑动事件
  PageSlideEnd: string; // 页面滑动结束事件
  KeyUp: string; // 按键抬起事件
  KeyDown: string; // 按键按下事件
}

StbKeys

类型: StbKeys
说明: 标准按键值枚举,包含各种按键值。

type StbKeys = {
  // 数字键
  KEY_0: 48, KEY_1: 49, KEY_2: 50, KEY_3: 51, KEY_4: 52,
  KEY_5: 53, KEY_6: 54, KEY_7: 55, KEY_8: 56, KEY_9: 57,
  // 首页、菜单、返回、确认、暂停键
  KEY_PORTAL: 287, KEY_HOME: 292, KEY_MENU: 1120, KEY_BACK: 8, KEY_OK: 13, KEY_PAUSE: 263,
  // 四色键
  KEY_LIVE: 275, KEY_TVOD: 276, KEY_VOD: 277, KEY_INFO: 278,
  KEY_LIVE_1: 136, KEY_TVOD_1: 137, KEY_VOD_1: 138, KEY_INFO_1: 139,
  KEY_LIVE_2: 1108, KEY_TVOD_2: 1110, KEY_VOD_2: 1109, KEY_INFO_2: 1112,
  // 方向键
  KEY_LEFT: 37, KEY_UP: 38, KEY_RIGHT: 39, KEY_DOWN: 40,
  // 翻页键
  KEY_PAGE_UP: 33, KEY_PAGE_DOWN: 34,
  // 频道键
  KEY_CHANNEL_UP: 257, KEY_CHANNEL_DOWN: 258,
  // 音量键
  KEY_VOL_UP: 259, KEY_VOL_DOWN: 260, KEY_MUTE: 261,
  // 快进退键
  KEY_FAST_FORWARD: 264, KEY_FAST_REWIND: 265,
  // 收藏、停止、搜索、删除、应用、虚拟键值
  KEY_COLLECT: 280, KEY_STOP: 270, KEY_SEARCH: 132, KEY_DEL: 1378, KEY_APP: 142, KEY_VIRTUAL: 768,
  // 扩展PC按键
  KEY_A: 65, KEY_W: 87, KEY_D: 68, KEY_S: 83,
  KEY_N0: 96, KEY_N1: 97, KEY_N2: 98, KEY_N3: 99, KEY_N4: 100,
  KEY_N5: 101, KEY_N6: 102, KEY_N7: 103, KEY_N8: 104, KEY_N9: 105,
  KEY_ESC: 27, KEY_PBACK: 32, KEY_U: 85, KEY_I: 73, KEY_O: 79,
  KEY_H: 72, KEY_J: 74, KEY_K: 75, KEY_L: 76, KEY_M: 77, KEY_PHOME: 36
};

UtilityEvent

类型: UtilityEvent
说明: 机顶盒事件枚举,包含各种机顶盒相关的事件。

type UtilityEvent = {
  /** 当前环境不支持Utility */ UNSUPPORTED: 'UNSUPPORTED',
  /** 当前环境不支持Utility且报错 */ UNSUPPORTED_ERROR: 'UNSUPPORTED_ERROR',
  /** 当按下 CH+, CH-和数字键,机顶盒将打开下一个频道时触发 */ GO_CHANNEL: 'EVENT_GO_CHANNEL',
  /** 资源空闲时触发 */ STB_RESOURCE_IDLE: 'EVENT_STB_RESOURCE_IDLE',
  /** 恢复播放 */ IPTV_RESUME: 'EVENT_IPTV_RESUME',
  /** 媒体播放到末端时触发 */ MEDIA_END: 'EVENT_MEDIA_END',
  /** 媒体播放到起始端时触发 */ MEDIA_BEGINING: 'EVENT_MEDIA_BEGINING',
  /** 媒体播放到起始端时触发 */ MEDIA_FIRST_FRAME: 'EVENT_MEDIA_FIRST_FRAME',
  /** 发生异常时触发 */ MEDIA_ERROR: 'EVENT_MEDIA_ERROR',
  /** 当媒体播放器的 playback mode 发生改变的时候触发 */ PLAYMODE_CHANGE: 'EVENT_PLAYMODE_CHANGE',
  /** 当机顶盒定时提醒时触发 */ REMINDER: 'EVENT_REMINDER',
  /** 当增值业务客户端产生下载、启动、退出、出错等状态发生时触发 */ JVM_CLIENT: 'EVENT_JVM_CLIENT'
};

8.2 全局方法

getSepgEmitter

函数签名:

getSepgEmitter() => EventEmitter

功能说明: 获取框架事件发射器。
返回值: 框架事件发射器的实例
示例:

import { getSepgEmitter, SepgEvent } from 'sepg';
// 获取并使用框架事件发射器
const emitter = getSepgEmitter();
// 监听页面首次加载完成事件
emitter.on(SepgEvent.PageFirstLoaded, (data) => {
  console.log(data);
});
// 监听页面滑动事件
emitter.on(SepgEvent.PageSlide, (data) => {
  console.log(data);
});
// 监听页面滑动结束事件
emitter.on(SepgEvent.PageSlideEnd, (data) => {
  console.log(data);
});
// 监听按键抬起事件
emitter.on(SepgEvent.KeyUp, (data) => {
  console.log(data);
});
// 监听按键按下事件
emitter.on(SepgEvent.KeyDown, (data) => {
  console.log(data);
});

getNearestIndexByRect

函数签名:

getNearestIndexByRect(area: Area, dir: TKeyDir, curRect: SafeDOMRect, rects: (SafeDOMRect | null)[]) => number

功能说明: 获取指定区域实例的指定元素定位数据在指定移动方向上到目标定位元素数据组中的最近索引。
参数:

import { getNearestIndexByRect } from 'sepg';
// 获取当前区域的当前元素在目标区域的目标元素定位数据组中的最近索引
const floor = createFloor('floorContainer'); // 当前楼层区域实例
const tfloor = createFloor('tfloorContainer'); // 目标楼层区域实例
const curRect = floor.getCurrentDom().getBoundingClientRectSafe(); // 当前元素定位数据
const rects = tfloor.getDomList().map(dom => dom.getBoundingClientRectSafe()); // 目标元素定位数据组
const index = getNearestIndexByRect(floor, 'RIGHT', curRect, rects); // 获取最近的索引
console.log('最近的索引是:', index);

createFloor

函数签名:

createFloor(container: Container, options?: FloorOptions) => Floor

功能说明:
创建楼层实例。
参数:

import { createFloor } from 'sepg';
// 创建楼层实例
const newFloor = createFloor('floorContainer', {
  // 楼层配置...
});

getPageInstance

函数签名:

getPageInstance() => Page

功能说明: 获取顶层页面控制器实例。
返回值: 顶层页面控制器实例
示例:

import { getPageInstance } from 'sepg';
// 获取顶层页面控制器实例
const page = getPageInstance();

9. 核心接口与类型

NumberOrNumbers

/** 数字或数字数组 */
type NumberOrNumbers = number | number[];

INumbers

/** 一维数字数组或二维数字数组 */
type INumbers = NumberOrNumbers[];

TKeyDir

/** 方向键 */
type TKeyDir = 'left' | 'right' | 'up' | 'down';

DomMoveStrategy

/** dom级别移动策略定制 */
type DomMoveStrategy = Map<number, Map<TKeyDir, number | number[] | Function>>;

MoveToRecord

/** 指定移动索引记忆 */
interface MoveToRecord {
  left?: { [key: number]: NumberOrNumbers };
  right?: { [key: number]: NumberOrNumbers };
  up?: { [key: number]: NumberOrNumbers };
  down?: { [key: number]: NumberOrNumbers };
}

Content

/** 内容或返回内容的函数 */
type Content = string | string[] | ExtendHTMLElement | (() => string | string[] | ExtendHTMLElement);

loadData

/** 加载数据 */
interface loadData {
  /** 总条数 */
  total?: number;
  /** 当前页数 */
  pageIndex?: number;
  /** 当前页的数据 */
  data: any;
  /** 当前需要渲染的内容 */
  content: Content;
}

AreaLoadConfig

/** 区域加载配置 */
interface AreaLoadConfig {
  /** 是否要推迟加载函数到手动执行(针对区域初始后不需要立即调用加载函数的场景,) */
  defer?: boolean;
  /** 指定的的容器元素, 默认为区域容器 */
  container?: ExtendHTMLElement;
  /** 加载函数的触发类型为focus, 即焦点联动触发时的防抖时间, 默认500ms */
  timeout?: number;
  /** 加载函数的触发类型: focus-焦点联动触发 click-点击触发, 默认为focus */
  trigger?: 'focus' | 'click';
  /** 根据焦点移动逻辑的联动锁方向, 默认为right */
  lock?: TKeyDir;
  /** 分页加载时是否需要按页次顺序加载, 某些布局可能需要保证顺序页数加载数据, 防止布局乱序 */
  order?: boolean;
  /** 指定为分页加载时每页的数据量, 底层调用floor.renderByPage实现, load函数会传递给该配置 */
  size?: number;
  /** 是否延迟加载区域, 即进入可视区才调用区域加载函数, 默认为true */
  delay?: boolean;
  /** 区域离开视区是否清空区域, 子区域为false、非子区域为true */
  gc?: boolean;
  /** gc时是否缓存区域数据(不再执行load加载函数) */
  cache?: boolean;
  /** 开启cache时的最大缓存页数(默认6) */
  maxCache?: number;
  /** 检测视口, 默认为document.body */
  viewPoint?: ExtendHTMLElement;
  /** 预加载位置, 默认为视口高度 */
  preLoad?: number;
  /** 当区域数据为空时显示的内容, 类型可为字符串、dom对象或返回值为字符串或dom对象的函数 */
  empty?: Content;
  /** 图片加载异常时的替换图片或返回替换图片的函数(当图片元素配置了error-src属性时优先读取该属性值) */
  error: string | ((image: ExtendHTMLElement) => string);
  /** 查询图片的类名, 默认img */
  imageClass: string;
  /** 是否懒加载区域图片 */
  lazy?: boolean;
  /** 懒加载元素类名, 默认lazy */
  lazyClass?: string;
  /** 懒加载区域图片的延迟时间, 默认300ms */
  lazyLoad?: number;
  /** 首次加载完成的回调(仅执行一次,执行后会销毁) */
  firstLoaded?: (() => void) | null;
  /** 数据加载函数, 一般加载可通过入参获取加载回调函数, 当配置了size即为分页加载时, 首个入参为当前页数, 第二个参数为加载回调函数; 数据加载函数的返回值可为普通loadData对象或Promise<loadData>对象, 其中content为必选, 类型可为字符串、dom对象或返回值为字符串或dom对象的函数, 表示需要渲染的数据内容; data为必选, 类型为数组, 是当前区域的数据列表; pageIndex为可选(分页加载时为必选), 表示当前页码; total为可选(分页加载时为必选), 表示数据总数; 当接受了handleCallBack即加载回调函数则需要在执行回调中调用该回调以完成数据加载, 否则未返回有效值则认为数据为空, 加载empty配置 */
  load?(handleCallBack: (loadData: loadData) => void): loadData | Promise<loadData>;
  load?(pageIndex: number, handleCallBack: (loadData: loadData) => void): loadData | Promise<loadData>;
  /**
   * 加载完成回调
   * @param pageIndex 加载页数
   * @param current 是否来自当前页加载数据
   */
  loaded?: (pageIndex: number, current?: boolean) => void;
  [key: string]: any;
}

TScrollDir

/** 横纵方向 */
type TScrollDir = 'h' | 'v';

CyclicRollingConfig

/** 循环滚动配置接口 */
interface CyclicRollingConfig {
  /** 是否启用循环滚动 */ scroll?: boolean;
  /** 滚动方向 h 横向 v 纵向(默认h) */ scrollDir?: TScrollDir;
  /** 头循环(默认到头不循环,执行边界事件) */ headCycle?: boolean;
  /** 起始滚动索引 */ startIndex?: number;
  /** 起始滑动值 */ start?: number;
  /** 滑动步长 */ step?: number;
  /** 滑动速度 */ speed?: number;
  /** 边界元素切换延迟 */ delay?: number;
}

ScrollConfig

/** 区域内滑动配置接口 */
interface ScrollConfig {
  /** 模式 auto-到达边界触发滑动 computed-自动计算滑动量 fixed-指定起始位置 screen-按元素所在屏整屏滑动 cycle-列表循环滚动 rate-按视口长度比例计算滚动 item-按焦点元素位置自动计算位置, 默认fixed(注意:fixed模式滑动失效时请指定明确的行列数或maxCount值)*/ mode?: 'auto' | 'computed' | 'fixed' | 'screen' | 'cycle' | 'rate' | 'item';
  /** 是否需要容器滚动, 默认滚动 */ scroll?: boolean;
  /** 容器滚动方向 h 横向 v 纵向(默认h) */ scrollDir?: TScrollDir;
  /** 滑动锁 */ moveLock?: boolean;
  /** 滚动速度, 即动画过度时间 */ speed?: number;
  /** 可视区最大行列数,纵向滑动时看行数,横向滑动时看列数 */ maxCount?: number;
  /** computed或fixed模式下, 指定开始位置 */ startIndex?: number;
  /** computed或fixed模式下, 指定开始位置是否为中点 */ middle?: boolean;
  /** 固定追加滑动值 */ mesh?: number;
  /** 滑动步长 */ step?: number;
  /** 指定的滑动容器 */ container?: ExtendHTMLElement;
  /** 最大滑动量, 防止超出预计滑动量 */ maxSlide?: number;
  /** computed或screen模式下自动计算滑动量数组 */ computedStep?: number[];
  /** computed模式下自动计算时的容器边距 */ computedOffset?: number;
  /** 非computed|screen模式下末尾元素距离容器的偏移值 */ offset?: number;
  /** 出区域后重置滚动到指定位置 start 开头 record 暗焦点位置 end 末尾 */ outReset?: 'start' | 'record' | 'end';
  /** 滚动模式为rate时的比例0-1之间, 默认0.5 */ rate?: number;
  /** 滚动模式为rate时是否显示对齐的视口线 */ showLine?: boolean;
  /**
   * 满足滑动的条件, 不传则没有限制, 传入数值时按指定数值量滑动
   * @param {number} value 当前滑动值
   */
  condition?(value: number): boolean;
  [key: string]: any;
}

SlideFocusConfig

/** 滑动焦点配置 */
interface SlideFocusConfig {
  /** 要排除的区域id */ excludeAreaIds?: number[] | null;
  /** 是否启用焦点滑动 */ slide?: boolean;
  /** 焦点边框宽度 */ borderWidth?: number;
  /** 边框类型 */ borderType?: 'solid' | 'dashed' | 'dotted' | 'double';
  /** 边框颜色 */ borderColor?: string;
  /** 圆角度 */ radius?: number | string;
  /** 滑动速度 */ speed?: number;
  /** 指定滑动的焦点dom */ slideBox?: ExtendHTMLElement;
  /** 边框图片(优先级高) */ image?: string;
  /** 边框是否覆盖元素而非围绕元素 */ cover?: boolean;
}

DirBoolean

/** 边界接口 */
interface DirBoolean {
  left?: boolean;
  right?: boolean;
  up?: boolean;
  down?: boolean;
}

LoaderConfig

/** loader配置接口 */
type LoaderConfig = Partial<{
  /** 持有的dom元素 */ element: ExtendHTMLElement | null;
  /** 容器元素 */ container: Element;
  /** 定位left值 */ left: number | string;
  /** 定位top值 */ top: number | string;
  /** 宽度 */ width: number | string;
  /** 高度 */ height: number | string;
  /** 缩放比例 */ zoom: number;
  /** 背景圆角度 */ radius: string;
  /** 显示字体颜色 */ color: string;
  /** 层级 */ zIndex: number;
  /** 指定的显示内容或返回内容的函数 */ content: Content;
  /** 延迟显示时间ms */ time: number;
}>;

MarqueeConfig

/** marquee配置接口 */
interface MarqueeConfig {
  /** 滚动文字间的像素间距 */ space?: number;
  /** 延迟滚动毫秒数 */ delay?: number;
  /** 滚动方向 */ direction?: TKeyDir;
  /** 速度 */ speed?: number;
  /** 是否显示左右渐隐效果 */ shadow?: boolean;
  /** 是否强制js执行 */ forceJs?: boolean;
  /** 是否是维语文字 */ wy?: boolean;
  /** 持有的dom元素 */ element?: ExtendHTMLElement;
  /** 是否降级marquee标签做滚动 */ tag?: boolean;
}

OutMoveDir

/** 越界指向区域id */
interface OutMoveDir {
  /** 向左越界区域id */ left?: NumberOrNumbers;
  /** 向右越界区域id */ right?: NumberOrNumbers;
  /** 向上越界区域id */ up?: NumberOrNumbers;
  /** 向下越界区域id */ down?: NumberOrNumbers;
}

FloorOutMoveDir

/** 越界指向区域实例 */
type FloorOutMoveDir = Partial<{
  left: Floor | null;
  right: Floor | null;
  up: Floor | null;
  down: Floor | null;
}>;

AreaPick

/** 暴露的区域配置 */
type AreaPick = 'throttleTime' | 'popup' | 'keepFocus' | 'skipHide' | 'disableShake' | 'customClass' | 'longPressHide' | 'virtual' | 'emptyCorrect' | 'along' | 'rightAlign' | 'stack' | 'reverse' | 'cyclicMoveH' | 'cyclicMoveV' | 'pageSize' | 'openRightFix' | 'closeDownFix' | 'openMarquee' | 'marqueeClass' | 'rowCount' | 'colCount' | 'totalCount' | 'commonClass' | 'normalClass' | 'focusClass' | 'blurClass' | 'itemId' | 'closeInsideBoundary' | 'insideUpside' | 'record' | 'recordIndex' | 'select' | 'alwaysSelect' | 'manualSelect' | 'selectClass' | 'slideAlign' | 'selectListener' | 'scrollListener' | 'areaIn' | 'areaOut' | 'borderLeft' | 'borderRight' | 'borderUp' | 'borderDown' | 'customLeft' | 'customRight' | 'customUp' | 'customDown' | 'keyOk' | 'keyBack' | 'keyPrevPage' | 'keyNextPage' | 'focusBefore' | 'focusAfter' | 'blurBefore' | 'blurAfter' | 'cyclicRollingAfter' | 'inViewpoint' | 'outViewpoint' | 'moveViewpoint';

SlideConfig

/** 页面滑动配置 */
interface SlideConfig {
  /** 手动页面滑动量配置, 传入每个区域所需滑动量 */ slideArray?: NumberOrNumbers[];
  /** 滑动方向 */ slideDir?: TScrollDir;
  /** 滑动锁 */ moveLock?: boolean;
  /** 滑动速度 */ speed?: number;
  /** 延迟 */ delay?: number;
  /** 节流滑动 */ throttle?: number;
  /**
   * 满足滑动的条件, 不传则没有限制, 传入数值时按指定数值量滑动
   * @param {number} value 当前滑动值
   */
  condition?(value: number): boolean;
  /** 
   * 滑动结束回调 
   * @param {number} value 当前滑动值
   */
  complete?(value: number): void;
  /** 焦点框滑动量配置 */ slideFocusArray?: number[];
  /** 最后区域距离底部的间距(align=bottom时为每个滑动区域距离底部的间距) */
  bottom?: number;
  /** 与最底部滑动值的最小差值(当前滑动值-最底部滑动值小于该值时设当前滑动值到最底部滑动值) */
  stickBottom?: number;
  /** 自动计算时的滑动对齐方式 top:顶部对齐 middle:中部对齐(默认) bottom:底部对齐 */
  align?: 'top' | 'middle' | 'bottom';
  /** 组件进入视口前的预加载高度(默认50px) */
  preLoad?: number;
  /** 滑动时当前父级及祖先容器的滑动偏移量 */
  offset?: number;
  /** 当前父级容器高度增量值(可微调楼层区域滑动的高度位置) */
  gap?: number;
  /** 因自动计算的滑动量可能存在不是自上而下的顺序, 是否对自动计算的滑动量做从大到小的排序(默认ture) */
  sort?: boolean;
  /** 计算基线偏移位置(按照滑动容器或视口的边界位置偏移的基准点, 用于确定触发滑动的边界位置)(默认-60) */
  baseline?: number;
}

ScreenConfig

/** 切屏配置 */
interface ScreenConfig {
  /** 依赖的滑动容器 */ container?: ExtendHTMLElement;
  /** 滑动方向 */ slideDir?: TScrollDir;
  /** 指定一屏尺寸 */ size?: number;
  /** 切屏速度 */ speed?: number;
  /** 是否循环 */ cycle?: boolean;
  /** 总屏数 */ total?: number;
  /** 初始屏索引 */ index?: number;
  /** 起始索引 */ first?: number;
  /** 关联的区域控制器 */ area?: Area;
  /** 排除切换的索引 */ excludeIndexs?: number[];
  /** 切屏时锁定移动 */ moveLock?: boolean;
  /** 切屏时锁定横向移动 */ moveHLock?: boolean;
  /** 切屏时锁定纵向 */ moveVLock?: boolean;
  /** 切屏时锁定左移 */ moveLeftLock?: boolean;
  /** 切屏时锁定右移 */ moveRightLock?: boolean;
  /** 切屏时锁定上移 */ moveUpLock?: boolean;
  /** 切屏时锁定下移 */ moveDownLock?: boolean;
  /** 初始时是否立即执行完成回调 */ immediate?: boolean;
  /**
   * 开始切换回调
   * @param {number} index 当前屏索引
   */
  start?: (index: number) => void;
  /**
   * 切换完成回调
   * @param {number} index 当前屏索引
   */
  complete?: (index: number) => void;
}

ShakeConfig

/** 边界抖动配置 */
interface ShakeConfig {
  /** 要排除的区域id数组 */
  excludeAreaIds?: number[];
  /** 水平方向抖动类名 默认__shake-horizontal__ */
  horizontal?: string;
  /** 垂直方向抖动类名 默认__shake-vertical__ */
  vertical?: string;
  /** 抖动元素类名 默认__shake-item__ */
  shakeClass?: string;
  /** 动画时间 */
  duration?: number;
  /** 不需要添加包裹容器 */
  nowrapper?: boolean;
  /**
   * 抖动过程中再执行的回调
   * @param {TKeyDir} direction 当前按键方向
   */
  progress?: (direction: TKeyDir) => void;
}

10. 使用示例

10.1 基本使用(esm版本)

import { $, FloorManager, CycleStack, createFloor, getPageInstance } from 'sepg';
// 创建页面控制器
const page = getPageInstance();
// 创建区域控制器
const area1 = createFloor('container1');
const area2 = createFloor('container2');
// 页面滑动容器
const $wrapper = $('wrapper');
// 设置路由切换回调
CycleStack.setChangeListener((next, from, to) => {
  console.log('从', from, '跳转到', to);
  /** 这里可以做一些资源释放或探针上报操作,例如:清理定时器、释放播放器等等 */
  next(); // 执行页面跳转
});
// 配置区域控制器
function areaInit() {
  // area1作为区域2的父级联动
  area1.connect(area2);
  // 链式配置区域1并注册到页面控制器
  area1.fusionConfig({
    /** 按需完成区域配置 */
  }).loadConfig({
    /** 按需完成加载配置 */
  }).setScrollConfig({
    /** 按需完成滑动配置 */
  }).build();
  // 链式配置区域2并注册到页面控制器
  area2.fusionConfig({
    /** 按需完成区域配置 */
  }).loadConfig({
    /** 按需完成加载配置 */
  }).setScrollConfig({
    /** 按需完成滑动配置 */
  }).build();
  // 区域间跨界链接
  area1.pile_v(area2);
  // 可以使用楼层管理器管理全局链接逻辑
  FloorManager.pile('v');
}
// 配置页面控制器
function pageInit() {
  // 配置页面滑动
  page.setSlidePage($wrapper, {
    /** 按需完成页面滑动配置 */
  });
  // 覆写返回事件
  page.keyBack = () => {
    // 返回上一页
    CycleStack.backStack();
  };
  // 覆写Ok事件
  page.keyOk = () => {
    const area = page.getCurrentArea();
    switch (area) {
      // 区域1的Ok操作
      case area1.id: break;
      // 区域2的Ok操作
      case area2.id: break;
      default: break;
    }
  };
  // 初始化按键事件监听并初始焦点到area1区域,当存在记忆焦点数据时将自动设置到记忆的区域
  page.pageInit(area1);
}
areaInit(), pageInit();

10.2 完整案例(umd版本)

index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>列表页</title>
    <link rel="stylesheet" href="./index.css" />
    <link rel="shortcut icon" href="../../favicon.ico" type="image/x-icon" />
  </head>
  <body>
    <div class="container">
      <div class="absolute" id="wrapper">
        <div class="absolute category">
          <div class="absolute mt30" id="first-category"></div>
        </div>
        <div class="absolute category sub">
          <div class="absolute mt30" id="second-category"></div>
        </div>
        <div class="absolute list">
          <div class="absolute" id="vod-list"></div>
        </div>
      </div>
    </div>
    <script src="../../scripts/sepg.js"></script>
    <script src="../../scripts/sepg.var.js"></script>
    <script>
      // 捕获错误信息
      errorCapture({
        onError: function (data) {
          debug(data.message);
        },
        once: true,
      });
    </script>
    <script src="../../services/api.js"></script>
    <script src="./index.js"></script>
  </body>
</html>

index.css

html, body, .container {
  margin: 0;
  padding: 0;
  width: 1280px;
  height: 720px;
  overflow: hidden;
}
img {
  display: block;
}
.container {
  position: relative;
  background-color: #202233;
}
.absolute {
  position: absolute;
  left: 0;
  top: 0;
}
.category {
  top: 30px;
  width: 200px;
  height: 600px;
  overflow: hidden;
}
.category .mt30 {
  margin-top: 30px;
}
.category .item, .category .item-copy {
  width: 150px;
  height: 50px;
  line-height: 50px;
  position: absolute;
  left: 25px;
  top: 0;
  font-size: 30px;
  color: #ffffff;
  text-align: center;
  border-radius: 3px;
}
.category .item .txt {
  width: 100%;
  height: 50px;
  line-height: 50px;
  position: absolute;
  left: 0;
  top: 0;
  font-size: 20px;
  text-align: center;
  color: #ffffff;
  white-space: nowrap;
  overflow: hidden;
}
.category .item_focus {
  background: linear-gradient(to left, #ffac0b, #ff2d2d);
}
.category .item_select {
  background: rgba(255, 255, 255, 0.1);
}
.sub {
  width: 150px;
  left: 210px;
}
.sub .item, .sub .item-copy {
  width: 130px;
  height: 50px;
  line-height: 50px;
  left: 10px;
  font-size: 24px;
}
.list {
  top: 30px;
  left: 370px;
  width: 1070px;
  height: 690px;
  overflow: hidden;
}
.list .absolute {
  margin: 30px;
}
.list .item {
  border: 3px solid transparent;
}
.list .item, .list .item .pic, .list .item .pic img {
  position: absolute;
  width: 178px;
  height: 250px;
  border-radius: 3px;
  object-fit: cover;
}
.list .item .pic {
  background: rgba(255, 255, 255, 0.1);
}
.list .item .txt-wrap {
  width: 100%;
  height: 40px;
  line-height: 40px;
  position: absolute;
  left: 0;
  bottom: 0;
  border-radius: 3px;
  background: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.8));
}
.list .item .txt {
  width: 80%;
  height: 40px;
  line-height: 40px;
  position: absolute;
  left: 10%;
  font-size: 20px;
  text-align: center;
  color: #ffffff;
  white-space: nowrap;
  overflow: hidden;
}
.list .item_focus {
  transition: all 0.3s;
  transform: scale(1.1);
  border: 3px solid #ffffff;
}
.list .item_focus .pic img {
  border-radius: 0;
}
.lazy1 {
  opacity: 0;
}
.loaded {
  animation: move 1s forwards;
}
@keyframes move {
  from {
    opacity: 0;
    transform: scale(0.8);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

index.js

var state = CycleStack.getState();
var pageSize = 15;
var page = getPageInstance();
var firstCategory = createFloor('first-category');
var secondCategory = createFloor('second-category');
var vodList = createFloor('vod-list');
var $wrapper = $('wrapper');

function createCategory(result) {
  if (result && result.length) {
    var html = result.map(function (item, i) {
      return (
        '<div class="item" style="top: ' + i * 80 + 'px">'
        + '<div class="txt">' + (item.name || '') + '</div>' +
        '</div>'
      );
    });
    return { data: result, content: html };
  }
}
function createFirstCategory(cb) {
  GetFirstCategory(function (data) {
    var result = data.result;
    var html = result.map(function (item, i) {
      return (
        '<div class="item" style="top: ' + i * 80 + 'px">'
        + '<div class="txt">' + (item.name || '') + '</div>' +
        '</div>'
      );
    });
    cb({ data: result, content: html });
  });
}
function createSecondCategory(cb) {
  var first = firstCategory.getDataByIndex();
  if (first) {
    GetSecondCategory(first.id, function (data) {
      var result = data.result;
      cb(createCategory(result));
    });
  }
}
function bindVodList(data, pageIndex) {
  return (data || []).map(function (item, i) {
    var index = (pageIndex - 1) * pageSize + i;
    var l = 210 * (index % vodList.colCount);
    var t = 320 * Math.floor(index / vodList.colCount);
    var img = item.posterImg ? '<img class="img lazy1" data-src="' + item.posterImg + '" />' : '';
    return (
      '<div class="item" style="left:' + l + 'px;top:' + t + 'px">'
      + '<div class="pic">' + img + '</div>'
      + '<div class="txt-wrap">'
      + '<div class="txt">' + (item.name || '') + '</div>'
      + '</div>' +
      '</div>'
    );
  });
}
function createVodList(pageIndex, cb) {
  var second = secondCategory.getDataByIndex();
  if (second) {
    var result = vodList.getDataByPage(pageIndex);
    if (result) {
      var html = bindVodList(result, pageIndex);
      return { data: result, pageIndex: pageIndex, total: vodList.totalCount, content: html };
    }
    GetVodList(second.id, pageSize, pageIndex, function (data) {
      var totalCount = data.totalCount;
      var html = bindVodList(data.result, pageIndex);
      cb({ data: data.result, pageIndex: pageIndex, total: totalCount, content: html });
    });
  }
}
function areaInit() {
  // 列表联动
  firstCategory.connect(secondCategory).connect(vodList);
  firstCategory.fusionConfig({
    // select: true, record: true, recordIndex: firstSelect
    select: true, record: true
  }).setLoader({
    content: '<h1>Loading1...</h1>'
  }).setScrollConfig({
    step: 80, maxCount: 7
  }).loadConfig({
    timeout: 400,
    load: createFirstCategory,
    empty: '<h1>暂无数据1</h1>'
  }).build();
  secondCategory.fusionConfig({
    // select: true, record: true, recordIndex: secondSelect
    select: true, record: true
  }).setLoader({
    content: '<h1>Loading2...</h1>'
  }).setScrollConfig({
    step: 80, maxCount: 7
  }).loadConfig({
    load: createSecondCategory,
    empty: '<h1>暂无数据2</h1>'
  }).build();
  vodList.fusionConfig({
    record: true, openMarquee: true, colCount: 5,
    closeInsideBoundary: false, longPressHide: true,
    keyOk: function (index) {
      // vodList.removeItem(index);
      // console.log('vodList: ', vodList);
      // return true;
    }
  }).setLoader({
    left: page.slideValue ? 450 : 380, top: 250
  }).loadConfig({
    empty: '<h1>Empty...</h1>',
    lazy: true,
    lazyClass: 'lazy1',
    size: pageSize,
    load: createVodList
  }).setScrollConfig({
    scrollDir: 'v', step: 320, maxCount: 2
  }).build();
  FloorManager.pile('h');
}
function pageInit() {
  page.keyOk = function (id, index) {
    var floor = FloorManager.getFocusFloor();
    var data = floor.getDataByIndex(index);
    if (id === floor.id) {
      CycleStack.pushState(PAGE_NAV.Nav.url);
    }
  };
  page.setSlidePage($wrapper, {
    slideDir: 'h',
    slideArray: [0, -180, -180],
    condition: function (value) {
      vodList.setLoader({
        left: value ? 450 : 380, top: 250
      });
      return true;
    }
  });
  page.keyBack = function () {
    CycleStack.backState();
  };
  page.pageInit(secondCategory);
}

areaInit(), pageInit();

11. 注意事项

11.1 性能优化

  1. 避免频繁的DOM操作: 框架内部已做优化,但开发者仍需注意
  2. 合理使用节流防抖: 对于高频操作建议使用框架提供的工具函数
  3. 内存管理: 及时清理不再使用的区域实例

11.2 兼容性

  1. 浏览器支持: 支持现代浏览器和WebView环境
  2. 设备适配: 针对TV、机顶盒等大屏设备优化
  3. 输入设备: 支持遥控器、键盘、鼠标等多种输入方式

11.3 调试建议

  1. 使用开发者工具: 框架提供了丰富的调试信息
  2. 事件监听: 通过事件总线可以监听内部状态变化
  3. 错误处理: 框架提供了完善的错误处理机制