Appearance
触控功能
JsView中的触控功能,设计思路是js定规则后尽最大可能减少触控处理过程中和js的交互,以提升触控处理中drag/fling的性能。 (TBD: 当前版本PC浏览器模拟环境上的click/drag/fling暂时未实现)
1. 普通div元素上追加点击支持
在div元素上追加 @click="回调函数" 即可
例如:
vue
<script setup>
/* 声明click的回调函数 */
const click_callback = ()=>{
console.log("on clicked");
}
<script/>
<template>
<div
:style="{
width:100,
height:100,
backgroundColor: '#FF00FF'}"
@click="click_callback"/>
</template>2. 普通元素中追加长按的响应
通过element的ref句柄,调用 jsvSetTapListener 函数来设置,具体参考
3. MetroWidget支撑的列表触控处理(drag/fling/click)
列表触控由 JsvTouchModeSwitcher + MetroWidget 的 touchFlag 共同完成。
3.1 JsvTouchModeSwitcher
JsvTouchModeSwitcher 用于按键模式 / 触控模式的自动切换与监听。将其作为页面内容的包裹层后:
- 用户触摸屏幕 → 进入触控模式(
TOUCH_MODE = 2) - 用户按下指定按键(默认方向键)→ 切回按键模式(
KEY_MODE = 1) - 子组件可通过回调感知模式变化,据此控制焦点框显示、缩放等 UI
该组件会维护全局交互模式 JsvInteractionMode。MetroWidget 在 touchFlag > 0 时,只有检测到页面存在 JsvTouchModeSwitcher,才会真正开启触控相关能力。
引入
js
import { JsvTouchModeSwitcher } from "jsview";模板中标签名为:jsv-touch-mode-switcher。
基本用法
建议放在页面根内容外层,width / height 与可视区域一致:
vue
<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import { JsvTouchModeSwitcher } from "jsview";
const switcherRef = ref();
const onModeChange = (mode) => {
// mode: 1 = 按键, 2 = 触控
console.log("当前模式:", mode === 1 ? "key" : "touch");
};
onMounted(() => {
switcherRef.value.registerCallback(onModeChange);
});
onBeforeUnmount(() => {
switcherRef.value.unregisterCallback(onModeChange);
});
</script>
<template>
<jsv-touch-mode-switcher
ref="switcherRef"
:width="1280"
:height="720"
>
<!-- 页面内容 -->
<metro-widget :touchFlag="1" ... />
</jsv-touch-mode-switcher>
</template>Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| width | Number | — | 容器宽度,建议与页面可视宽一致 |
| height | Number | — | 容器高度,建议与页面可视高一致 |
| initMode | Number | 1 | 初始模式:1 按键,2 触控 |
| changeModeKeyList | Array | [37, 38, 39, 40] | 从触控切回按键的按键列表(默认左/上/右/下) |
实例方法(通过 ref 调用)
| 方法 | 签名 | 说明 |
|---|---|---|
| registerCallback | (callback: (mode: number) => void) => void | 注册模式变化回调 |
| unregisterCallback | (callback: (mode: number) => void) => void | 注销回调(必须与 register 成对使用) |
| getInteractiveMode | () => number | 获取当前模式:1 按键,2 触控 |
| changeMode | (mode: "key" | "touch") => void | 主动切换模式 |
模式常量
KEY_MODE = 1(按键)TOUCH_MODE = 2(触控)
模式切换规则
- 触控 → 按键:在触控模式下,按下
changeModeKeyList中的键会切回按键模式。该次按键不会继续向下传递(用于切换模式,不触发焦点移动等业务逻辑)。 - 按键 → 触控:在 Switcher 包裹区域内触发
touchStart时,自动进入触控模式。 - 主动切换:
js
switcherRef.value.changeMode("key"); // 切到按键
switcherRef.value.changeMode("touch"); // 切到触控切换时会同步调用 window.JsView.changeInteractionMode,并更新全局 JsvInteractionMode。
3.2 与 MetroWidget 配合
开启列表触控时,需要同时满足:
- 页面使用
JsvTouchModeSwitcher包裹 MetroWidget设置:touchFlag="1"
仅设置 touchFlag > 0 不够;内部还会检查是否存在 JsvTouchModeSwitcher,两者同时满足才会启用 drag / fling 等触控行为。
vue
<jsv-touch-mode-switcher
ref="switcherRef"
:width="1280"
:height="720"
>
<metro-widget
:touchFlag="1"
:mouseFlag="1"
...
/>
</jsv-touch-mode-switcher>MetroWidget 相关 props:
js
// props
// touchFlag {int} 触控的开关,
// 0:关闭, 1:打开. 打开后支持drag, fling;
// 另外,item要支持点击(click)时,要在measure回调函数中,对measuresObject的追加enableTap:true
// mouseFlag {int} 支持鼠标滚轮的开关, 0:关闭, 1:打开, 打开后可以用鼠标滚轮来对mw进行scroll从触控切回按键后如何重新落焦,见 第 9 节。
4. 长文本滚动
使用JsvScrollBox和JsvScrollFollow组件来完成。可以参考“功能实例->长文字”的样例(如下)
node_modules/@shijiu/jsview-vue-samples/LongText/LongTextScroll.vue
因为是整篇文字是一部分可见,所以用JsvScrollBox的抽屉模式(drawer)
这两个组件的参数说明见:
node_modules/@shijiu/jsview-vue/utils/JsViewVueWidget/JsvScrollBox/JsvScrollBox.vue
node_modules/@shijiu/jsview-vue/utils/JsViewVueWidget/JsvScrollBox/JsvScrollFollow.vue
5. 进度条拖动(视频进度条)
使用JsvScrollBox和JsvScrollFollow组件来完成。可以参考“触控->可拖拽进度条”的样例(如下)
node_modules/@shijiu/jsview-vue-samples/ScrollBoxTest/SizeDivBar.vue
node_modules/@shijiu/jsview-vue-samples/ScrollBoxTest/ClipBar.vue
node_modules/@shijiu/jsview-vue-samples/ScrollBoxTest/NinePatchBar.vue
因为是进度条游标在滚动区域中滑动,所以用JsvScrollBox的Pin模式
这两个组件的参数说明见:
node_modules/@shijiu/jsview-vue/utils/JsViewVueWidget/JsvScrollBox/JsvScrollBox.vue
node_modules/@shijiu/jsview-vue/utils/JsViewVueWidget/JsvScrollBox/JsvScrollFollow.vue
6. div拖动和对齐检测
使用JsvDragBox组件来完成此功能,可参考"触控->DragBox"的样例(如下)
node_modules/@shijiu/jsview-vue-samples/DragBox/App.vue
使用此组件时,注意 setSensor 的敏感度设置,越小性能开销越大(js是单线程,过于频繁的消息和回调会导致其他任务无法执行)
此组件的参数说明见:
node_modules/@shijiu/jsview-vue/utils/JsViewVueWidget/JsvDragBox/JsvDragBox.vue
7. 鼠标的hover进出检测
在div元素上追加 @mouseenter="回调函数" 和 @mouseleave="回调函数" 即可
例如:
vue
<script setup>
/* 声明click的回调函数 */
const click_callback = ()=>{
console.log("on clicked");
}
<script/>
<template>
<div
:style="{
width:100,
height:100,
backgroundColor: '#FF00FF'}"
@mouseenter="mouseenter_callback"
@mouseleave="mouseleave_callback"
/>
</template>8. 使用蒙层屏蔽下层元素的触控与鼠标事件
在需要临时禁止用户操作(例如弹窗、加载中、全屏遮罩)时,可在界面上方叠一层全屏或局部的 蒙层 div,使其盖住下层可交互元素。蒙层本身通过 jsvSetTapListener 与 jsvConsumeMouseEvent 吞掉触控与鼠标事件,下层元素便不会收到 click、长按、hover、滚轮等响应。
实现要点:
- 蒙层需覆盖待屏蔽区域,并设置合适DOM层级,使其位于下层元素之上。
- 触控:对蒙层调用
jsvSetTapListener,为各触控回调注册空实现,避免事件继续下发。 - 鼠标:对蒙层调用
jsvConsumeMouseEvent({ hover: true, scroll: true }),屏蔽 hover 与滚轮;蒙层挡住区域内的 MetroWidget 等下层控件的鼠标事件同样会被挡住。
API 说明见:
Element 的 jsvSetTapListener / jsvConsumeMouseEvent
例如(Vue 3,使用 ref 拿到蒙层 div 句柄 overlay):
vue
<script setup>
import { ref, onMounted } from "vue";
const overlay = ref(null);
// 空回调,用于吞掉触控事件
const emptyListener = () => {};
onMounted(() => {
if (!overlay.value) return;
let emptyListener = ()=>{};
// 屏蔽所有触控事件
overlay.value.jsvSetTapListener({
onClick: emptyListener,
onTouchStart: emptyListener,
onTouchEnd: emptyListener,
onLongPress: emptyListener,
onLongPressRelease: emptyListener,
onCancel: emptyListener,
});
// 屏蔽所有鼠标 hover 与滚轮事件
overlay.value.jsvConsumeMouseEvent({ hover: true, scroll: true });
});
</script>
<template>
<!-- 下层:正常可点击、可 hover 的内容 -->
<div :style="{ width: 1920, height: 1080 }">
<!-- ... -->
</div>
<!-- 蒙层:盖住下层,屏蔽触控与鼠标事件 -->
<div
ref="overlay"
:style="{
width: 1920,
height: 1080,
backgroundColor: 'rgba(0,0,0,0.5)',
}"
/>
</template>需要恢复交互时,移除或隐藏蒙层即可;若蒙层长期存在,可在显示/隐藏时分别调用上述 API 与对应清理逻辑(按业务需要处理)。
9. Touch 模式切换到 Key 模式时的焦点定位
触控操作后切回按键(Key)模式时,需要重新确定焦点应落在哪个可见、可获焦的 item 上。对相关 MetroWidget 调用 getItemVisibleState,根据返回的可视状态树选择落焦目标。
getItemVisibleState
获取指定区间内可视 item 的可见状态树(支持 MetroWidget 嵌套场景)。
- 传入的
leftTop/rightBottom已是真实区域坐标,无需再减去 padding。 - 会按滚动方向取区间与 item 求交,仅返回在区间内可见(含部分可见)的 item。
- 对嵌套的子 MetroWidget 会递归查询,结果放入
children。 - 当前 gaze(落焦/注视)对应的 item 会排在返回列表最前。
参数
| 参数 | 类型 | 说明 |
|---|---|---|
| leftTop | {x: number, y: number} | 查询区域左上角 |
| rightBottom | {x: number, y: number} | 查询区域右下角 |
返回值
array,每项结构为:
| 字段 | 类型 | 说明 |
|---|---|---|
| name | string | 当前 MetroWidget 的 name |
| index | number | item 的 index |
| visibleState | "partial" | "full" | 部分可见或完全可见 |
| children | array | 嵌套子 MetroWidget 的可见状态列表,无嵌套时为空数组 |
| widgetHandler | object | 当前 MetroWidget 的 handler |
| focusable | boolean | item 是否可获焦 |
落焦策略(业务自选)
拿到可见状态列表后,可按业务需要择一处理(落焦前请结合 focusable 判断):
- Gaze 优先:取返回列表第一项。API 已将当前 gaze 对应的 item 排在最前,适合希望尽量贴近触控前落焦/注视位置的场景。
- 完全可见优先:在列表中筛选
visibleState === "full"的项,再取其中第一项(或嵌套树中业务认定的优先项)。适合希望焦点落在完整可见 item 上的场景。
嵌套场景下,可沿 children 递归,直到选中叶子 item,再通过对应 widgetHandler / name + index 完成落焦。
10. 支持鼠标滚轮
JsView 对鼠标滚轮(含触控板滚动)的支持,主要由列表组件 MetroWidget / ListWidget、滚动组件 JsvScrollBox,以及可选的全局倍率配置共同完成。需要临时屏蔽滚轮时,可对蒙层调用 jsvConsumeMouseEvent(见 第 8 节)。
10.1 MetroWidget / ListWidget:列表滚轮滚动
通过 mouseFlag 打开列表的鼠标滚轮滚动;MetroWidget 还可用 mouseConfig.wheelRate 调节滚动速度。
MetroWidget props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| mouseFlag | Number | 0 | 鼠标滚轮开关:0 关闭,1 打开;打开后可用滚轮对列表 scroll |
| mouseConfig | Object | — | 仅在 mouseFlag === 1 时生效 |
| mouseConfig.wheelRate | Number | 10 | 鼠标滚轮滚动速度 |
vue
<metro-widget
:touchFlag="1"
:mouseFlag="1"
:mouseConfig="{ wheelRate: 10 }"
...
/>ListWidget
ListWidget(单列/单行 MetroWidget)同样提供 mouseFlag(0 关闭 / 1 打开),用法与 MetroWidget 一致。
10.2 JsvScrollBox:滚动区域滚轮
长内容抽屉滚动、视频进度条等场景,通过 JsvScrollBox 的滚轮开关启用:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| enableMouseWheel | Boolean | false | 是否支持鼠标滚轮滚动(非响应式) |
| mouseWheelRate | Number | 10 | 鼠标滚轮滚动速度比率(非响应式) |
vue
<jsv-scroll-box
:direction="VERTICAL"
:mode="ScrollBoxStyle.DrawerMode"
:enableFling="true"
:enableMouseWheel="true"
:mouseWheelRate="10"
:style="{ width: 1000, height: 500 }"
:sliderSize="{ height: scrollHeight }"
>
<template #SliderBox>
<!-- 长内容 -->
</template>
</jsv-scroll-box>组件参数完整说明见:node_modules/@shijiu/jsview-vue/utils/JsViewVueWidget/JsvScrollBox/JsvScrollBox.vue
10.3 屏蔽滚轮事件
对蒙层或指定元素调用(常用于在遮挡层/蒙层上屏蔽滚轮事件,避免下层组件仍接收滚轮事件而产生误操作):
js
element.jsvConsumeMouseEvent({ scroll: true }); // 仅屏蔽滚轮
// 或
element.jsvConsumeMouseEvent({ hover: true, scroll: true }); // 同时屏蔽 hover 与滚轮API 说明见:Element 的 jsvConsumeMouseEvent
10.4 全局滚轮倍率
可通过 JsView.setRenderGlobalConfig 设置全局滚轮/触控板滚动倍率,与视图级滚动速率(如 wheelRate / mouseWheelRate)相乘:
js
JsView.setRenderGlobalConfig({
wheelRate: 1, // 默认 1
});10.5 相关样例(Vue)
可在 DemoHomepage 的 router 中按路径定位(以下为 Vue 样例):
| 样例 | router 路径 | 说明 | 关键用法 |
|---|---|---|---|
| 长文字 | /feature/LongText | JsvScrollBox 典型场景:长文本 + 右侧进度条联动,支持触控拖动 / fling / 进度条点击跳转 / 鼠标滚动 | :enableMouseWheel="true" |
| 长图片 | /Operations/LongImage | 长图滚动,同样基于 JsvScrollBox | :enableMouseWheel="true" |
| 触控示例 | /touch/TouchWidget | MetroWidget 开启滚轮;OK 键可开蒙层,屏蔽下层触控与鼠标(含滚轮) | :mouseFlag="1";蒙层 jsvConsumeMouseEvent({ hover: true, scroll: true }) |
对应源码:
node_modules/@shijiu/jsview-vue-samples/LongText/LongTextScroll.vuenode_modules/@shijiu/jsview-vue-samples/LongImage/LongImageScroll.vuenode_modules/@shijiu/jsview-vue-samples/TouchWidget/App.vuenode_modules/@shijiu/jsview-vue-samples/TouchWidget/WidgetItem.vue(嵌套 MetroWidget 同样:mouseFlag="1")