
# 在线开发华为云Astro轻应用高级页面自定义组件
#### 操作场景
当华为云Astro轻应用低代码平台提供的预置高级组件无法满足您的开发需求时，开发者可以自定义组件包，并上传到华为云Astro轻应用中。自定义组件包上传到华为云Astro轻应用中后，可在高级页面中使用。自定义组件的开发流程如下：
1. [下载组件模板]
   将华为云Astro轻应用系统预置的模板到本地。
   
2. [开发自定义组件]
   基于下载的模板，在本地根据自身业务需求开发组件。
   
3. [上传组件到组件库并使用组件]
   将开发完的自定义组件上传到组件库，并在高级页面中使用。
   
 
本章节以开发网站中常用的标签切换页面为例，向您介绍如何基于组件模板在线开发组件。参考消费者业务网站（如[图1]所示），页面中主要包含**标签栏** 和**详情展示** **模块**两部分，可以通过切换标签来控制详情展示模块中的展示内容。
图1消费者业务网站示例   
![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001894139220.png "点击放大")
本章节主要在高级页面中，通过两个组件（**标签页组件** 、**信息展示组件** ）复现上述场景。其中，**标签页组件** 包含产品类别（手机、笔记本、平板等），**信息展示组件** 用于展示不同产品类别的图片信息。两个组件通过**事件-动作机制**实现交互，在标签页组件中注册标签切换事件，此事件绑定信息展示组件中切换产品图片的动作。
![](https://support.huaweicloud.com/usermanual-astrozero/public_sys-resources/note_3.0-zh-cn.png)
本章节使用的示例组件开发过程中，使用了前端开发框架[Vue](https://cn.vuejs.org/)及组件库[Element](https://element.eleme.cn/#/zh-CN)。**事件-动作** 机制的详细介绍，请参见[添加事件或宏实现高级页面组件交互](https://support.huaweicloud.com/usermanual-astrozero/astrozero_05_9113.html)。
 #### 下载组件模板
1. 进入[华为云Astro轻应用服务控制台](https://console.huaweicloud.com/appcube/#/home)。
2. 在主页中，单击"进入首页"，进入应用开发页面。
3. 在应用开发页面，单击![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001894139212.png)，选择"环境管理 \> 环境配置"，进入环境配置。
4. 在顶部主菜单中，选择"维护"。
5. 在左侧导航栏中，选择"全局元素 \> 页面资产管理 \> 组件模板"。 
   在组件模板页面，您可以查看到系统预置的几种Widget模板。
   表1组件模板列表 
   | 组件模板名称                  | 功能                                                                                                                                          |
   |:---|:---|
   | widgetVue3Template      | 自定义组件需要使用Vue库时，请选用该模板。                                                                                                                      |
   | widgetPropertyTemplate  | 自定义组件需要通过自定义属性栏配置属性时，请选用该模板。                                                                                                                |
   | widgetActionTemplate    | 自定义组件需要添加动作属性时，请选用该模板。该类型组件开发过程，请参考[添加事件或宏实现高级页面组件交互](https://support.huaweicloud.com/usermanual-astrozero/astrozero_05_9113.html)。         |
   | widgetEventTemplate     | 自定义组件需要添加事件属性时，请选用该模板。该类型组件开发过程，请参考[在线开发华为云Astro轻应用高级页面自定义组件](https://support.huaweicloud.com/usermanual-astrozero/astrozero_05_9110.html)。 |
   | widgetBridgeTemplate    | 自定义组件需要通过桥接器调用后台数据时，请选用该模板。该类型组件开发过程，请参考[使用桥接器为高级页面组件绑定数据](https://support.huaweicloud.com/usermanual-astrozero/astrozero_05_9117.html)。    |
   | widgetPageMacroTemplate | 需要使用页面宏来存储变量时，请选用该模板。                                                                                                                       |
      
   
   
6. 下载组件模板。 
   根据需求选择模板，在组件模板详情页中单击"**下载** "按钮，在"下载组件模板"弹窗中输入组件名称，单击"**保存**"按钮即可。
   本章节示例中同时开发**标签页组件** 和**信息展示组件** ，由于本例中组件基于Vue框架实现，所以优先选择widgetVue3Template模板，**标签页组件** 取名为TabsWidget，**信息展示组件**取名为DisplayWidget。模板组件下载方法如下图所示（以下载TabsWidget为例）：
   图2下载组件模板示例   
   ![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001936098801.png "点击放大")
   图3保存模板   
   ![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001894299160.png "点击放大")
   **如果选择"下载原始模板"，下载到本地的组件包中，组件名称不会被修改。**
   
   
 
 #### 开发自定义组件
1. 初识组件文件结构。 
   将下载到本地的组件包进行解压，使用您熟悉的开发工具进行开发。本章节以[下载组件模板]中下载的TabsWidget组件为例，介绍组件包的文件结构以及各文件的功能。
   表2组件文件结构 
   | 文件名                          | 文件说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
   |:---|:---|
   | TabsWidget.js                | 组件逻辑文件，整个Widget的渲染核心JS，在组件编辑状态和页面最终的发布运行态都会被加载执行。主要包含的预置API说明，请参见[高级页面组件中预置的API](https://support.huaweicloud.com/api-astrozero/astrozero_api_00102.html#section0)。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
   | TabsWidget.editor.js         | 组件属性定义文件，负责组件在编辑状态时，需要渲染的界面和逻辑。"\*.editor.js"只在组件编辑状态被加载，主要包含： - propertiesConfig：主要负责组件配置页面中，右侧的属性配置逻辑。  - create方法仅在组件首次被创建时，调用一次。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
   | TabsWidget.css               | 组件的样式文件，在该文件中编写组件的CSS样式。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
   | TabsWidget.ftl               | 组件DOM结构文件，需要在服务端提前渲染的部分可以写在此文件中，相当于HTML文件，负责样式展示。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
   | packageinfo.json             | 组件的元数据描述文件，定义了如下内容。 - widgetApi name：组件的名称。  - widgetDescription：组件的描述信息。  - authorName：组件的作者信息。  - localFileBasePath：组件本地调测路径。  - i18n：指定组件的国际化资源文件（本例模板中未体现）。  - requires：依赖的库名称和版本号。  - width：在绝对布局高级页面中，添加该组件时的默认宽度，单位为px，不填写默认为200px（本例模板中未体现）。  - height：在绝对布局高级页面中，添加该组件时的默认高度，单位为px，不填写默认为200px（本例模板中未体现）。   |
   | messages-zh/messages-en.json | 组件的国际化资源文件，用于配置多语言（本例模板中未体现）。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
      
   
   
2. 组件DOM结构及逻辑编写。 
   - **TabsWidget组件**
     1. 在TabsWidget组件包TabsWidget.js文件中的render函数下，修改注册的Vue实例。
        ```
        render: function()
            {
                var thisObj = this;
                var widgetProperties = thisObj.getProperties();
                var elem = thisObj.getContainer();
                var items = thisObj.getItems();
                var connectorProperties = thisObj.getConnectorProperties();
                /*
                 * API to get base path of your uploaded widget API file
                 */
                var widgetBasePath = thisObj.getWidgetBasePath();
                if (elem)
                {
                    var containerDiv = $(".scfClientRenderedContainer", elem);
                    if (containerDiv.length)
                    {
                        $(containerDiv).empty();
                    }
                    else
                    {
                        containerDiv = document.createElement('div');
                        containerDiv.className = "scfClientRenderedContainer";
                        $(elem).append(containerDiv);
                    }
                    const app = Vue.createApp({
                        data() {
                          return {
                            activeName: "phone",
                            //定义页签栏中的所含项目
                            tabs: [
                              {label:"手机",name:"phone"},
                              {label:"笔记本",name:"PC"},
                              {label:"平板",name:"pad"},
                              {label:"智慧屏",name:"HiSilicon"},
                              {label:"穿戴",name:"wearableDevice"}
                            ]
                          }
                        },
                        methods:{
                          //此函数在切换页签时触发，用于触发后续步骤中TabsWidget组件注册的切换页签事件
                          handleClick: function () {
                            thisObj.triggerEvent("switchingTab", {param: this.activeName});
                          }
                        }
                    });
                    app.use(ElementPlus);
                    thisObj.vm = app.mount($("#Tabswidget", elem)[0]);
                }
        ```
        
     
     2. 在TabsWidget组件包TabsWidget.ftl文件中，修改DOM结构。
        ```
        <div id="TabsWidget">
           <!-- 此处用到了Element提供的el-tabs组件  -->
           <el-tabs v-model="activeName" @tab-change="handleClick">
              <el-tab-pane
                      v-for="(tab, index) in tabs"
                      :key="index"
                      :label="tab.label"
                      :name="tab.name"
              ></el-tab-pane>
           </el-tabs>
        </div>
        ```
        
      
   
   - **DisplayWidget组件**
     1. 在DisplayWidget组件包DisplayWidget.js文件中的render函数下，修改注册的Vue实例。
        ```
        render: function()
            {
                var thisObj = this;
                var widgetProperties = thisObj.getProperties();
                var elem = thisObj.getContainer();
                var items = thisObj.getItems();
                var connectorProperties = thisObj.getConnectorProperties();
                /*
                 * API to get base path of your uploaded widget API file
                 */
                var widgetBasePath = thisObj.getWidgetBasePath();
                if (elem)
                {
                    var containerDiv = $(".scfClientRenderedContainer", elem);
                    if (containerDiv.length)
                    {
                        $(containerDiv).empty();
                    }
                    else
                    {
                        containerDiv = document.createElement('div');
                        containerDiv.className = "scfClientRenderedContainer";
                        $(elem).append(containerDiv);
                    }
                    const app = Vue.createApp({
                        data() {
                            return {
                                imgSrc: widgetBasePath + "img/phone.jpg",
                                //定义信息展示组件中展示的图片路径信息
                                sources: {
                                    phone: widgetBasePath + "img/phone.jpg",
                                    PC: widgetBasePath + "img/PC.jpg",
                                    pad: widgetBasePath + "img/pad.jpg",
                                    HiSilicon: widgetBasePath + "img/hisilicon.jpg",
                                    wearableDevice: widgetBasePath + "img/wearableDevice.jpg"
                                }
                            }
                        },
                        methods:{
                            //此方法将在后续步骤中DisplayWidget组件注册的切换展示信息的动作中调用
                            switchPic: function (param) {
                                this.imgSrc = this.sources[param];
                            }
                        }
                    });
                    thisObj.vm = app.mount($("#showtabs", elem)[0]);
                }
        ```
        - 上述代码中定义的展示图片文件可使用其他图片代替，将图片放到DisplayWidget目录中即可正常使用。
        
        - 本示例代码中，**widgetBasePath**变量为组件包上传后的路径，在组件模板中已包含获取此变量的逻辑，在此直接使用即可（此例也展示了组件中如何引入本地图片的基本方法）。
         
     
     2. 在DisplayWidget组件包DisplayWidget.ftl文件中，实现DOM结构。
        ```
        <div id="showTabs">
           <img :src="imgSrc">
        </div>
        ```
        
      
   
   
   
   
3. 注册、实现事件和动作。 
   1. 在**TabsWidget** 组件包TabsWidget.js文件中的init函数中，注册页签切换的**事件** 。
      ```
      init: function()
          {
              var thisObj = this;
              thisObj._super.apply(thisObj, arguments);
              thisObj.render();
             if ((typeof(Studio) != "undefined") && Studio)
              {
                var sendEventConfig = [{
                  "name": "param"
                }];
                Studio.registerEvents(
                    thisObj,
                    "switchingTab",
                    {"zh_CN": "切换标签", "en_US": "Switching Tab"},
                    sendEventConfig
                );
              }
          },
      ```
      
   
   2. 在**DisplayWidget** 组件包DisplayWidget.js文件中的init函数中，注册切换展示图片的**动作** 。
      ```
      init: function()
          {
              var thisObj = this;
              thisObj._super.apply(thisObj, arguments);
              thisObj.render();
              if ((typeof(Studio) != "undefined") && Studio)
              {
                  Studio.registerAction(
                      thisObj,
                      "switchingPicture",
                      "switchingPicture",
                      [],
                      $.proxy(thisObj.switchingPicture, thisObj),
                      []
                  );
              }
          },
      ```
      在**DisplayWidget** 组件包DisplayWidget.js文件中的组件示例中（即与init和render方法在同级作用域）实现上述注册的**动作**，示例代码如下所示：
      ```
      switchingPicture: function (event) {
          if (event && event.eventParam) {
              this.vm.switchPic(event.eventParam.param);
          }
      }
      ```
      "DisplayWidget.js"文件中第一行代码"var DisplayWidget = StudioWidgetWrapper.extend();"，其含义为新建的自定义组件继承于平台定义的StudioWidgetWrapper类，此为开发规范，基于此类开发的自定义组件可以使用平台提供的如下方法：
      - "var widgetProperties = thisObj.getProperties(); "用于获取组件的自定义属性配置值。
      
      - "var elem = thisObj.getContainer();" 用于获取组件的DOM元素。
      
      - "var connectorProperties = thisObj.getConnectorProperties();" 用于获取组件的桥接器属性配置值。
       
   
   
   
   
4. 定义组件依赖库及组件在绝对布局中默认尺寸。 
   本节开发的示例组件TabsWidget依赖Vue和Element库，DisplayWidget依赖Vue库。所依赖的Vue库已在之前选择的组件模板"widgetVueTemplate"中定义，这里只需要在TabsWidget组件包的packageinfo.json文件中定义所依赖的Element库即可。
   1. 在华为云Astro轻应用的环境配置中，查看库ID和版本号。 以查询ElementPlus库为例，在环境配置的"维护 \> 全局元素 \> 页面资产管理 \> 库"，搜索库，查看库ID和版本号信息。
      图4查询库信息   
      ![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000002076763010.png "点击放大")
      图5查看库版本和ID   
      ![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001913310574.png "点击放大")
      本例中查询的ElementPlus库ID为：**global_ElementPlu** **s** ，库最新版本号为：**2.6.0**。
      
   
   2. 在TabsWidget组件包的packageinfo.json中，修改requires、width、height属性。
      示例代码如下所示：
      ```
      {
          "widgetApi": [
              {
                  "name": "TabsWidget"
              }
          ],
          "widgetDescription": "",
          "authorName": "",
          "localFileBasePath": "",
          "requires": [
              {
                  "name": "global_Vue3",
                  "version": "3.3.4"
              },
              {
                "name": "global_ElementPlus",
                "version": "2.6.0"
              }
          ],
          "width": "900",
          "height": "55"
      }
      ```
      
   
   3. DisplayWidget组件只依赖Vue库，且在下载时选择的widgetVue3Template组件模板，所依赖的Vue库已在模板中定义，本例无需修改，只需修改width、height属性。
      示例代码如下所示：
      ```
      "width": "900",
      "height": "560",
      ```
      
   
   
   
   
5. 将开发好的组件代码压缩到后缀为.zip的压缩文件中，如TabsWidget.zip、DisplayWidget.zip。
 
 #### 上传组件到组件库并使用组件
1. 上传自定义组件。
   
   1. 将开发好的组件代码压缩到后缀为".zip"的压缩文件中，如TabsWidget.zip、DisplayWidget.zip。
   
   2. 在华为云Astro轻应用环境配置页面的"维护 \> 全局元素 \> 页面资产管理 \> 组件"，单击"提交新组件"。
   
   3. 在提交新组件页面，设置组件基本信息，并上传压缩文件，单击"提交"。
      图6上传自定义组件示例   
      ![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000002141922384.png "点击放大")
      表3上传组件参数说明 
      | 参数    | 说明                                                                                         | 示例                                    |
      |:---|:---|:---|
      | 名字    | 新提交组件的名称，系统会根据组件包名称自动填充。                                                                   | TabsWidget                            |
      | 上传源文件 | 组件源文件包，单击"请选择源文件(.zip)"，选择[5]中的包。                      | TabsWidget.zip                        |
      | 组件ID  | 资产ID，前缀不可编辑，上传组件包后会自动填写。                                                                   | t0000\*\*\*\*\*\*i3m（自动生成）_TabsWidget |
      | 分类    | 组件所属分类，上传组件后，该组件将会在页面的该分类下进行展示。                                                            | 其它                                    |
      | 领域    | 组件包应用的领域，一般保持默认"通用"。                                                                       | 通用                                    |
      | 场景    | 组件包的应用场景，可以勾选多个。勾选后，在相应类型页面开发中才可使用该组件。                                                     | 高级页面                                  |
      | 发行说明  | 组件的描述信息，需要配置不同语种下的描述信息。 此处配置的信息，将会在组件详情页的"概况"页签中进行展示。 | 自定义组件                                 |
         
      
   
   
   
   
2. 组件功能测试。 
   1. 在高级页面中，分别拖入上传的示例组件TabsWidget和DisplayWidget，并调整布局。
   
   2. 选中TabsWidget组件，在右侧"事件"页签，单击"切换标签"后的![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001913469550.png)。
   
   3. 在"编辑事件 "页面，单击"新建动作"，选择"DisplayWidget \> 切换图片"。
   
   4. 单击"确定"，完成组件间交互设置。
   
   5. 在页面上方，单击![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001913309642.png)，保存高级页面。
   
   6. 单击![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001945668741.png)，发布页面，打开发布的页面网址测试效果。
      单击TabsWidget组件上的标签栏，会在DisplayWidget组件详情页进行相应的切换展示。
      
   
   
   
   
 
#### 相关文档
- 自定义组件时，支持开发者直接引用第三方库，来丰富组件的功能，具体操作请参见[使用华为云Astro轻应用开发高级页面时如何引用第三方库](https://support.huaweicloud.com/bestpractice-astrozero/astrozero_bestpractice_0019.html)。
- 组件预置的属性不能满足您的业务需求时，支持为组件自定义属性，具体操作请参见[使用华为云Astro轻应用自定义组件在页面中的属性](https://support.huaweicloud.com/bestpractice-astrozero/astrozero_bestpractice_0036.html)。
- 为组件配置多语言属性，实现组件在不同语种环境下都可正常显示，具体操作请参见[使用华为云Astro轻应用为组件配置中英文语言属性](https://support.huaweicloud.com/bestpractice-astrozero/astrozero_bestpractice_0006.html)。
 
