|
| 1 | +<h1 align="center"> |
| 2 | +Ant Design Pro Layout |
| 3 | +</h1> |
| 4 | + |
| 5 | +<div align="center"> |
| 6 | + |
| 7 | +[](https://npmjs.org/package/@ant-design-vue/pro-layout) [](./package.json) [](https://v3.vuejs.org/guide/composition-api-introduction.html) [](https://npmjs.org/package/@ant-design-vue/pro-layout) [](./LICENSE) |
| 8 | + |
| 9 | +</div> |
| 10 | + |
| 11 | +<details> |
| 12 | + <summary> 💻 <b>Preview layout</b>: </summary> |
| 13 | + <br /> |
| 14 | + <img src="https://user-images.githubusercontent.com/5404542/130903472-5020f0ff-a1c3-461a-9072-134b5fdd4c0e.jpeg" /> |
| 15 | + <img src="https://user-images.githubusercontent.com/5404542/130903580-def38691-e912-4a05-aa50-8ab112acf9f4.jpeg" /> |
| 16 | + <img src="https://user-images.githubusercontent.com/5404542/130903670-558423f1-987a-446e-ad56-1d7791e9ad5f.jpeg" /> |
| 17 | + <img src="https://user-images.githubusercontent.com/5404542/130903737-f8a6a404-8445-43fd-830b-d72974edc3ff.jpeg" /> |
| 18 | +</details> |
| 19 | + |
| 20 | +## Basic Usage |
| 21 | + |
| 22 | +Recommend look [Examples](./examples/) or [Use Template](https://github.com/sendya/preview-pro) |
| 23 | + |
| 24 | + |
| 25 | +## Branch |
| 26 | +- next : Vue3 + [email protected] (beta) |
| 27 | +- v3.1 : Vue3 + [email protected] (release LTS) |
| 28 | + |
| 29 | + |
| 30 | +## Install |
| 31 | + |
| 32 | +```bash |
| 33 | +# yarn |
| 34 | +yarn add @ant-design-vue/pro-layout@next |
| 35 | +# npm |
| 36 | +npm i @ant-design-vue/pro-layout@next -S |
| 37 | +``` |
| 38 | + |
| 39 | +### Simple Usage |
| 40 | + |
| 41 | +First, you should add the `@ant-design-vue/pro-layout` that you need into the library. |
| 42 | + |
| 43 | +```js |
| 44 | +// main.[js|ts] |
| 45 | +import '@ant-design-vue/pro-layout/dist/style.css'; // pro-layout css or style.less |
| 46 | + |
| 47 | +import { createApp } from 'vue'; |
| 48 | +import App from "./App.vue"; |
| 49 | +import Antd from 'ant-design-vue'; |
| 50 | +import ProLayout, { PageContainer } from '@ant-design-vue/pro-layout'; |
| 51 | + |
| 52 | +const app = createApp(App); |
| 53 | + |
| 54 | +app.use(Antd).use(ProLayout).use(PageContainer).mount('#app'); |
| 55 | +``` |
| 56 | + |
| 57 | +After that, you can use pro-layout in your Vue components as simply as this: |
| 58 | + |
| 59 | +```vue |
| 60 | +<template> |
| 61 | + <pro-layout |
| 62 | + :locale="locale" |
| 63 | + v-bind="layoutConf" |
| 64 | + v-model:openKeys="state.openKeys" |
| 65 | + v-model:collapsed="state.collapsed" |
| 66 | + v-model:selectedKeys="state.selectedKeys" |
| 67 | + > |
| 68 | + <router-view /> |
| 69 | + </pro-layout> |
| 70 | +</template> |
| 71 | +
|
| 72 | +<script setup lang="ts"> |
| 73 | +import { reactive, useRouter } from 'vue'; |
| 74 | +import { getMenuData, clearMenuItem } from '@ant-design-vue/pro-layout'; |
| 75 | +
|
| 76 | +const locale = (i18n: string) => i18n; |
| 77 | +const router = useRouter(); |
| 78 | +
|
| 79 | +const { menuData } = getMenuData(clearMenuItem(router.getRoutes())); |
| 80 | +
|
| 81 | +const state = reactive({ |
| 82 | + collapsed: false, // default value |
| 83 | + openKeys: ['/dashboard'], |
| 84 | + selectedKeys: ['/welcome'], |
| 85 | +}) |
| 86 | +const layoutConf = reactive({ |
| 87 | + navTheme: 'dark', |
| 88 | + layout: 'mix', |
| 89 | + splitMenus: false, |
| 90 | + menuData, |
| 91 | +}); |
| 92 | +</script> |
| 93 | +``` |
| 94 | + |
| 95 | + |
| 96 | + |
| 97 | +## API |
| 98 | + |
| 99 | +### ProLayout |
| 100 | + |
| 101 | +| Property | Description | Type | Default Value | |
| 102 | +| --- | --- | --- | --- | |
| 103 | +| title | layout in the upper left corner title | VNode \| String | `'Ant Design Pro'` | |
| 104 | +| logo | layout top left logo url | VNode \| render | - | |
| 105 | +| loading | layout loading status | boolean | - | |
| 106 | +| layout | layout menu mode, sidemenu: right navigation, topmenu: top navigation | 'side' \| 'top' \| 'mix' | `'side'` | |
| 107 | +| contentWidth | content mode of layout, Fluid: adaptive, Fixed: fixed width 1200px | 'Fixed' \| 'Fluid' | `Fluid` | |
| 108 | +| navTheme | Navigation theme | 'light' \|'dark' | `'light'` | |
| 109 | +| headerTheme | Header Bar theme | 'light' \|'dark' | `'light'` | |
| 110 | +| menuData | Vue-router `routes` prop | Object | `[{}]` | |
| 111 | +| collapsed | control menu's collapse and expansion | boolean | true | |
| 112 | +| selectedKeys | menu selected keys | string[] | `[]` | |
| 113 | +| openKeys | menu openKeys | string[] | `[]` | |
| 114 | +| isMobile | is mobile | boolean | false | |
| 115 | +| handleCollapse | folding collapse event of menu | (collapsed: boolean) => void | - | |
| 116 | +| menuHeaderRender | render header logo and title | v-slot \| VNode \| (logo,title)=>VNode \| false | - | |
| 117 | +| menuExtraRender | render extra menu item | v-slot \| VNode \| (props)=>VNode \| false | - | |
| 118 | +| menuFooterRender | render footer menu item | v-slot \| VNode \| (props)=>VNode \| false | - | |
| 119 | +| headerContentRender | custom header render method | `slot` \| (props: BasicLayoutProps) => VNode | - | |
| 120 | +| rightContentRender | header right content render method | `slot` \| (props: HeaderViewProps) => VNode | - | |
| 121 | +| collapsedButtonRender | custom collapsed button method | `slot` \| (collapsed: boolean) => VNode | - | |
| 122 | +| footerRender | custom footer render method | `slot` \| (props: BasicLayoutProps) => VNode | `false` | |
| 123 | +| breadcrumbRender | custom breadcrumb render method | `slot` \| ({ route, params, routes, paths, h }) => VNode[] | - | |
| 124 | +| menuItemRender | custom render Menu.Item | v-slot#menuItemRender="{ item, icon }" \| ({ item, icon }) => VNode | null | |
| 125 | +| menuSubItemRender | custom render Menu.SubItem | v-slot#menuSubItemRender="{ item, icon }" \| ({ item, icon }) => VNode | null | |
| 126 | +| locale | i18n | Function (key: string) => string \| `false` | `false` | |
| 127 | + |
| 128 | +> Menu generation requires `getMenuData` and `clearMenuItem` function |
| 129 | +> e.g. `const { menuData } = getMenuData(clearMenuItem(routes))` |
| 130 | +
|
| 131 | +### PageContainer |
| 132 | + |
| 133 | +| Property | Description | Type | Default Value | |
| 134 | +| --- | --- | --- | --- | |
| 135 | +| content | Content area | VNode \| v-slot | - | |
| 136 | +| extra | Extra content area, on the right side of content | VNode \| v-slot | - | |
| 137 | +| extraContent | Extra content area, on the right side of content | VNode \| v-slot | - | |
| 138 | +| tabList | Tabs title list | `Array<{key: string, tab: sting}>` | - | |
| 139 | +| tab-change | Switch panel callback | (key) => void | - | |
| 140 | +| tab-active-key | The currently highlighted tab item | string | - | |
| 141 | + |
| 142 | +### WaterMark |
| 143 | + |
| 144 | +| Property | Description | Type | Default Value | |
| 145 | +| ------------- | ------------------------------------- | ----------------- | ---------------------- | |
| 146 | +| markStyle | mark style | CSSProperties | - | |
| 147 | +| markClassName | mark class | string | - | |
| 148 | +| gapX | Horizontal spacing between water-mark | number | 212 | |
| 149 | +| gapY | Vertical spacing between watermark | number | 222 | |
| 150 | +| offsetLeft | Horizontal offset | number | `offsetTop = gapX / 2` | |
| 151 | +| offsetTop | Vertical offset | number | `offsetTop = gapY / 2` | |
| 152 | +| | | | | |
| 153 | +| width | | number | 120 | |
| 154 | +| height | | number | 64 | |
| 155 | +| rotate | Angle of rotation, unit ° | number | -22 | |
| 156 | +| image | image src | string | - | |
| 157 | +| zIndex | water-mark z-index | number | 9 | |
| 158 | +| content | water-mark Content | string | - | |
| 159 | +| fontColor | font-color | string | `rgba(0,0,0,.15)` | |
| 160 | +| fontSize | font-size | string` \| `number | 16 | |
| 161 | + |
| 162 | + |
| 163 | + |
| 164 | + |
| 165 | +### Custom Render |
| 166 | + |
| 167 | +#### Custom rightContentRender |
| 168 | +```vue |
| 169 | +<template #rightContentRender> |
| 170 | + <div style="margin-right: 12px"> |
| 171 | + <a-avatar shape="square" size="small"> |
| 172 | + <template #icon> |
| 173 | + <UserOutlined /> |
| 174 | + </template> |
| 175 | + </a-avatar> |
| 176 | + </div> |
| 177 | +</template> |
| 178 | +``` |
| 179 | + |
| 180 | +#### Custom menu.item |
| 181 | +```vue |
| 182 | +<template #menuItemRender="{ item, icon }"> |
| 183 | + <a-menu-item |
| 184 | + :key="item.path" |
| 185 | + :disabled="item.meta?.disabled" |
| 186 | + :danger="item.meta?.danger" |
| 187 | + :icon="icon" |
| 188 | + > |
| 189 | + <router-link :to="{ path: item.path }"> |
| 190 | + <span class="ant-pro-menu-item"> |
| 191 | + <a-badge count="5" dot> |
| 192 | + <span class="ant-pro-menu-item-title">{{ item.meta.title }}</span> |
| 193 | + </a-badge> |
| 194 | + </span> |
| 195 | + </router-link> |
| 196 | + </a-menu-item> |
| 197 | +</template> |
| 198 | +``` |
| 199 | + |
| 200 | +#### Custom menuExtraRender |
| 201 | +```vue |
| 202 | +<template #menuExtraRender="{ collapsed }"> |
| 203 | + <a-input-search v-if="!collapsed" /> |
| 204 | +</template> |
| 205 | +``` |
| 206 | + |
| 207 | +#### Custom menuFooterRender |
| 208 | +```vue |
| 209 | +<template #menuFooterRender> |
| 210 | + <div>menu footer</div> |
| 211 | +</template> |
| 212 | +``` |
| 213 | + |
| 214 | +#### Custom breadcrumbRender |
| 215 | +```vue |
| 216 | +<template #breadcrumbRender="{ route, params, routes }"> |
| 217 | + <span v-if="routes.indexOf(route) === routes.length - 1"> |
| 218 | + {{ route.breadcrumbName }} |
| 219 | + </span> |
| 220 | + <router-link v-else :to="{ path: route.path, params }"> |
| 221 | + {{ route.breadcrumbName }} |
| 222 | + </router-link> |
| 223 | +</template> |
| 224 | +``` |
| 225 | + |
| 226 | +#### Custom collapsedButtonRender |
| 227 | +```vue |
| 228 | +<template #collapsedButtonRender="collapsed"> |
| 229 | + <HeartOutlined v-if="collapsed" /> |
| 230 | + <SmileOutlined v-else /> |
| 231 | +</template> |
| 232 | +``` |
| 233 | + |
| 234 | + |
| 235 | +#### Custom footer with slot |
| 236 | +```vue |
| 237 | +<GlobalFooter> |
| 238 | + <template #links> |
| 239 | + <a>链接1</a> |
| 240 | + <a>链接2</a> |
| 241 | + <a>链接3</a> |
| 242 | + <a>链接4</a> |
| 243 | + </template> |
| 244 | + <template #copyright> |
| 245 | + <span>Pro Layout © 2021 Sendya.</span> |
| 246 | + </template> |
| 247 | +</GlobalFooter> |
| 248 | +``` |
| 249 | + |
| 250 | +#### Custom footer with props |
| 251 | +```vue |
| 252 | +<GlobalFooter :links="[{ title: 'Link 1', href: '#' }, { title: 'Link 2', href: '#' }]" copyright="Pro Layout © 2021 Sendya." /> |
| 253 | +``` |
| 254 | + |
| 255 | + |
| 256 | +### Use WaterMark |
| 257 | +```vue |
| 258 | +<router-view v-slot="{ Component }"> |
| 259 | + <WaterMark content="Pro Layout"> |
| 260 | + <component :is="Component" /> |
| 261 | + </WaterMark> |
| 262 | +</router-view> |
| 263 | +``` |
| 264 | + |
| 265 | +## Build project |
| 266 | + |
| 267 | +```bash |
| 268 | +pnpm build # Build library and .d.ts |
| 269 | +``` |
0 commit comments