# (Vue)JsvFocusBlock

# 1. 基本介绍

JsvFocusBlock(焦点控制)组件用于 JsView-Vue3 架构。

它是一个穿插于UI组件之间,用于焦点变更以及按键流响应的组件。

JsvFocusBlock可以通过设置namespace属性进行命名空间隔离。你可以通过其中一个JsvFocusBlock的引用获取到相同namesapce下的其他JsvFocusBlock节点。但是获取本namespace外层嵌套的JsvFocusBlock节点是被禁止的(替代方法请参考 Demo)。

uml diagram

# 2. 控件说明

对应代码位置:
node_modules/@shijiu/jsview-vue/utils/JsViewEngineWidget/JsvFocus/JsvFocusBlock.vue

前提条件:

  • 在使用JsvFocusBlock前,首先需要将JsvFocusManager组件添加到app中。添加后,插件会自动注册一个默认的顶级namespace到app。后续添加的所有组件,均会以此为根。

    例如 main.ts 文件中添加

    import { jsvCreateFocusManager } from 'jsview/utils/JsViewEngineWidget'
    
    ...
    
    app.use(jsvCreateFocusManager(), '#app')
    
    1
    2
    3
    4
    5

    输入参数

    jsvCreateFocusManager(): 创建一个JsView焦点插件。 '#app': app mount的根元素

属性设置(props):

  • name / namespace: [String]

    • 二选一。手动给JsvFocusBlock设置一个名字/命名空间,该属性不能包含"."关键字,"."用于级联namespace。
      • name: 名字。可以使用getBlock(name)函数通过名字获取到该组件的引用。
      • namespace:命名空间。隔离JsvFocusBlock组件,用于解决 name 冲突。namespace下name唯一,也就是说:<JsvFocusBlock namespace="xxx">节点包含的所有的<JsvFocusBlock name="yyy">, name必须各不相同。
      • 当节点不需要被setFocus作为目标时, name和namespace都可以不设置, 默认会给与一个匿名的name(通过 getCurrentNodeStask 可以看到)
  • autoFocus: [Boolean]

    • 在 mounted 后自动尝试申请焦点。
  • onAction: [Object]

    • 包含事件回调函数的对象。可选则 onDispatchKeyUp, onDispatchKeyDown, onKeyUp, onKeyDown, onFocus, onBlur 其中的几个或全部。当onAction成员的回调和下面其他直接设置的回调事件同时存在时,onAction成员的回调被忽略,直接设置的回调有效。
  • onDispatchKeyUp, onDispatchKeyDown: [(event: JsvFocusEvent) => Boolean]

    • Key Up/Down 分发事件回调,当Root获取到按键时,从Root节点向当前Focus节点方向逐级分发。 当某个节点注册此回调函数并返回true时,截断该事件继续传递。
  • onKeyUp, onKeyDown: [(event: JsvFocusEvent) => Boolean]

    • Key Up/Down 事件回调,如果Dispatch事件没有被截断,则尝试从当前Focus节点向Root节点方向逐级触发。 当某个节点注册此回调函数并返回true时,截断该事件继续传递。
  • onFocus, onBlur: [(ownerNode: JsvFocusBlock) => Void]

    • onFocus: 当某个节点注册onFocus回调函数并获取到焦点时,触发该回调。
    • onBlur: 当前Focus节点注册ononBlur回调函数并失去到焦点时,触发该回调。

JsvFocusEvent 成员说明:

  • ownerNode: [JsvFocusBlock] 回调函数所在的节点实例
  • type: [String] 键类型, "keyup"/"keydown"
  • keyCode: [Number] 键值, 例如:
    • 13(Enter) / 37(ArrowLeft) / 38(ArrowUp) / 39(ArrowRight) / 40(ArrowDown)
  • key: [String] 键值字符串,例如:
    • "Enter" / "ArrowLeft" / "ArrowUp" / "ArrowRight" / "ArrowDown"

方法(methods):

  • async getFullName() => String

    • 说明:

      • 获取JsvFocusBlock的包含有全局namespace的名字
    • 返回值:

      • 格式为 ".{namespace}. * * * .{namespace}" 或 ".{namespace}. * * * .{namespace}.{name}" 形式的字符串。

      常见的返回值(ns = namespace):

      UI结构 名字 错误理解
      name1 .name1
      name1 -> name2 .name2"
      ns1 -> name2 .ns1.name2"
      ns1 -> ns2 -> name3 .ns1.ns2.name3
      ns1 -> name2 -> name3 .ns1.name4 .ns1.name2.name4
      ns1 -> name2 -> ns3 .ns1.ns3 .ns1.name2.ns3
      ns1 -> name2 -> ns3 -> name4 .ns1.ns3.name4 .ns1.name2.ns3.name4

      首字符"."代表全局namesapce

    提示

    namespace下的所有name都是扁平化的。 这和编程语言中的命名空间没什么不同。

  • async requestFocus() => void

    • 说明:
      • 让此节点获得焦点(不常用, 基本可以被 useFocusHub + setFocus 调用替代)

注意

所以的方法均为异步处理, 在其挂载到链接着根节点的dom树后产生效果, 可使用await对齐调用

焦点切换

  • useFocusHub(bool withNameSpace) => Hub

    • 说明:
      • 全局方法, 可获得根节点focusHub对象, 用于控制焦点切换
    • 输入参数:
      • withNameSpace: 若为false, 拿到root的FocusHub, 对在NameSpace节点中的子节点进行setFocus操作时,需要传完整名称(命名空间.名称);若为true则获得含有当前深度nameSpace的hub, 在相同的命名空间中,对子节点进行setFocus时,直接传名称即可。
  • FocusHub对象

    • 接口和说明
  /**
   * setFocus
   * 
   * 设置焦点,在焦点对应的 JsvFocusBlock 完成mounted之前设置的话,
   * 会在JsvFocusBlock完成mounted后立即设上焦点 
   * 
   * @param {string} focusName 
   *         当前命名空间的名字/全局命名空间的名字。
   *         当前命名空间的名字: 是指和当前节点相同命名空间的名字(首字符不为".")。
   *         对于二级命名空间,可以使用 "{namespace}.{name}"的方式。
   *         全局命名空间的名字: 是指通过getName()函数获取后再附加下级节点的名字。
   *         *请注意: 请避免手写的全局命名空间名字,防止在二次集成时可能会出现名字找不到的问题。
   * @param {boolean} passToChild 保持/恢复子焦点的聚焦状态(若此焦点的子焦点为聚焦状态,
   *         当本焦点从失焦状态恢复为聚焦状态时,子焦点也自动回复为聚焦状态),默认为不保持/恢复。
   */
  public setFocus(focusName: string, passToChild: boolean = false)

  /**
   * returnFocusToParent
   * 
   * 将焦点从当前节点还给其父JsvFocusBlock节点 
   */
  public returnFocusToParent()

  /**
   * getCurrentFocus
   * 
   * 获取当前焦点的的 focusName 信息,用于后续的进行的 setFocus 操作
   * (注意, 不带NameSpace)
   * 
   * @return {string} 当前焦点的focusName
   */
  public getCurrentFocus(): string

  /**
   * getLastFocus
   * 
   * 获得切到到当前焦点前的上一个焦点的name(注意, 不带NameSpace), 
   * 注意:如果上一次的焦点已经不在dom树时, 返回null
   * 
   * @return {string} 焦点的focusName
   */
  public getLastFocus(): string

  /**
   * getDeactivedPageFocus
   * 
   * 在对一个keep-alive的界面进行deactive后,为了未来将其active时恢复离开时的焦点时使用。
   * 在 onDeactive 回调中调用
   * 注意: 只有当一个有焦点的keep-alive倍deactive时才能获得
   * 
   * @return {string} 焦点的focusName
   */
  public getDeactivedPageFocus(): string

  /**
   * getNameSpace
   * 
   * 获取当前FocusHub的nameSpace
   * 
   * @return {string} 当前FocusHub的nameSpace
   */
  public getNameSpace(): string

  /**
   * enableFocusTrace
   * 
   * 调试API: 启用焦点变化时的回调日志,通过console.log打出,其中含产生此行为的调用堆栈
   * 
   * @param {boolean} needCallStack 是否打印焦点变化时产生变化的api调用的堆栈,例如setFocus, unmount之类
   */
  public enableFocusTrace(needCallStack: boolean = true)

  /**
   * printAllFocusable
   * 
   * 调试API: console.log当前 Hub 中所有的节点引用,只打印当前NameSpace的内容
   */
  public printAllFocusable()

  /**
   * getCurrentFocusStack
   * 
   * 调试API: console.log当前焦点的焦点链条(从root到此节点的链条)
   * 
   * @return {Array} 当前焦点的链条队列
   */
  public getCurrentFocusStack(): Array<Object>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

# 3. 手把手搭建JsvFocusBlock

  • 在src下创建空白的 vue3 文件 demo.vue
<template>
  <div></div>
</template>

<script setup>
<script/>

<style scoped>
</style>
1
2
3
4
5
6
7
8
9
  • 在template部分,将<div>更换为<jsv-focus-block>,给组件设置onAction配置,此配置为一个map{}
<template>
  <jsv-focus-block :onAction="{
    onKeyDown: onKeyDown_Level0,
    onDispatchKeyDown: onDispatchKeyDown_Level0,
    onFocus: onFocus_Level0,
    onBlur: onBlur_Level0,
  }">
  </jsv-focus-block>
</template>
1
2
3
4
5
6
7
8
9
  • 在script部分,声明上述onAction中的函数
<script setup>
let onKeyDown_Level0 = (event)=>{
  console.log(`level 0 收到回流的按键 code=${event.keyCode}`);
  return false; // 标识为未使用, 允许继续回流
}

let onDispatchKeyDown_Level0 = (event)=>{
  console.log(`level 0 收到下发的按键 code=${event.keyCode}`);
  return false; // 标识为未使用, 允许继续下发
}

let onFocus_Level0 = ()=>{
  console.log(`level 0 收到focus事件`);
}

let onBlur_Level0 = ()=>{
  console.log(`level 0 收到blur事件`);
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • 在template部分,为<jsv-focus-block>追加一个子节点,并通过name属性进行命名(为了聚焦操作),同样添加onAction和函数定义
<template>
  <jsv-focus-block :onAction="{
    onKeyDown: onKeyDown_Level0,
    onDispatchKeyDown: onDispatchKeyDown_Level0,
    onFocus: onFocus_Level0,
    onBlur: onBlur_Level0,
  }">
    <jsv-focus-block name="level1" :onAction="{
      onKeyDown: onKeyDown_Level1,
      onDispatchKeyDown: onDispatchKeyDown_Level1,
      onFocus: onFocus_Level1,
      onBlur: onBlur_Level1,
    }"/>
  </jsv-focus-block>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script setup>
...

let onKeyDown_Level1 = (event)=>{
  console.log(`level 1 收到回流的按键 code=${event.keyCode}`);
  return false; // 标识为未使用, 允许继续回流
}

let onDispatchKeyDown_Level1 = (event)=>{
  console.log(`level 1 收到下发的按键 code=${event.keyCode}`);
  return false; // 标识为未使用, 允许继续下发
}

let onFocus_Level1 = ()=>{
  console.log(`level 1 收到focus事件`);
}

let onBlur_Level1 = ()=>{
  console.log(`level 1 收到blur事件`);
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  • 在script部分,从jsview模块引入useFocusHub,添加初始化后的聚焦动作,让命名为level1的节点获得焦点
<script setup>
import { useFocusHub } from "jsview";

...

let hub = useFocusHub();
hub.setFocus("level1");
</script>
1
2
3
4
5
6
7
8
  • 为此独立程序添加通知小程序运行器关闭启动图的处理(需要引入onMounted和jsvRuntimeBridge)
<script setup>
import { onMounted } from "vue"  
import { jJsvRuntimeBridge, useFocusHub } from "jsview"

...

onMounted(()=>{
  jJsvRuntimeBridge.notifyPageLoaded(); // 通知小程序运行器关闭启动图和超时计时器
})
</script>
1
2
3
4
5
6
7
8
9
10
  • 在script标签纸中纠正eslint和vue3 setup语法在no-unused-vars上的兼容问题
<script setup>
/* eslint-disable no-unused-vars */
...
<script>
1
2
3
4
  • 代码整体一览
<template>
  <jsv-focus-block :onAction="{
    onKeyDown: onKeyDown_Level0,
    onDispatchKeyDown: onDispatchKeyDown_Level0,
    onFocus: onFocus_Level0,
    onBlur: onBlur_Level0,
  }">
    <jsv-focus-block name="level1" :onAction="{
      onKeyDown: onKeyDown_Level1,
      onDispatchKeyDown: onDispatchKeyDown_Level1,
      onFocus: onFocus_Level1,
      onBlur: onBlur_Level1,
    }"/>
  </jsv-focus-block>
</template>
<script setup>
/* eslint-disable no-unused-vars */  
import { onMounted } from "vue"  
import { jJsvRuntimeBridge, useFocusHub } from "jsview"

let onKeyDown_Level0 = (event)=>{
  console.log(`level 0 收到回流的按键 code=${event.keyCode}`);
  return false; // 标识为未使用, 允许继续回流
}

let onDispatchKeyDown_Level0 = (event)=>{
  console.log(`level 0 收到下发的按键 code=${event.keyCode}`);
  return false; // 标识为未使用, 允许继续下发
}

let onFocus_Level0 = ()=>{
  console.log(`level 0 收到focus事件`);
}

let onBlur_Level0 = ()=>{
  console.log(`level 0 收到blur事件`);
}

let onKeyDown_Level1 = (event)=>{
  console.log(`level 1 收到回流的按键 code=${event.keyCode}`);
  return false; // 标识为未使用, 允许继续回流
}

let onDispatchKeyDown_Level1 = (event)=>{
  console.log(`level 1 收到下发的按键 code=${event.keyCode}`);
  return false; // 标识为未使用, 允许继续下发
}

let onFocus_Level1 = ()=>{
  console.log(`level 1 收到focus事件`);
}

let onBlur_Level1 = ()=>{
  console.log(`level 1 收到blur事件`);
}

let hub = useFocusHub();
hub.setFocus("level1");

onMounted(()=>{
  jJsvRuntimeBridge.notifyPageLoaded(); // 通知小程序运行器关闭启动图和超时计时器
})
</script>
<style scoped>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  • 将main.ts指向此vue文件
...
// import App from '@/App.vue'
import App from './demo.vue'

const app = createApp(App)
...
1
2
3
4
5
6
  • 运行后的打印(在devtools中看见,或者android中的 adb logcat -s JSIConsole 可以看见)
level 0 收到focus事件
level 1 收到focus事件
1
2
  • 按下OK按键后的打印信息
level 0 收到下发的按键 code=13
level 1 收到下发的按键 code=13
level 1 收到回流的按键 code=13
level 0 收到回流的按键 code=13
1
2
3
4

# 4. 渐进式焦点样例

  • 参考开发环境的
    node_modules/@shijiu/jsview-vue-samples/FocusBlockDemos/ProgressiveFocusControl
    课题通过改动 src/main.ts 的内容启动这个页面:
import { createApp } from 'vue'
import { jsvCreateFocusManager } from 'jsview/utils/JsViewEngineWidget'

// 改动点!!!!! 为如下两行
// import App from '@/App.vue'
import App from 'jsview/samples/FocusBlockDemos/ProgressiveFocusControl/App.vue'

const app = createApp(App)
...
1
2
3
4
5
6
7
8
9

此Demo的示意目的是(节选自本目录App.vue):

<!--
 * 【界面概述】
 * 渐进式焦点展示,整个界面分为上下两个部分,每个部分有3个方格,当方格获焦的时候会变更颜色。
 * 所展示的效果是,上下两个部分只了解到兄弟节点focusBlock的名字,而并不知道其子节点的名字。
 * 当从上部分的子焦点切换到下部分的子焦点过程,是首先指定父节点来进行setFocus,
 * 然后通过onFocus事件处理再进一步setFocus到子焦点上
 *
 *
 * 【技巧说明】
 * Q: 如何进行按键响应?
 * A: 重载函数onKeyDown/onKeyUp/onDispatchKeyDown/onDispatchKeyUp中任何一个关心
 *    的按键事件响应函数,处理ev.keyCode判断按键值,通过返回值控制消息传递链是否中止
 *
 * Q: 如何进行焦点切换?
 * A: 首先为子焦点设置name属性,当需要进行焦点切换的时候,通过 useFocusHub() 提供的hub
 *    的 setFocus 函数处理
 *
 * Q: setFocus的第二个参数keepChildFocus的作用是什么?
 * A: 使用场景举例:
 *    针对有子节点的FocusBlock,当子节点已经获焦后,通过对自身进行setFocus并且设置
 *    keepChildFocus=false,可让自己的子焦点失焦
 *
-->
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

效果如下所示: 一个六个可获焦方块的界面中,分为上层3个方块(分别为A,B,C)为一组,下层3个方块(1,2,3)为另一组,方格处于焦点状态则表现为红色,非焦点状态则表现为绿色


其焦点树关系为:

  App -+- UpPlane -+- A
       |           +- B
       |           +- C
       +- DownPlane -+- 1
                     +- 2
                     +- 3
1
2
3
4
5
6

按照低耦合的程序设计思想,App只调度 UpPlane 和 DownPlane 之间的焦点切换,而当UpPlane获焦后其内部的焦点调度由UpPlane自己完成, 所以落实到代码中就是 App 收到按键处理后,根据按键是否为上键或者下键,进行调度UpPlane和DownPlane(节选自本目录App.vue):

<script setup>
...
const onKeyDownFunc = (ev)=>{
  console.log(`App 根节点 收到回流按键 code=${ev.keyCode}`);

  // 将按键转化为left/right指令
  let keyConsumed = true;
  switch(ev.keyCode) {
    case DefaultKeyCodeMap.Up:
      focusHub.setFocus("UpPlane");
      break;
    case DefaultKeyCodeMap.Down:
      focusHub.setFocus("DownPlane");
      break;
    default:
      keyConsumed = false;
  }

  return keyConsumed; // 若为true则会阻止按键下发到子节点
}
...
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

UpPlane内部当获焦后再进行如下所示(节选自本目录UpPlane.vue)的子节点的调度。

<script setup>
...
const onFocusFunc = () => {
  console.log(`父节点 ${planeName} 获得焦点`);

  // 让子焦点获焦
  lastIndex = globalColumn.index; // 同步全局节点信息
  focusHub.setFocus(ChildBlockNames[lastIndex]);
};
...
</script>
1
2
3
4
5
6
7
8
9
10
11

这种方法叫JsvFocusBlock的渐进式获取焦点的方式。
另外,可以在运行此demo时,打开devtools观察console信息,可观察到上下左右移动焦点时各个模块获焦失焦的打印。

# 5. 自动获焦属性autoFocus

  • 参考开发环境的
    node_modules/@shijiu/jsview-vue-samples/FocusBlockDemos/AutoFocus
    课题通过改动 src/main.ts 的内容启动这个页面:
import { createApp } from 'vue'
import { jsvCreateFocusManager } from 'jsview/utils/JsViewEngineWidget'

// 改动点!!!!! 为如下两行
// import App from '@/App.vue'
import App from 'jsview/samples/FocusBlockDemos/AutoFocus/App.vue'

const app = createApp(App)
...
1
2
3
4
5
6
7
8
9

此Demo的示意目的是(节选自本目录App.vue):

<!--
 * 【界面概述】
 * JsvFocusBlock的autoFocus效果展示
 * 主要用于Dialog弹出的场景,当Dialog内部的JsvFocusBlock设置autoFocus后,
 * Dialog只要展示就会抢走焦点,同时,此样例也展示了,当Dialog退出后,只要App讲焦点
 * 还给Dialog弹出前的焦点分支的根部,按照渐进式焦点处理写法,各级的onFocus触发后
 * 后会再次将焦点传递给目标的子节点
 *
-->
1
2
3
4
5
6
7
8
9

效果图如下所示: 一个三个可获焦方块的界面中,方格处于焦点状态则表现为红色,非焦点状态则表现为绿色,按下OK键时,弹出对话框,对话框通过autoFocus属性获得焦点。在对话框点击OK键后,会返回主界面中启动对话框前的方格上


Dialog中加入autoFocus的处理(节选自本目录下的DialogBlock.vue)如下所示:
可以在运行此demo时,打开devtools观察console信息,可观察到上下左右移动焦点时各个模块获焦失焦的打印。

# 6. 其他技巧提示

提问1: 为什么不把焦点控制集成在普通的HTML元素中?

  • 为了加速焦点传递。

    一个复杂的应用里,可能包含几千个HTML元素,而其中需要只有一小部分需要用到焦点功能。大量的元素去传递按键流,非常影响按键响应时间。

    所以将焦点控制部分单独提取出来做成独立组件,由开发者在需要的地方手动植入,是一个既不影响开发体验,又能获得良好响应时间的处理方法。

提问2: namespace节点如果让带nameSpace的节点尽心共聚焦?

  • 例如namespace1->namespace2->name3,想通过namespace2的引用获取name3时,namespace2所在的命名空间为namespace1,所以路径中需要添加上自己的命名空间。
    <templete>
    <JsvFocusBlock namespace="ns1">
      <JsvFocusBlock namespace="ns2" ref="jfbNs2">
        ...
        <JsvFocusBlock name="n3">
          ...
        </JsvFocusBlock>
      </JsvFocusBlock>
    </JsvFocusBlock>
    </templete>
    
    <script setup>
      import { useFocusHub } from "jsview";
      ...
      const focusHub = useFocusHub();
      focusHub.setFocus("ns2.n3"); // NameSpace以.进行切分
      ...
    </script>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

提问3: 我可以通过名字直接跳转到任意焦点?

  • focusHub.setFocus(name)就可以实现跳转。
import { useFocusHub } from "jsview";
const focusHub = useFocusHub();
//需要跳转焦点时
focusHub.setFocus(name);
1
2
3
4

提问4: 当不知道按键事件发给哪个焦点时?调试过程中想找出当前的焦点时?

  • 在App.vue文件中将 focusHub 挂载到window上,方便devtools的命令输入行调用
<script setup>
import { useFocusHub } from "jsview"

window.DebugJsvFocusHub = useFocusHub();
...
<script>
1
2
3
4
5
6
  • 开始确认焦点前,先按一下按键触发一个按键事件来激活debug的log信息
  • 上述的window.DebugJsvFocusHub对象,通过printGlobalLastFocus接口获得从焦点信息
  • 上述的window.DebugJsvFocusHub对象,通过printFocusList接口获得从根节点到焦点的堆栈信息

提问5: 在代码时如何获取当前焦点的name?

<script setup>
import { useFocusHub } from "jsview"

let hub = useFocusHub();
let name = hub.getCurrentFocus(); // 输出为焦点的名称的String
<script>
1
2
3
4
5
6

提问6: 当焦点丢失时,如何定位焦点丢失到了哪

方案1 通过 FocusHub 的 getCurrentFocus 接口,定位当前焦点到底落在哪了

<script setup>
import { useFocusHub } from "jsview"

let hub = useFocusHub();
let name = hub.getCurrentFocus(); // 输出为焦点的名称的String
<script>
1
2
3
4
5
6

方案2 通过 FocusHub 的 getCurrentFocusStack 接口, 定位从root节点到当前焦点的 stack, 以此确认焦点在哪

<script setup>
import { useFocusHub } from "jsview"

let hub = useFocusHub();
let name = hub.getCurrentFocusStack(); // 输出为焦点的名称的String
<script>
1
2
3
4
5
6

:::

提问7: 如何将焦点退后一级,仅仅让最后一级焦点失焦?

  • 方案1,直接对焦点链上的父焦点进行setFocus
<script setup>
import { useFocusHub } from "jsview"

let hub = useFocusHub();
hub.setFocus(parentName);
<script>
1
2
3
4
5
6
  • 方案2,视通 focusHub 的 returnFocusToParent 接口
<script setup>
import { useFocusHub } from "jsview"

let hub = useFocusHub();
hub.returnFocusToParent();
<script>
1
2
3
4
5
6

提问8: 对焦点执行setFocus时,不想影响其子焦点的focus状态(或者进行焦点回归时,想让回归的这个焦点的子焦点链条恢复成最后一次失焦前的状态)?

  • 方案: setFocus调用的第二个参数设置为true,第二个参数的功能是恢复/保持子链条焦点状态(restoreChildFocus)
<script setup>
import { useFocusHub } from "jsview"

let hub = useFocusHub();
hub.setFocus(parentName, true); // restoreChildFocus = true
<script>
1
2
3
4
5
6
Last Updated: 10/25/2024, 8:52:41 AM