[TOC]

之前介绍了widget的简单使用,本次来看一下widget在各种不同的场景下的使用。具体包括和marsui搭配使用、参数配置、动态传参、api、多个根组件场景的处理、widget间的动态交互等。
在学习具体业务场景的使用之前,要先明确一个概念,widget本身并不会负责ui方面的任何事情,总体来说,widget只做了三件事,1. 对ui部分和map部分进行解耦,关联生命周期。2. 对widget各种行为的封装,通过简单的配置和api,完成widget各种交互。 3. 支持对prop的配置和动态修改。当widget的这些特性结合到marsui中的pannel或者dialog使用时,就能够轻松的应对一些复杂场景。

  1. 搭配marsui使用

widget的入口是一个vue单文件组件,在这个组件的模板中我们可以写任何的html或者没有html,在gis的场景中经常需要一些操作面板,这些就可以在组件的模板中来编写这些代码,这个时候又免不了需要去封装一些组件,幸运的是mars-ui恰好解决了这个问题。在火星科技的vue项目中,mars-dialog 和 mars-pannel 通常都会搭配widget一起使用来实现这种操作面板的场景。下面是一个简单的示例

<template>
  <!-- 这是一个宽 370px 位于左上角的固定面板 -->
  <mars-pannel width="370" left="10" top="10">
    <a-space>
      <mars-button>按钮1</mars-button>
      <mars-button>按钮2</mars-button>
      <mars-button>按钮3</mars-button>
    </a-space>
  </mars-pannel>
</template>

<template>
  <!-- 这是一个宽 370px 位于左上角的可移动可缩放的面板 -->
  <mars-dialog width="370" left="10" top="10">
    <a-space>
      <mars-button>按钮1</mars-button>
      <mars-button>按钮2</mars-button>
      <mars-button>按钮3</mars-button>
    </a-space>
  </mars-dialog>
</template>

有一个细节,上面的示例并没有去传入visible参数,那么pannel或者dialog是如何显示的呢,这里就涉及到组件的属性继承。widget已经在外部传入了visible属性,因为两个示例都只存在一个根组件,所以就自动继承的visible属性。我们也可以手动的进行属性继承,后面会这对这种场景具体分析。

  1. 参数配置

WidgetState 接口定义了widget相关的配置参数,具体可参考上一篇文档,(下文中提到的defaultOption、 meta、data等概念也请参看上一篇文档)。这里主要来介绍一下在widget中对ui控件的一些配置。首先在defaultOption中可以为所有的widget配置prop,写法如下:

// widget-store.ts
// 这里配置的参数会被合并到所有组件的prop中,组件中的相同属性将会被覆盖
defaultOption: {
  meta: {
    props: {
      top: 50,
      bottom: 50,
      left: 50
    }
  }
}

除了defaultOption 也可以在每一个widget配置中传入自己的个性化参数,写法如下:

// widget-store.ts
// 这里配置的参数会被合并到本组件的prop中,组件和defaultOption中的相同属性都将会被覆盖
{
  component: markRaw(defineAsyncComponent(() => import("your-widget.vue"))),
  name: "your-widget",
  meta: {
    props: {
      top: 50,
      bottom: 50,
      left: 50
    }
  }
}

以上都是通过配置的方式来设置组件的prop值,widget还支持通过动态调用的方式,进行prop的设置:

import { useWidget } from "@mars/common/store/widget"
const { activate, disable, getWidget } = useWidget()

// 激活 your-widget
activate({
    name: "your-widget",
    data: {
      // 为这个组件设置prop,此处属性的优先级,高于所有配置中的属性
      props: {
        top: 50,
        bottom: 50,
        left: 50
      }
    }
  })
})
  1. API

上面的示例中用到了 activate 这个api,用来激活widget并传递data,他通过useWidget 函数导出,useWidget提供了多个api来操作widget。

export const useWidget: () => {
  // 本页面widget配置数组
  widgets: ComputedRef<Widget[]>
  // 默认开启的widget
  openAtStart: ComputedRef<string[]>
  // 获取指定的widget
  getWidget: (name: string) => Widget
  // 出发对应widget的onUpdate
  updateWidget: (name: string, ...args: any[]) => viod
  // 获取widget的当前激活状态
  isActivate: (name: string) => boolean
  // 激活指定 widget模块
  activate: (widget: string | Widget, reload = true) => void
  // 释放指定的widget
  disable: (name: string) => void
  // 关闭释放所有widget ,hasAll传true值强制释放所有widget(默认autoDisable为false的widet不会释放)
  disableAll: (hasAll?: boolean) => void
}
  1. 多个根组件的场景,假设一个widget的组件像下面这样。
    <template>
    <mars-pannel :width="305" left="15" top="170" bottom="40">
    </mars-pannel>
    <mars-pannel :width="340" right="10" top="10" bottom="40">
    </mars-pannel>
    </template>
    
    此时会发现,这个widget激活之后无法在页面中显示,这是因为这里有两个根组件,此时vue无法自动继承prop,所以需要我们手动的来完成这个继承的操作,所以需要改成下面这样。 ```vue

    这种方式就可以实现具有多个面板的widget,我们也可以根据自身的需求来确定让哪些面板来继承外部的props。甚至在只有一个面板时我们也可以对外部的props做一些自定义的处理。只需要再加上inheritAttrs: false 来禁用继承。
    ```vue
    // 这里禁用了属性继承,并且将内联的prop优先级提升到最高。
    <template>
      <mars-pannel v-bind="attrs" :width="305" left="15" top="170" bottom="40">
      </mars-pannel>
    </template>
    <script setup lang="ts">
    import { useAttrs } from "vue"
    const attrs = useAttrs()
    </script>
    <script lang="ts">
    export default {
      inheritAttrs: false
    }
    </script>
    
    1. widget间的交互

    一些复杂的场景中可能会需要两个widget之间有一些数据的传递,这里是通过updateWidget来实现的。

    // widget1
    <template>
      <mars-pannel width="370" left="10" top="10">
         <mars-button @click="change">按钮1</mars-button>
      </mars-pannel>
    </template>
    <script setup lang="ts">
    import { useWidget } from "@mars/common/store/widget"
    const { updateWidget } = useWidget()
    const change = () => {
      updateWidget("widget2", { 
        /* 传递参数,这里的参数将会被处理成响应式数据,如果需要传递复杂对象,请使用markRaw */ 
      })
    }
    </script>
    
    // widget2
    <script setup lang="ts">
    import { useWidget } from "@mars/common/store/widget"
    
    const { getWidget } = useWidget()
    
    const widget = getWidget("widget2") // 获取自身的widget
    
    widget.onUpdate((...args: any[]) => {
        // 监听 updateWidget 的调用
        console.log(...args)
    })
    </script>
    

    over~~~