• UI5-文档-4.34-Custom Controls


    在这一步中,我们将使用自定义控件扩展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

  • 相关阅读:
    CV baseline之VGG
    CV baseline之Alexnet
    Colab踩得坑
    CV baseline之ResNet
    轻量模型之Distilling the Knowledge in a Neural Network
    轻量模型之Xception
    用Rapidminer做文本挖掘的应用:情感分析
    R语言缺失值的处理:线性回归模型插补
    R语言如何解决线性混合模型中畸形拟合(Singular fit)的问题
    数据类岗位需求的数据面
  • 原文地址:https://www.cnblogs.com/ricoo/p/10103560.html
Copyright © 2020-2023  润新知