IT干货网

UI5-文档-4.34-Custom Controls

lxf 2022年03月09日 SAP 144 0

在这一步中,我们将使用自定义控件扩展SAPUI5的功能。我们希望对详细页面上显示的产品进行评级,因此我们使用SAPUI5扩展机制创建了多个标准控件的组合,并添加了一些粘合代码以使它们能够很好地一起工作。这样,我们可以在整个应用程序中重用控件,并将所有相关功能保存在一个模块中。

Preview

 

A custom product rating control is added to the detail page

Coding

You can view and download all files at Walkthrough - Step 34.

 

webapp/control/ProductRating.js (New)

sap.ui.define([ 
        "sap/ui/core/Control" 
],function(Control){ 
        "use strict"; 
        returnControl.extend("sap.ui.demo.walkthrough.control.ProductRating",{ 
               metadata :{ 
               }, 
               init :function(){ 
               }, 
               renderer :function(oRM, oControl){ 
               } 
        }); 
});

我们创建一个新的文件夹控件和一个ProductRating.js文件,它会控制我们的新控件。与我们的控制器和视图一样,自定义控件继承了SAPUI5基本对象的公共控件功能,对于控件来说,这是通过扩展基本类sap.ui.core.Control来完成的。

自定义控件是小的可重用组件,可以非常容易地在应用程序中创建。由于它们的性质,它们有时也被称为“记事本”或“动态”控件。自定义控件是一个JavaScript对象,它有两个特殊部分(元数据和呈现器)和许多实现控件功能的方法。

元数据部分定义数据结构,从而定义控件的API。通过这些关于控件SAPUI5的属性、事件和聚合的元信息,SAPUI5会自动创建setter和getter方法以及其他可以在应用程序中调用的方便函数。

渲染器定义HTML结构,当控件在视图中实例化时,该HTML结构将被添加到应用程序的DOM树中。它最初通常由SAPUI5的核心调用,并在控件的属性发生更改时调用。呈现函数的参数oRM是SAPUI5呈现管理器,可用于将字符串和控制属性写入HTML页面。

init方法是一个特殊的函数,每当控件实例化时,SAPUI5核心就会调用它。可以使用它来设置控件并准备要显示的内容。

请注意:控件总是扩展sap.ui.core。控制和呈现自己。您还可以扩展sa .ui.core。元素或sap.ui.base。如果希望重用SAPUI5的生命周期特性,包括未呈现的对象的数据绑定,可以直接使用ManagedObject。有关控件继承层次结构的更多信息,请参阅API参考。

webapp/control/ProductRating.js

sap.ui.define([ 
        "sap/ui/core/Control", 
        "sap/m/RatingIndicator", 
        "sap/m/Label", 
        "sap/m/Button" 
  
], function (Control,RatingIndicator,Label,Button) { 
        "use strict"; 
        return Control.extend("sap.ui.demo.walkthrough.control.ProductRating", { 
               metadata : { 
                       properties :{ 
                               value:{type :"float", defaultValue :0} 
                       }, 
                       aggregations :{ 
                               _rating :{type :"sap.m.RatingIndicator", multiple:false, visibility :"hidden"}, 
                               _label :{type :"sap.m.Label", multiple:false, visibility :"hidden"}, 
                               _button :{type :"sap.m.Button", multiple:false, visibility :"hidden"} 
                       }, 
                       events :{ 
                               change :{ 
                                      parameters :{ 
                                              value :{type :"int"} 
                                      } 
                               } 
                       } 
               }, 
               init :function(){ 
                       this.setAggregation("_rating",newRatingIndicator({ 
                               value:this.getValue(), 
                               iconSize:"2rem", 
                               visualMode:"Half", 
                               liveChange:this._onRate.bind(this) 
                       })); 
                       this.setAggregation("_label",newLabel({ 
                               text:"{i18n>productRatingLabelInitial}" 
                       }).addStyleClass("sapUiSmallMargin")); 
                       this.setAggregation("_button",newButton({ 
                               text:"{i18n>productRatingButton}", 
                               press:this._onSubmit.bind(this) 
                       }).addStyleClass("sapUiTinyMarginTopBottom")); 
               }, 
  
               setValue:function(fValue){ 
                       this.setProperty("value", fValue,true); 
                       this.getAggregation("_rating").setValue(fValue); 
               }, 
  
               reset:function(){ 
                       var oResourceBundle =this.getModel("i18n").getResourceBundle(); 
  
                       this.setValue(0); 
                       this.getAggregation("_label").setDesign("Standard"); 
                       this.getAggregation("_rating").setEnabled(true); 
                       this.getAggregation("_label").setText(oResourceBundle.getText("productRatingLabelInitial")); 
                       this.getAggregation("_button").setEnabled(true); 
               }, 
  
               _onRate :function(oEvent){ 
                       var oRessourceBundle =this.getModel("i18n").getResourceBundle(); 
                       var fValue = oEvent.getParameter("value"); 
  
                       this.setProperty("value", fValue,true); 
  
                       this.getAggregation("_label").setText(oRessourceBundle.getText("productRatingLabelIndicator",[fValue, oEvent.getSource().getMaxValue()])); 
                       this.getAggregation("_label").setDesign("Bold"); 
               }, 
  
               _onSubmit :function(oEvent){ 
                       var oResourceBundle =this.getModel("i18n").getResourceBundle(); 
  
                       this.getAggregation("_rating").setEnabled(false); 
                       this.getAggregation("_label").setText(oResourceBundle.getText("productRatingLabelFinal")); 
                       this.getAggregation("_button").setEnabled(false); 
                       this.fireEvent("change",{ 
                               value:this.getValue() 
                       }); 
               }, 
               renderer : function (oRM, oControl) { 
                       oRM.write("<div"); 
                       oRM.writeControlData(oControl); 
                       oRM.addClass("myAppDemoWTProductRating"); 
                       oRM.writeClasses(); 
                       oRM.write(">"); 
                       oRM.renderControl(oControl.getAggregation("_rating")); 
                       oRM.renderControl(oControl.getAggregation("_label")); 
                       oRM.renderControl(oControl.getAggregation("_button")); 
                       oRM.write("</div>"); 
               } 
        }); 
});


 现在,我们使用所需的自定义功能增强了新的自定义控件。在我们的例子中,我们希望创建交互式产品评级,因此我们定义了一个值,并使用三个内部控件,这些控件由我们的控件自动更新显示。评级指示器控件用于收集用户对产品的输入,标签显示进一步的信息,按钮将评级提交给应用程序存储。

因此,在元数据部分,我们定义了几个在实现中使用的属性:

▪Properties

       ▪Value

  我们定义一个控件属性值,该属性值将保存用户在评级中选择的值。该属性的Getter和setter函数将自动创建,如果愿意,还可以将其绑定到XML视图中的数据模型字段。

▪Aggregations

  正如第一段所述,我们需要三个内部控制来实现我们的评级功能。因此,我们通过将可见性属性设置为hidden来创建三个“隐藏聚合”。这种方式, 我们可以使用视图上设置的模型,也可以在内部控件中使用,SAPUI5将负责生命周期管理,并在不再需要控件时销毁它们。聚合也可以用于保存控件数组,但是我们只想在每个聚合中有一个控件,因此需要通过将属性multiple设置为false来调整基数。

  _rating: A sap.m.RatingIndicator control for user input

  _label: A sap.m.Label to display additional information

  _button: A sap.m.Button to submit the rating

  请注意:您可以为控件定义聚合和关联。区别在于父控件与相关控件之间的关系:

▪aggregation:

  聚合是一种强关系,它还管理相关控件的生命周期,例如,当父控件被销毁时,相关控件也会被销毁。而且,控件只能分配给一个聚合,如果它被分配给第二个聚合,它将自动从前一个聚合中删除。

▪association:

  关联是一种弱关系,它不管理生命周期,并且可以定义多次。为了明确区别,关联只存储ID,而聚合存储对控件的直接引用。在本例中,我们不指定关联,因为我们希望内部控制由父控件管理。

▪Events

       ▪Change

  我们指定一个更改事件,当提交评级时控件将触发该更改事件。它包含当前值作为事件参数。应用程序可以注册到这个事件并处理类似于“常规”SAPUI5控件的结果,这些控件实际上构建得类似于自定义控件。

 

  在由SAPUI5在实例化控件的新实例时自动调用的init函数中,我们设置了内部控件。我们通过调用继承自sap.ui.core.Control的框架方法setAggregation来实例化这三个控件并将它们存储在内部聚合中。我们传递上面指定的内部聚合的名称和新的控件实例。我们指定了一些控件属性,以使自定义控件看起来更好,并将liveChange事件注册到评级,并将press事件注册到按钮。标签和按钮的初始文本引用自我们的i18n模型。

  现在让我们忽略其他内部帮助函数和事件处理程序,定义我们的渲染器。在SAPUI5呈现管理器和作为引用传递的控件实例的帮助下,我们现在可以呈现控件的HTML结构。我们将外部<div>标记的开头呈现为<div,并调用助手方法writeControlData来呈现div标记内控件的ID和其他基本属性。接下来,我们添加一个自定义CSS类,以便稍后在CSS文件中定义自定义控件的样式规则。在视图中添加的这个CSS类和其他类,然后通过调用renderer实例上的writeClasses来呈现。然后关闭周围的div标记,并通过将内部聚合的内容传递给render managers renderControl函数呈现三个内部控件。这将调用控件的呈现程序并将它们的HTML添加到页面中。最后,关闭周围的<div>标记。

  setValue是一个覆盖的setter。SAPUI5将生成一个setter,在控制器中调用或在XML视图中定义时更新属性值,但我们还需要更新隐藏聚合中的内部评级控制,以正确反映状态。此外,我们还可以通过调用setProperty方法来更新以true作为第三个参数的控件属性,从而跳过在控件上更改属性时通常触发的SAPUI5的重新发布。

  现在我们为内部评级控制定义事件处理程序。每次用户更改评级时都会调用它。可以从sap.m.RatingIndicator 的事件参数值读取评级控制的当前值。通过调用覆盖setter来更新控件状态的值,然后更新评级旁边的标签,向用户显示当前选择的值,并显示最大值。带有占位符值的字符串是从自动分配给控件的i18n模型读取的。

 

接下来,我们拥有提交评级的评级按钮的press处理程序。我们假设对产品进行评级是一次性操作,首先禁用评级和按钮,这样用户就不允许提交其他评级。我们还更新标签以显示“感谢您的评级!”消息,然后触发控件的更改事件,并将当前值作为参数传入,以便侦听此事件的应用程序可以对评级交互作出反应。

我们定义reset方法,以便能够将UI上控件的状态还原为其初始状态,以便用户可以再次提交评级。

 

webapp/view/Detail.view.xml

<mvc:View 
        controllerName="sap.ui.demo.walkthrough.controller.Detail" 
        xmlns="sap.m" 
        xmlns:mvc="sap.ui.core.mvc" 
        xmlns:wt="sap.ui.demo.walkthrough.control"> 
        <Page 
               title="{i18n>detailPageTitle}" 
               showNavButton="true" 
               navButtonPress="onNavBack"> 
               <ObjectHeader 
                       intro="{invoice>ShipperName}" 
                       title="{invoice>ProductName}"/> 
               <wt:ProductRatingid="rating"class="sapUiSmallMarginBeginEnd"change="onRatingChange"/> 
        </Page> 
</mvc:View>

在detail视图上定义了一个新的名称空间wt,以便我们可以在视图中轻松地引用自定义控件。然后,我们将ProductRating控件的一个实例添加到详细信息页面,并为更改事件注册一个事件处理程序。为了获得合适的布局,我们还添加了一个margin样式类。

webapp/controller/Detail.controller.js

sap.ui.define([ 
        "sap/ui/core/mvc/Controller", 
        "sap/ui/core/routing/History", 
        "sap/m/MessageToast" 
], function (Controller, History,MessageToast) { 
        use strict; 
        return Controller.extend(sap.ui.demo.walkthrough.controller.Detail, { 
               … 
               _onObjectMatched: function (oEvent) { 
                       this.byId("rating").reset(); 
                       this.getView().bindElement({ 
                               path: "/" + oEvent.getParameter("arguments").invoicePath, 
                               model: "invoice" 
                       }); 
               }, 
               onNavBack: function () { 
                       … 
               }, 
               onRatingChange :function(oEvent){ 
                       var fValue = oEvent.getParameter("value"); 
                       var oResourceBundle =this.getView().getModel("i18n").getResourceBundle(); 
                       MessageToast.show(oResourceBundle.getText("ratingConfirmation",[fValue])); 
               } 
        }); 
});

在onobjectmatchprivate方法中,我们调用reset方法,以便在显示不同项目的详细信息视图时提交另一个评级。在Detail控制器中,我们将依赖项加载到sap.m。MessageToast,因为我们将简单地显示一条消息,而不是将评级发送到后端,以保持示例的简单性。事件处理程序onRatingChange读取在提交评级时触发的自定义更改事件的值。然后,我们在MessageToast控件中显示带有值的确认消息。

 

webapp/css/style.css

.myAppDemoWTmyCustomButton.sapMBtn { 
        margin-right: 0.125rem; 
} 
.myAppDemoWTmyCustomText { 
        font-weight: bold; 
} 
/*  ProductRating */ 
.myAppDemoWTProductRating { 
        padding:0.75rem; 
} 
.myAppDemoWTProductRating .sapMRI { 
        vertical-align: initial; 
}

我们也可以在渲染器中使用更多的HTML来实现这一点,但这是最简单的方法,它只应用于我们的自定义控件中。但是,请注意,自定义控件在您的应用程序中,可能需要在SAPUI5未来版本的内部控件更改时进行调整。要布局控件,我们向根类添加一些填充,以便在三个内部控件周围留出一些空间,并覆盖RatingIndicator控件的对齐,以便它与标签和按钮对齐在一行。

webapp/i18n/i18n.properties

… 
# Detail Page 
detailPageTitle=Walkthrough - Details 
ratingConfirmation=You have rated this product with {0} stars 
  
# Product Rating 
productRatingLabelInitial=Please rate this product 
productRatingLabelIndicator=Your rating: {0} out of {1} 
productRatingLabelFinal=Thank you for your rating! 
productRatingButton=Rate

Conventions资源包由我们在自定义控件中引用的确认消息和字符串扩展。我们现在可以用全新的控件在详细页面上对产品进行评级。

将自定义控件放到应用程序的控件文件夹中。

Parent topic: Walkthrough


Previous: Step 33: Routing Back and History

Next: Step 35: Responsiveness

Related Information

Developing Controls

Defining the Control Metadata

API Reference: sap.m.RatingIndicator

Samples: sap.m.RatingIndicator

API Reference: sap.m.Label

Samples: sap.m.Label

API Reference: sap.m.Button

Samples: sap.m.Button

API Reference: sap.ui.core.Control

API Reference: sap.ui.core.Element

API Reference: sap.ui.base.ManagedObject


评论关闭
IT干货网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

UI5-文档-4.33-Routing Back and History