# 微件

# 微件类型

支持两种类型的 widget:in-panel 和 off-panel,每个 widget 都有一个 openAtStart 控制其是否初始打开。

  1. In-panel,即 inPanel 设置为 true,表示需要在一个 panel 中打开的
  2. Off-panel,即 inPanel 设置为 false,表示不需要在 panel 中打开

# 所需文件

一般情况下,一个 widget 只有 1 个 manifest 文件。

# 微件 manifest

{
  // widget的标识名称
  "name": "底图管理",
  // widget的作者
  "author": "MapGIS",
  // widget的描述
  "description": "",
  // widget的组件名,如果inPanel为false,则表示widget本身UI,
  // 如果inPanel为true,其icon会显示到地图占位区域或内容区域中,widget本身UI会展示到Panel中
  "component": "MpBasemapManager",
  // widget图标
  "icon": "<svg class=\"icon\" viewBox=\"0 0 1024 1024\" xmlns=\"http://www.w3.org/2000/svg\" width=\"200\" height=\"200\"><defs><style/></defs><path d=\"M64 64h384v384H64zm512 0h384v384H576zM64 576h384v384H64zm512 0h384v384H576z\"/></svg>",
  // widget属性表
  "properties": {
    // 确定widget是否支持2D,默认为true
    "2D": true,
    // 确定widget是否支持3D,默认为false
    "3D": true,
    // 设置widget是否inPanel,如果不在一个panel中,widget会直接展示,默认为true
    "inPanel": false,
    // 设置为true的话,默认加载config文件,反之不加载,默认为true
    "hasConfig": false,
    // 设为为true的话,builder会加载setting页。如果为false并且widget可配置则展示一个Json编辑器
    "hasSettingPage": true,
    // 如果有setting页,settingUiComponent表示设置页ui的组件名
    "settingUiComponent": "",
    // 确定widget的窗口大小,默认为normal,可设置为normal(常规的,由panel决定)、max(最大化),可不设置
    "windowSize": "max",
    // 自定义widget面板的宽度,Number格式,在经典主题下工具条微件所属面板默认为320,左侧微件所属面板默认为280,可不设置
    "customWidth": 280
    // 确定widget的窗口是否有边距,默认为true,可设置为false,可不设置
    "hasPadding": false,
    // 设置微件是否懒加载,默认为false,当为true的时候,会在打开微件面板时才会去加载微件,可通过此特性控制初始加载的微件数和内存大小
    "lazyload": false,
    // 设置微件是否有UI,默认为true,当inPanel为false且hasUi也为false时,会自动加载该微件,并由内容区域负责该微件的标识和响应
    "hasUi": true,
    // 设置微件实例是否缓存,默认为true,当为false的时候,会在打开微件面板时才会去加载微件,关闭微件面板时销毁微件
    "keepalive": true
  }
}

# 使微件可配置

要使 widget 可配置,需要两个步骤

  1. widget 中有一个配置文件 config.json
  2. 配置 manifest.json 文件中的 properties. hasConfig 为 true

最佳实践是,如果一个 widget 可配置,就需要提供一个配置 UI,让其可以在应用中有自己专属的配置页面。请遵循下面 widget 的约定:

  1. 配置 manifest.json 文件中的 properties. hasSettingPage 为 true
  2. 配置 manifest.json 文件中的 properties. settingUiComponent

# 微件生命周期

# keepalive-缓存

keepalive属性在微件的manifest配置文件中进行配置,用于控制微件面板以及面板中微件的加载时机。该属性默认为"keepalive": true,即微件面板以及面板中的微件会在系统初始化时进行加载,后续对该微操作时会使用系统缓存的微件实例。当设置为"keepalive": false时,每次打开微件面板时都会重新加载微件面板以及面板中的微件,因为在微件面板关闭时会销毁微件面板以及面板中的微件,若微件中存在不会随Vue组件销毁而销毁的其他实例或对象,则需要开发者自行在微件中通过Vue的生命周期钩子函数中进行处理,避免微件再次加载时出现异常,例如注册的eventBus事件监听等。

通过微件配置属性keepalive可实现微件实例的缓存与销毁,该属性通常作用在微件面板组件上,通过代码对配置了该属性的微件进行对应逻辑处理,以默认面板组件MpContentWidgetCard为例,通过计算属性keepalive的值来控制组件MpWindow的创建时机,从而来实现keepalive效果。如果需要自定义微件面板组件且需要该效果,可以参考以下代码进行功能实现。

<template>
  <mp-window
    v-bind="propObject"
    v-if="keepalive"
    :title="widgetInfo.label"
    :width="widgetInfo.properties.customWidth || 320"
    :icon="widgetInfo.icon"
    :is-full-screen="widgetInfo.properties.windowSize === 'max'"
    :has-padding="widgetInfo.properties.hasPadding"
    :z-index="zIndex"
    :visible="visible"
    @update:visible="onUpdateVisible"
    @resize="onResize"
    @window-size="onWindowSize"
  >
    <template>
      <component
        :ref="widgetInfo.id"
        :is="widget.manifest.component"
        :widget="widget"
        @open-other-widget="$emit('open-other-widget', $event)"
        @update-widget-state="$emit('update-widget-state', $event)"
      />
    </template>
  </mp-window>
</template>

<script>
import { WidgetInfoMixin } from '../../mixins'
import { loadWidgetScript } from '../../utils/app-load-script'
import MpWindow from '../../../common/packages/window/Window.vue'

export default {
  name: 'MpContentWidgetCard',
  mixins: [WidgetInfoMixin],
  components: { MpWindow },
  provide() {
   ......
  },
  props: {
   ......
   visible: { type: Boolean, default: true }
  },
  data() {
    return {
      ......
    }
  },
  computed: {
	......
    keepalive() {
      const { properties, component } = this.widgetInfo
      if ('keepalive' in properties) {
        if (
          !properties.keepalive &&
          !this.defaultKeepaliveWidgets.includes(component)
        ) {
          return this.visible
        }
      }
      return true
    }
  },

  created() {
    ......
  },

  methods: {
	......
  }
}
</script>

注意事项:

  1. 以下微件无论是否设置keepalive的值,都不会生效

    - 数据目录 MpDataCatalog
    - 底图管理 MpBasemapManager  
    - 场景设置 MpSceneSetting
    - 图层管理 MpLayerList
    

# lazyload-懒加载

lazyload属性在微件的manifest配置文件中进行配置,用于控制微件的初次加载时机。该配置的默认值为"lazyload": false,即微件会在系统初始化时默认加载,后续对该微操作时使用系统缓存的微件实例。当微件配置设置为"lazyload": true时,只有首次打开微件面板时才会加载微件,然后系统将微件实例进行缓存,后续对该微操作时使用系统缓存的微件实例

通过lazyload属性可实现打开微件面板时加载微件的功能,该属性通常作用在微件面板组件上,通过代码对配置了该属性的微件进行对应逻辑处理,以默认面板组件MpContentWidgetCard为例,通过计算属性isNeedCreate的值来控制动态组件的创建时机,从而来实现lazyload效果。如果需要自定义微件面板组件且需要该效果,可以参考以下代码进行功能实现。

<template>
  <mp-window
    v-bind="propObject"
    :title="widgetInfo.label"
    :width="widgetInfo.properties.customWidth || 320"
    :icon="widgetInfo.icon"
    :is-full-screen="widgetInfo.properties.windowSize === 'max'"
    :has-padding="widgetInfo.properties.hasPadding"
    :z-index="zIndex"
    :visible="visible"
    @update:visible="onUpdateVisible"
    @resize="onResize"
    @window-size="onWindowSize"
  >
    <template>
      <component
        :ref="widgetInfo.id"
        :is="widget.manifest.component"
        v-if="isNeedCreate"
        :widget="widget"
        @open-other-widget="$emit('open-other-widget', $event)"
        @update-widget-state="$emit('update-widget-state', $event)"
      />
    </template>
  </mp-window>
</template>

<script>
import { WidgetInfoMixin } from '../../mixins'
import { loadWidgetScript } from '../../utils/app-load-script'
import MpWindow from '../../../common/packages/window/Window.vue'

export default {
  name: 'MpContentWidgetCard',
  mixins: [WidgetInfoMixin],
  components: { MpWindow },
  provide() {
   ......
  },
  props: {
   ......
   visible: { type: Boolean, default: true }
  },
  data() {
    return {
      needCreate: false,
      needLoadScript: true
    }
  },
  computed: {
	......
    isNeedCreate() {
      if (this.visible) {
        // eslint-disable-next-line vue/no-side-effects-in-computed-properties
        this.needCreate = true
      }
      return (
        (!this.widgetInfo.properties.lazyload || this.needCreate) &&
        !this.needLoadScript
      )
    }
  },

  created() {
    ......
    this.needLoadScript = false
  },

  methods: {
	......
  }
}
</script>

注意事项:

  1. keepalivelazyload一起使用时,若都为默认值,即"keepalive": true "lazyload": false,此时微件面板以及面板中的微件会在系统初始化时进行加载。若"keepalive": falselazyload使用默认值,此时使用keepalive的加载逻辑,反之则使用lazyload的加载逻辑。