# 布局和视图

页面整体布局是一个产品最外层的框架结构,往往会包含导航、页脚、侧边栏、通知栏以及内容等。在页面之中,也有很多区块的布局结构。在真实项目中,页面布局通常统领整个应用的界面,有非常重要的作用。

# 基础布局和视图

# 基础布局

我们抽离了使用过程中一些常用的布局,都放在 layouts 目录中,分别为:

  • 通用布局 CommonLayout:MapGIS-Pan-Spatial-Map/src/layouts/UserLayout.vue

    仅包含内容区和页脚的简单布局,项目中常用于注册、登录或展示页面

通用布局

# 基础视图

除了基本布局外,通常有很多页面的结构是相似的。因此,我们把这部分结构抽离为视图组件。
一个视图组件通常包含一个基本布局组件、视图公共区块、路由视图内容区、页脚等,常常结合路由配置使用。它们被放入了 views 目录中,即 MapGIS-Pan-Spatial-Map/src/views/。

# 如何使用

通常我们会把视图组件和路由配置结合一起使用,我们把配置信息抽离在路由配置文件中。

当然,如果这满足不了您的需求,您也可以自定义一些视图组件,或者直接在页面组件中使用布局。

# 专属布局

# 经典版主题布局

经典版主题布局 MpPanSpatialMapClassicTheme,包含了头部导航条,左侧导航条、左侧展示区域、工具条、底部展示区域和内容区。

<template>
  <mapgis-ui-layout class="pan-spatial-map-wrapper">
    <!-- 头部导航条 -->
    <component
      :is="headerContentComponent"
      ref="headerContent"
      v-bind="parseContentProps('header')"
    />
    <mapgis-ui-layout ref="bodyContent">
      <!-- 左侧导航条 -->
      <component
        :is="leftContentComponent"
        ref="leftContent"
        v-bind="parseContentProps('left')"
      />
      <!-- 左侧展示区域 -->
      <mp-pan-spatial-map-side-panel
        v-if="maxSidePanelWidth && mapInitialized"
        v-bind="left.panel"
        :widgets="left.widgets"
        :widgetStructure="left.widgetStructure"
        :max-width="maxSidePanelWidth"
        @update-widget-state="onUpdateWidgetState('left', $event)"
      />
      <mapgis-ui-layout class="main-wrapper">
        <mapgis-ui-layout-content class="content-wrapper">
          <!-- 工具条 -->
          <component
            :is="toolbarContentComponent"
            ref="toolbarContent"
            v-bind="parseContentProps('toolbar')"
          />
          <!-- 内容区 -->
          <slot v-if="mapInitialized" name="map" />
        </mapgis-ui-layout-content>
        <!-- 底部展示区域 -->
        <component
          :is="footerContentComponent"
          v-bind="parseContentProps('footer')"
          :max-view-height="maxFooterHeight"
        />
      </mapgis-ui-layout>
      <mp-map-container
        v-if="configInitialized"
        class="map-wrapper"
        :dataFlowList="dataFlowList"
        :cesium-lib-path="publicPath + 'cesium/Cesium.js'"
        :cesium-plugin-path="publicPath + 'cesium/webclient-cesium-plugin.js'"
        :map-options="mapOptions"
        :popupShowType="popupShowType"
        :dataStoreIp="dataStoreIp"
        :dataStorePort="dataStorePort"
        :getProjectorStatus="getProjectorStatus"
        :minimumLevel="minimumLevel"
        :maximumLevel="maximumLevel"
        @project-screen="handleProjectScreen"
      />
    </mapgis-ui-layout>
  </mapgis-ui-layout>
</template>

经典版主题布局

经典版主题布局由 MpApploader 根据 app.json 生成,指向的主题清单themes/pan-spatial-map-classic-theme/manifest.json共包含了 4 个内容区域。

"contents": [
    {
      "name": "header",
      "description": "头部导航条",
      "component": "MpPanSpatialMapClassicHeader"
    },
    {
      "name": "toolbar",
      "description": "工具条",
      "component": "MpPanSpatialMapClassicToolbar",
      "maxWidgets": 6,
      "subNodeMaxDepth": 2
    },
    {
      "name": "left",
      "description": "左侧导航条",
      "component": "MpPanSpatialMapClassicLeft"
    },
    {
      "name": "footer",
      "description": "底部展示区域",
      "component": "MpPanSpatialMapFooter"
    }
  ]

其中有 3 个区域支持微件配置:

"contentWidgets": {
  "groups": [
    {
      "content": "header",
      "widgets": []
    },
    {
      "content": "left",
      "widgets": [],
      "panel": {
        "relativeTo": "content"
      }
    },
    {
      "content": "toolbar",
      "widgets": []
    }
  ]
}
  • mapWidgets:地图 widgets,都是相对于 map 的,可以定义占位空间,对于 off-panel,设计器可以设置 visible,可以进行拖动(只要 dragble 不为 false)。
  • contentWidgets:内容 widgets,用来供页面导航使用,加入的 widget 必须以 group 的形式存在,添加到布局的 content 中。
{
  // 可选,应用logo,默认值为images/app-logo.svg
  "logo": "images/logo.png",
  // 可选,应用标题
  "title": "MapGIS全空间一张图",
  // 可选,应用副标题
  "subtitle": "",
  //可选. 应用包含的外链列表
  "links": [
    {
      "url": "http://www.smaryun.com",
      "label": "MapGIS Cloud"
    }
  ],
  // 必须,主题
  "theme": {
    // 主题名称,指向themes/name主题
    "name": "pan-spatial-map-classic-theme",
    // 可选,系统主题风格,如果不存在,则使用customStyle
    "style": "night",

    // 可选,自定义主题风格,必须跟style至少存在一个
    "customStyle": {
      "color": "#1890ff",
      "theme": "night"
    }
  },
  // 地图widgets
  "mapWidgets": {
    // widget
    "widgets": [
      {
        // widgetId,builder时动态生成
        "id": "widget_9b4aaff5-c4b1-4402-be60-d2cc4eca0476",
        // widget标识
        "uri": "widgets/map-mode-picker",
        // 可选,widget位置,如果没有设置,默认是相对于map的left=0,top=0
        "position": {
          // 可选,widget位置锚点,默认值为top-left,可以设置为top-right、top-left、bottom-right、bottom-left、top-center、center-right、bottom-center、center-left、center-center
          "anchor": "bottom-left",
          // 可选,widget水平和垂直方向偏移,默认值为0
          "horizontalOffset": 10,
          "verticalOffset": 36
        }
      },
      {
        "id": "widget_9832ede9-8e67-415e-8964-d97a363e247f",
        "uri": "widgets/zoom",
        "position": {
          "anchor": "bottom-left",
          "horizontalOffset": 10,
          "verticalOffset": 78
        }
      }
      {
        "position": {
          "anchor": "top-left",
          "horizontalOffset": 10,
          "verticalOffset": 52
        },
        "placeholder": true
      }
    ],
    // 可选,地图上所有inPanel为true的widget所展示的面板,显示位置根据widget自动计算弹出,
    // 如果不指定,使用系统默认面板MpMapWidgetPanel
    "panel": {
      // 面板组件名
      "component": "MpMapWidgetPanel",
      // 可选,显示模式(single/multi),只有relativeTo为map才有效
      // 如果没有指定,则默认为single
      "mode": "multi"
    }
  },
  // 内容widgets,由布局的内容区域去使用
  "contentWidgets": {
      // 内容widgets分为多组,每组对应布局中的一个内容区域(主题manifest.json中的contents)
    "groups": [
      {
          // 组名
        "content": "header",
        "widgets": [],
        "widgetStructure": [],
        "panel": {
          "position": {
            "anchor": "top-right",
            "horizontalOffset": 10,
            "verticalOffset": 10,
            "bottom": 10
          }
        }
      },
      {
        "content": "left",
        // 该内容区域包含的widget集合,可以有多个,因为内容区域中的widget只要inPanel为true,就会放到面板中显示,所以不需要指定position
        "widgets": [
          {
            "id": "widget_48a29d0c-ece4-474e-9259-65b5095757e7",
            "uri": "widgets/data-catalog",
            "config": "configs/data-catalog/config.json"
          },
          {
            "id": "widget_3e8667b6-71ce-492d-be6f-f8193360b4d2",
            "uri": "widgets/layer-list"
          }
        ],
        "widgetStructure": [],
        "panel": {
            // 可选,指定弹出面板相对的元素(map/content)
          // 如果没有指定,则默认相对于map
          "relativeTo": "content"
        }
      },
      {
        "content": "toolbar",
        "widgets": [
          {
            "id": "widget_878815b5-3f97-4026-80a9-46e683c053b1",
            "uri": "widgets/measurement"
          },
          {
            "id": "widget_8c5d3d2e-b05b-49be-a109-8e3254a9e428",
            "uri": "widgets/add-data",
            "config": "configs/add-data/config.json"
          },
          {
            "id": "widget_bfe8faf2-4568-466b-98fd-877e856ccbd9",
            "uri": "widgets/retrospect"
          },
          {
            "id": "widget_59be6878-b0c1-415b-bab4-f6bd4248e980",
            "uri": "widgets/swipe"
          },
          {
            "id": "widget_98e8c014-e015-400e-8f57-b4a22606c91a",
            "uri": "widgets/func-warehouse",
            "config": "configs/func-warehouse/config.json"
          },
          {
            "id": "widget_72e58aa3-ef5a-4f9c-892d-d7c0cac782a3",
            "uri": "widgets/topology-analysis"
          },
          {
            "id": "widget_af11a3c9-c5cc-464e-acf6-d3fb24560c71",
            "uri": "widgets/network-analysis"
          },
          {
            "id": "widget_ebc4e6c1-e17a-8c5a-6d65-d7f35f1f88c4",
            "uri": "widgets/scene-setting"
          },
          {
            "id": "widget_fa2ea6fd-c838-46bc-9b89-de82fc102e67",
            "uri": "widgets/scene-roaming",
            "config": "configs/scene-roaming/config.json"
          },
          {
            "id": "widget_cad68d22-8084-4616-96f3-a9152cf23444",
            "uri": "widgets/visual-analysis"
          }
        ],
        "widgetStructure": [
          {
            "id": "widget_878815b5-3f97-4026-80a9-46e683c053b1"
          }
          {
            "id": "folder_86c9b153-0d1e-4617-2bc3-09fbae5e6715",
            "type": "folder",
            "label": "对比分析",
            "children": [
              {
                "id": "widget_8c5d3d2e-b05b-49be-a109-8e3254a9e428"
              },
              {
                "id": "widget_bfe8faf2-4568-466b-98fd-877e856ccbd9"
              },
              {
                "id": "widget_59be6878-b0c1-415b-bab4-f6bd4248e980"
              }
            ]
          },
          {
            "id": "folder_42a60a3c-ba22-03b3-de91-5c7932e45612",
            "type": "folder",
            "label": "矢量分析",
            "children": [
              {
                "id": "widget_98e8c014-e015-400e-8f57-b4a22606c91a"
              },
              {
                "id": "widget_72e58aa3-ef5a-4f9c-892d-d7c0cac782a3"
              },
              {
                "id": "widget_af11a3c9-c5cc-464e-acf6-d3fb24560c71"
              }
            ]
          },
          {
            "id": "folder_566d9d41-b02d-e9a6-ab99-28ce895c91de",
            "type": "folder",
            "label": "三维分析",
            "children": [
              {
                "id": "widget_ebc4e6c1-e17a-8c5a-6d65-d7f35f1f88c4"
              },
              {
                "id": "widget_fa2ea6fd-c838-46bc-9b89-de82fc102e67"
              },
              {
                "id": "widget_cad68d22-8084-4616-96f3-a9152cf23444"
              }
            ]
          }
        ],
        // 可选,该内容区域widgets中所有inPanel为true的widget所展示的面板
        // 如果没有指定,则使用系统默认模板MpContentWidgetPanel
        "panel": {
          // 面板组件名
          "component": "MpContentWidgetPanel",
          // 可选,指定弹出面板相对的元素(map/content)
          // 如果没有指定,则默认相对于map
          "relativeTo": "content",
          // 可选,显示模式(single/multi),只有relativeTo为map才有效
          // 如果没有指定,则默认为single
          "mode": "multi",
          // 可选,面板弹出位置,只有relativeTo为map才有效
          "position": {
            // 可选,面板位置锚点,默认值为top-right,可以设置为top-right、top-left、bottom-right、bottom-left、top-center、center-right、bottom-center、center-left、center-center
            "anchor": "top-right",
            // 可选,面板水平和垂直方向偏移,默认值为0(单位:像素)
            "horizontalOffset": 10,
            "verticalOffset": 52,
            // 可选,相对于主视图顶的距离,默认值为0(单位:像素),当height没有指定,且anchor为'bottom-left', 'bottom-right', 'bottom-center'时生效
            "top": 0,
            // 可选,相对于主视图底的距离,默认值为0(单位:像素),当height没有指定,且anchor为'top-left', 'top-right', 'top-center'时生效
            "bottom": 0
          },
          // 可选,面板样式
          "styles": {
            // 可选,是否展开,当position.anchor为top-center、bottom-center、center-left、center-right、center-center时生效
            "expand": false,
            // 可选,面板内容宽度,如果没有传,可设置最小宽度和最大宽度并由内容自适应
            "width": 240,
            // 可选,面板内容高度,如果没有传,查看是否有top或bottom,如果有,将根据距离进行自适应,如果也没有,可设置最小高度和最大高度并由内容自适应
            "height": 480,
            // 可选,面板默认最小内容宽度,默认值240(单位:像素)
            "minWidth": 240,
            // 可选,面板默认最大内容宽度,默认值为100%,只支持像素单位设置
            "maxWidth": 240,
            // 可选,面板默认最小内容宽度,默认值48(单位:像素)
            "minHeight": 48,
            // 可选,面板默认最大内容宽度,默认值为100%,只支持像素单位设置
            "maxHeight": 48
          }
      }
    ]
  }
}

# 其它布局组件

除了内建布局以外,在一些页面中需要进行布局,还可以使用 Ant Design Vue 提供的布局组件:Grid 和 Layout。

# Grid 组件

栅格布局是网页中最常用的布局,其特点就是按照一定比例划分页面,能够随着屏幕的变化依旧保持比例,从而具有弹性布局的特点。

而 Ant Design Vue 的栅格组件提供的功能更为强大,能够设置间距、具有支持响应式的比例设置,以及支持 flex 模式,基本上涵盖了大部分的布局场景,详情查看:Grid (opens new window)

# Layout 组件

如果您需要辅助页面框架级别的布局设计,那么 Layout 则是您最佳的选择,它抽象了大部分框架布局结构,使得只需要填空就可以开发规范专业的页面整体布局,详情查看:Layout (opens new window)

# 根据不同场景区分抽离布局组件

在大部分场景下,我们需要基于上面两个组件封装一些适用于当下具体业务的组件,包含了通用的导航、侧边栏、顶部通知、页面标题等元素。

通常,我们会把抽象出来的布局组件,放到 layouts 文件夹中方便管理。需要注意的是,这些布局组件和我们平时使用的其它组件并没有什么不同,只不过功能性上是为了处理布局问题而单独归类。