每次打开视图时,不会调用onBeforeRendering

时间:2019-03-09 22:46:51

标签: sapui5

在我的UI5应用中,我有一个带有表(sap.m.Table)的视图,该表由来自后端onInit钩的数据填充。问题在于,onInit每个视图实例仅执行一次:

  

每个View实例仅调用一次,与onBeforeRenderingonAfterRendering挂钩不同。

并且如果用户决定离开此视图(例如,向后导航)并在以后重新打开,则onInit将不会被调用,因此将不会再次检索数据,并且表内容将无法反映可能的变化。

为确保每次打开视图时都检索到数据,我尝试在onBeforeRendering处获取数据,但是此挂钩也仅被调用一次。我发现,强制每次打开视图时都调用onBeforeRendering的唯一方法是在onInit方法中添加以下代码:

onInit: function () {
  this.getView().addEventDelegate({
    onBeforeShow: this.onBeforeShow,
  }, this);
}

我的问题:

  1. 为什么没有上面onInit中的代码段,每次显示视图时都不会触发onBeforeRendering

  2. 上面的代码段到底是做什么的?

  3. 替代技术:使用patternMatchedrouteMatched。但是,这三种方法中哪一种比较常见?

3 个答案:

答案 0 :(得分:4)

  
      
  1. 为什么onBeforeRendering不会在每次显示视图时都触发?
  2.   

我认为对“渲染”的含义有误解。在UI5中,当某些东西正在“渲染”时,RenderManager将编写一个完整的新DOM元素。即onBeforeRendering在控件的render函数(在我们的例子中是视图)的调用之前被调用。src

不是并不意味着它是在浏览器将屏幕上的元素绘制之前调用的(为此,现代浏览器提供了本机API,例如Intersection Observer

回到问题;之所以未触发on*Rendering,是因为该控件之前已经呈现过。当用户通过navTo导航然后再次返回时,可以看到这一点。相应的view元素已经在DOM中,因此无需再次调用render,这意味着不会触发任何on*Rendering


  
      
  1. 代码段到底能做什么?

    onInit: function () {
      this.getView().addEventDelegate({
        onBeforeShow: this.onBeforeShow,
      }, this);
    }
    
  2.   

addEventDelegate 向在控件上触发的事件(该控件)添加侦听器。

例如:view contains events类似于afterInitbeforeExit,...
由于此控件 触发了addEventDelegate({onAfterInit}),因此afterInit无法正常工作。
addEventDelegate({onmouseover})之所以有效,是因为它已此控件上触发。

onBeforeShow也是如此。该视图不包含任何事件,例如beforeShowafterShow等。这些事件由NavContainer(例如{{1 }}在其子视图上)。有关这些事件的文档可以在以下位置找到:

另请参阅类似的问题 Why does onBeforeFirstShow work?


  
      
  1. 另一种技巧:使用<App>(...)。但是,这三种方法中哪一种更常见?
  2.   

通过“三种方式”,我想你的意思是:

  • patternMatched(第一种方法),
  • on*Rendering(第二种方法),
  • 以及上述路由事件,例如on*Show(第三种方法)。

答案总是取决于您要实现的目标。但是通常,我们:

  • 如果应用程序没有路由概念(manifest.json中没有patternMatched),请使用第二种方法(NavContainerChild事件)。
  • 如果要在显示视图后设置初始焦点,请对sap.ui5/routing使用第二种方法。参见 How to Set Initial Focus in a View?
  • 使用第三种方法来获取有关匹配的路由模式的通知。此方法通常用于每次显示视图(onAfterShow)时执行某项操作,例如,导航到详细信息页面后执行 Context Binding 。运作方式:

    1. 调用NavContainerChild时,将创建下一个相应的视图和控制器。
    2. 在新创建的控制器的router.navTo()中,分配一个onInit handler
    3. 导航时,URL哈希值将更改。路由器(内部HashChanger)注意到URL更改,从而导致路由触发patternMatched,通过该路由将触发您的处理程序。
  • ⚠️个人观点:避免采用 application 开发人员的第一种方法。避免在patternMatchedonBeforeRendering中执行任何操作,因为从应用程序的角度来看,调用onAfterRendering函数的频率是无法预测的。对于 control 开发人员来说,这些挂钩绝对必要。但是对于应用程序开发人员来说,通常会有更好的选择。

答案 1 :(得分:2)

您应该使用

onInit: function() {
    let route = this.getOwnerComponent().getRouter().getRoute("yourroutename");
    route.attachPatternMatched(this.onRoutePatternMatched, this);
    // ...
},

每次在路由配置中匹配路由模式时,都会触发此路由事件。在上面的示例中,每次通过导航加载路线时都会调用函数onRoutePatternMatched

onRoutePatternMatched: function(event) {
    // this logic will repeat itself every time the route pattern is matched
},

答案 2 :(得分:0)

Boghyon Hoffmann和Bernard的答案目前是解决在导航到页面时需要事件执行某些操作的问题的最佳解决方案。

有一个选项,可以配置路由的目标以清除控制聚合,并在每次导航到时强制其重新呈现。通过此配置,导航到页面时将调用事件onBeforeRenderingonAfterRendering但是,这不是推荐的解决方案,因为它将导致不断重新渲染的性能问题,并且在使用sap.m.NavContainer时应将其设置为false,否则将导致过渡停止以及其他问题。如果您正在使用的sap.ui.ux3.Shell遗留项目(当前已弃用)是可行的解决方案。

因此,要配置此选项,我们需要在 manifest.json 中将选项clearControlAggregation设置为true,使用sap.m.routing.Router时默认为false。

在此链接中,您可以检查路线目标的所有选项: https://sapui5.hana.ondemand.com/#/api/sap.ui.core.routing.Targets

"config": {
    "routerClass": "sap.ui.core.routing.Router",
    "viewPath": "TestApp.view",
    "viewType": "XML",
    "clearControlAggregation": true,
    "controlId": "Main",
    "controlAggregation": "pages",
    "transition": "slide"
}

也可以仅针对特定目标添加此选项,例如:

"targets": {
    "Test1": {
        "viewType": "XML",
        "viewName": "Test1",
        "clearControlAggregation": true,
        "title": "Test1"
    },
    "Test2": {
        "viewType": "XML",
        "viewName": "Test2",
        "title": "Test2"
    }
}