From 102ed4bc2dc1d2c1d1261b0fb6d5aa0ac536f386 Mon Sep 17 00:00:00 2001 From: "qixiang.wqx" Date: Tue, 2 Jul 2019 15:41:42 +0800 Subject: [PATCH 1/3] feature/making-el-tree-generic - Adding generic type to ElTree --- types/element-ui.d.ts | 4 ++-- types/tree.d.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/types/element-ui.d.ts b/types/element-ui.d.ts index 9dbe2ef7a7b..4abeb7db393 100644 --- a/types/element-ui.d.ts +++ b/types/element-ui.d.ts @@ -67,7 +67,7 @@ import { ElTimePicker } from './time-picker' import { ElTimeSelect } from './time-select' import { ElTooltip } from './tooltip' import { ElTransfer } from './transfer' -import { ElTree } from './tree' +import { ElTree, TreeData } from './tree' import { ElUpload } from './upload' import { ElLink } from './link' import { ElDivider } from './divider' @@ -305,7 +305,7 @@ export class Tooltip extends ElTooltip {} export class Transfer extends ElTransfer {} /** Tree Component */ -export class Tree extends ElTree {} +export class Tree extends ElTree {} /** Upload Component */ export class Upload extends ElUpload {} diff --git a/types/tree.d.ts b/types/tree.d.ts index f9923f40d42..64dd36ad7dd 100644 --- a/types/tree.d.ts +++ b/types/tree.d.ts @@ -45,7 +45,7 @@ export interface TreeStore { } /** Tree Component */ -export declare class ElTree extends ElementUIComponent { +export declare class ElTree extends ElementUIComponent { /** TreeStore */ store: TreeStore; From 29d9b1966d38a994a25573b5539169cc9d303201 Mon Sep 17 00:00:00 2001 From: "qixiang.wqx" Date: Tue, 16 Jul 2019 10:43:09 +0800 Subject: [PATCH 2/3] Refine documentation and unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feature/drawer - 一个全新的扩展组件, 拥有和 Dialog 几乎一致的 API 和交互模式, 可以使得用户的交互更加丰富. - 对应的 Demo - 对应的 单元测试 - 对应的 使用文档 - 对应的类型定义 --- components.json | 3 +- examples/demo-styles/drawer.scss | 18 ++ examples/demo-styles/index.scss | 1 + examples/docs/en-US/drawer.md | 246 ++++++++++++++++++++ examples/docs/es/drawer.md | 246 ++++++++++++++++++++ examples/docs/fr-FR/drawer.md | 246 ++++++++++++++++++++ examples/docs/zh-CN/drawer.md | 246 ++++++++++++++++++++ examples/nav.config.json | 16 ++ packages/drawer/index.js | 8 + packages/drawer/src/main.vue | 167 ++++++++++++++ packages/theme-chalk/src/drawer.scss | 207 +++++++++++++++++ packages/theme-chalk/src/index.scss | 1 + src/index.js | 5 +- test/unit/specs/drawer.spec.js | 332 +++++++++++++++++++++++++++ types/drawer.d.ts | 63 +++++ types/element-ui.d.ts | 4 + 16 files changed, 1807 insertions(+), 2 deletions(-) create mode 100644 examples/demo-styles/drawer.scss create mode 100644 examples/docs/en-US/drawer.md create mode 100644 examples/docs/es/drawer.md create mode 100644 examples/docs/fr-FR/drawer.md create mode 100644 examples/docs/zh-CN/drawer.md create mode 100644 packages/drawer/index.js create mode 100644 packages/drawer/src/main.vue create mode 100644 packages/theme-chalk/src/drawer.scss create mode 100644 test/unit/specs/drawer.spec.js create mode 100644 types/drawer.d.ts diff --git a/components.json b/components.json index c9322ecd0c1..8785c19f053 100644 --- a/components.json +++ b/components.json @@ -78,5 +78,6 @@ "infinite-scroll": "./packages/infinite-scroll/index.js", "page-header": "./packages/page-header/index.js", "cascader-panel": "./packages/cascader-panel/index.js", - "avatar": "./packages/avatar/index.js" + "avatar": "./packages/avatar/index.js", + "drawer": "./packages/drawer/index.js" } diff --git a/examples/demo-styles/drawer.scss b/examples/demo-styles/drawer.scss new file mode 100644 index 00000000000..a8673836070 --- /dev/null +++ b/examples/demo-styles/drawer.scss @@ -0,0 +1,18 @@ +.demo-drawer { + &__content { + display: flex; + flex-direction: column; + height: 100%; + padding: 10px; + form { + flex: 1; + } + } + + &__footer { + display: flex; + button { + flex: 1; + } + } +} diff --git a/examples/demo-styles/index.scss b/examples/demo-styles/index.scss index 1684fb852b7..0e809e0ed7a 100644 --- a/examples/demo-styles/index.scss +++ b/examples/demo-styles/index.scss @@ -43,4 +43,5 @@ @import "./image.scss"; @import "./infiniteScroll.scss"; @import "./avatar.scss"; +@import "./drawer.scss"; diff --git a/examples/docs/en-US/drawer.md b/examples/docs/en-US/drawer.md new file mode 100644 index 00000000000..e9fbe243f74 --- /dev/null +++ b/examples/docs/en-US/drawer.md @@ -0,0 +1,246 @@ +## Drawer +Sometimes, `Dialog` does not always satisfy our requirements, let's say you have a massive form, or you need space to display something like `terms & conditions`, `Drawer` has almost identical API with `Dialog`, but it introduces different user experience. +### Basic Usage +Callout a temporary drawer, from multiple direction + +:::demo You must set `visible` for `Drawer` like `Dialog` does to control the visibility of `Drawer` itself, it's `boolean` type. `Drawer` has to parts: `title` & `body`, the `title` is a named slot, you can also set the title through attribute named `title`, default to an empty string, the `body` part is the main area of `Drawer`, which contains user defined content. When opening, `Drawer` expand itself from the **right corner to left** which size is **30%** of the browser window by default. You can change that default behavior by setting `direction` and `size` attribute. This show case also demonstrated how to use the `before-close` API, check the Attribute section for more detail +```html + + left to right + right to left + top to bottom + bottom to top + + + + open + + + + Hi, there! + + + +``` +::: + +### Customization Content +Like `Dialog`, `Drawer` can do many diverse interaction as you wanted. + +:::demo +```html +Open Drawer with nested table +Open Drawer with nested form + + + + + + + + + +
+ + + + + + + + + + + + +
+
+ + +``` +::: + +### Nested Drawer +You can also have multiple layer of `Drawer` just like `Dialog`. +:::demo If you need multiple Drawer in different layer, you must set the `append-to-body` attribute to **true** + +```html + + + open + + + +
+ Click me! + +

_(:зゝ∠)_

+
+
+
+ + + +``` +::: + +:::tip +The content inside Drawer should be lazy rendered, which means that the content inside Drawer will not impact the initial render performance, therefore any DOM operation should be performed through `ref` or after `open` event emitted. +::: + +:::tip +Drawer provides an API called `destroyOnClose`, which is a flag variable that indicates should destroy the children content inside Drawer after Drawer was closed. You can use this API when you need your `mounted` life cycle to be called every time the Drawer opens. +::: + +:::tip +If the variable bound to `visible` is managed in Vuex store, the `.sync` can not work properly. In this case, please remove the `.sync` modifier, listen to `open` and `close` events of Dialog, and commit Vuex mutations to update the value of that variable in the event handlers. +::: + +### Drawer Attributes +| Parameter| Description | Type | Acceptable Values | Defaults | +|---------- |-------------- |---------- |-------------------------------- |-------- | +| append-to-body | Controls should Drawer be inserted to DocumentBody Element, nested Drawer must assign this param to **true**| boolean | — | false | +| before-close | If set, closing procedure will be halted | function(done), done is function type that accepts a boolean as parameter, calling done with true or without parameter will abort the close procedure | — | — | +| close-on-press-escape | Indicates whether Drawer can be closed by pressing ESC | boolean | — | true | +| custom-class | Extra class names for Drawer | string | — | — | +| destroy-on-close | Indicates whether children should be destroyed after Drawer closed | boolean | - | false | +| modal | Should show shadowing layer | boolean | — | true | +| modal-append-to-body | Indicates should shadowing layer be insert into DocumentBody element | boolean | — | true | +| direction | Drawer's opening direction | Direction | rtl / ltr / ttb / tbb | rtl | +| show-close | Should show close button at the top right of Drawer | boolean | — | true | +| size | Drawer's size, if Drawer is horizontal mode, it effects the width property, otherwise it effects the height property, when size is `number` type, it describes the size by unit of pixels; when size is `string` type, it should be used with `x%` notation, other wise it will be interpreted to pixel unit | number / string | - | '30%' | +| title | Drawer's title, can also be set by named slot, detailed descriptions can be found in the slot form | string | — | — | +| visible | Should Drawer be displayed, also support the `.sync` notation | boolean | — | false | +| wrapperClosable | Indicates whether user can close Drawer by clicking the shadowing layer. | boolean | - | true | + +### Drawer Slot +| Name | Description | +|------|--------| +| — | Drawer's Content | +| title | Drawer Title Section | + +### Drawer Methods + +| Name | Description | +| ---- | --- | +| closeDrawer | In order to close Drawer, this method will call `before-close`. | + +### Drawer Events +| Event Name | Description | Parameter | +|---------- |-------- |---------- | +| open | Triggered before Drawer opening animation begins | — | +| opened | Triggered after Drawer opening animation ended | — | +| close | Triggered before Drawer closing animation begins | — | +| closed | Triggered after Drawer closing animation ended | — | diff --git a/examples/docs/es/drawer.md b/examples/docs/es/drawer.md new file mode 100644 index 00000000000..e9fbe243f74 --- /dev/null +++ b/examples/docs/es/drawer.md @@ -0,0 +1,246 @@ +## Drawer +Sometimes, `Dialog` does not always satisfy our requirements, let's say you have a massive form, or you need space to display something like `terms & conditions`, `Drawer` has almost identical API with `Dialog`, but it introduces different user experience. +### Basic Usage +Callout a temporary drawer, from multiple direction + +:::demo You must set `visible` for `Drawer` like `Dialog` does to control the visibility of `Drawer` itself, it's `boolean` type. `Drawer` has to parts: `title` & `body`, the `title` is a named slot, you can also set the title through attribute named `title`, default to an empty string, the `body` part is the main area of `Drawer`, which contains user defined content. When opening, `Drawer` expand itself from the **right corner to left** which size is **30%** of the browser window by default. You can change that default behavior by setting `direction` and `size` attribute. This show case also demonstrated how to use the `before-close` API, check the Attribute section for more detail +```html + + left to right + right to left + top to bottom + bottom to top + + + + open + + + + Hi, there! + + + +``` +::: + +### Customization Content +Like `Dialog`, `Drawer` can do many diverse interaction as you wanted. + +:::demo +```html +Open Drawer with nested table +Open Drawer with nested form + + + + + + + + + +
+ + + + + + + + + + + + +
+
+ + +``` +::: + +### Nested Drawer +You can also have multiple layer of `Drawer` just like `Dialog`. +:::demo If you need multiple Drawer in different layer, you must set the `append-to-body` attribute to **true** + +```html + + + open + + + +
+ Click me! + +

_(:зゝ∠)_

+
+
+
+ + + +``` +::: + +:::tip +The content inside Drawer should be lazy rendered, which means that the content inside Drawer will not impact the initial render performance, therefore any DOM operation should be performed through `ref` or after `open` event emitted. +::: + +:::tip +Drawer provides an API called `destroyOnClose`, which is a flag variable that indicates should destroy the children content inside Drawer after Drawer was closed. You can use this API when you need your `mounted` life cycle to be called every time the Drawer opens. +::: + +:::tip +If the variable bound to `visible` is managed in Vuex store, the `.sync` can not work properly. In this case, please remove the `.sync` modifier, listen to `open` and `close` events of Dialog, and commit Vuex mutations to update the value of that variable in the event handlers. +::: + +### Drawer Attributes +| Parameter| Description | Type | Acceptable Values | Defaults | +|---------- |-------------- |---------- |-------------------------------- |-------- | +| append-to-body | Controls should Drawer be inserted to DocumentBody Element, nested Drawer must assign this param to **true**| boolean | — | false | +| before-close | If set, closing procedure will be halted | function(done), done is function type that accepts a boolean as parameter, calling done with true or without parameter will abort the close procedure | — | — | +| close-on-press-escape | Indicates whether Drawer can be closed by pressing ESC | boolean | — | true | +| custom-class | Extra class names for Drawer | string | — | — | +| destroy-on-close | Indicates whether children should be destroyed after Drawer closed | boolean | - | false | +| modal | Should show shadowing layer | boolean | — | true | +| modal-append-to-body | Indicates should shadowing layer be insert into DocumentBody element | boolean | — | true | +| direction | Drawer's opening direction | Direction | rtl / ltr / ttb / tbb | rtl | +| show-close | Should show close button at the top right of Drawer | boolean | — | true | +| size | Drawer's size, if Drawer is horizontal mode, it effects the width property, otherwise it effects the height property, when size is `number` type, it describes the size by unit of pixels; when size is `string` type, it should be used with `x%` notation, other wise it will be interpreted to pixel unit | number / string | - | '30%' | +| title | Drawer's title, can also be set by named slot, detailed descriptions can be found in the slot form | string | — | — | +| visible | Should Drawer be displayed, also support the `.sync` notation | boolean | — | false | +| wrapperClosable | Indicates whether user can close Drawer by clicking the shadowing layer. | boolean | - | true | + +### Drawer Slot +| Name | Description | +|------|--------| +| — | Drawer's Content | +| title | Drawer Title Section | + +### Drawer Methods + +| Name | Description | +| ---- | --- | +| closeDrawer | In order to close Drawer, this method will call `before-close`. | + +### Drawer Events +| Event Name | Description | Parameter | +|---------- |-------- |---------- | +| open | Triggered before Drawer opening animation begins | — | +| opened | Triggered after Drawer opening animation ended | — | +| close | Triggered before Drawer closing animation begins | — | +| closed | Triggered after Drawer closing animation ended | — | diff --git a/examples/docs/fr-FR/drawer.md b/examples/docs/fr-FR/drawer.md new file mode 100644 index 00000000000..e9fbe243f74 --- /dev/null +++ b/examples/docs/fr-FR/drawer.md @@ -0,0 +1,246 @@ +## Drawer +Sometimes, `Dialog` does not always satisfy our requirements, let's say you have a massive form, or you need space to display something like `terms & conditions`, `Drawer` has almost identical API with `Dialog`, but it introduces different user experience. +### Basic Usage +Callout a temporary drawer, from multiple direction + +:::demo You must set `visible` for `Drawer` like `Dialog` does to control the visibility of `Drawer` itself, it's `boolean` type. `Drawer` has to parts: `title` & `body`, the `title` is a named slot, you can also set the title through attribute named `title`, default to an empty string, the `body` part is the main area of `Drawer`, which contains user defined content. When opening, `Drawer` expand itself from the **right corner to left** which size is **30%** of the browser window by default. You can change that default behavior by setting `direction` and `size` attribute. This show case also demonstrated how to use the `before-close` API, check the Attribute section for more detail +```html + + left to right + right to left + top to bottom + bottom to top + + + + open + + + + Hi, there! + + + +``` +::: + +### Customization Content +Like `Dialog`, `Drawer` can do many diverse interaction as you wanted. + +:::demo +```html +Open Drawer with nested table +Open Drawer with nested form + + + + + + + + + +
+ + + + + + + + + + + + +
+
+ + +``` +::: + +### Nested Drawer +You can also have multiple layer of `Drawer` just like `Dialog`. +:::demo If you need multiple Drawer in different layer, you must set the `append-to-body` attribute to **true** + +```html + + + open + + + +
+ Click me! + +

_(:зゝ∠)_

+
+
+
+ + + +``` +::: + +:::tip +The content inside Drawer should be lazy rendered, which means that the content inside Drawer will not impact the initial render performance, therefore any DOM operation should be performed through `ref` or after `open` event emitted. +::: + +:::tip +Drawer provides an API called `destroyOnClose`, which is a flag variable that indicates should destroy the children content inside Drawer after Drawer was closed. You can use this API when you need your `mounted` life cycle to be called every time the Drawer opens. +::: + +:::tip +If the variable bound to `visible` is managed in Vuex store, the `.sync` can not work properly. In this case, please remove the `.sync` modifier, listen to `open` and `close` events of Dialog, and commit Vuex mutations to update the value of that variable in the event handlers. +::: + +### Drawer Attributes +| Parameter| Description | Type | Acceptable Values | Defaults | +|---------- |-------------- |---------- |-------------------------------- |-------- | +| append-to-body | Controls should Drawer be inserted to DocumentBody Element, nested Drawer must assign this param to **true**| boolean | — | false | +| before-close | If set, closing procedure will be halted | function(done), done is function type that accepts a boolean as parameter, calling done with true or without parameter will abort the close procedure | — | — | +| close-on-press-escape | Indicates whether Drawer can be closed by pressing ESC | boolean | — | true | +| custom-class | Extra class names for Drawer | string | — | — | +| destroy-on-close | Indicates whether children should be destroyed after Drawer closed | boolean | - | false | +| modal | Should show shadowing layer | boolean | — | true | +| modal-append-to-body | Indicates should shadowing layer be insert into DocumentBody element | boolean | — | true | +| direction | Drawer's opening direction | Direction | rtl / ltr / ttb / tbb | rtl | +| show-close | Should show close button at the top right of Drawer | boolean | — | true | +| size | Drawer's size, if Drawer is horizontal mode, it effects the width property, otherwise it effects the height property, when size is `number` type, it describes the size by unit of pixels; when size is `string` type, it should be used with `x%` notation, other wise it will be interpreted to pixel unit | number / string | - | '30%' | +| title | Drawer's title, can also be set by named slot, detailed descriptions can be found in the slot form | string | — | — | +| visible | Should Drawer be displayed, also support the `.sync` notation | boolean | — | false | +| wrapperClosable | Indicates whether user can close Drawer by clicking the shadowing layer. | boolean | - | true | + +### Drawer Slot +| Name | Description | +|------|--------| +| — | Drawer's Content | +| title | Drawer Title Section | + +### Drawer Methods + +| Name | Description | +| ---- | --- | +| closeDrawer | In order to close Drawer, this method will call `before-close`. | + +### Drawer Events +| Event Name | Description | Parameter | +|---------- |-------- |---------- | +| open | Triggered before Drawer opening animation begins | — | +| opened | Triggered after Drawer opening animation ended | — | +| close | Triggered before Drawer closing animation begins | — | +| closed | Triggered after Drawer closing animation ended | — | diff --git a/examples/docs/zh-CN/drawer.md b/examples/docs/zh-CN/drawer.md new file mode 100644 index 00000000000..b075c1b4b52 --- /dev/null +++ b/examples/docs/zh-CN/drawer.md @@ -0,0 +1,246 @@ +## Drawer 抽屉 +有些时候, `Dialog` 组件并不满足我们的需求, 比如你的表单很长, 亦或是你需要临时展示一些文档, `Drawer` 拥有和 `Dialog` 几乎相同的 API, 在 UI 上带来不一样的体验. +### 基本用法 +呼出一个临时的侧边栏, 可以从多个方向呼出 + +:::demo 需要设置 `visible` 属性,它的**类型**是 `boolean`,当为 **true** 时显示 Drawer。Drawer 分为两个部分:`title` 和 `body`,`title` 需要具名为 **title** 的 `slot`, 也可以通过 `title` 属性来定义,默认值为空。需要注意的是, Drawer 默认是从右往左打开, 当然可以设置对应的 `direction`, 详细请参考 `direction` 用法 最后,本例还展示了 `before-close` 的用法 +```html + + 从左往右开 + 从右往左开 + 从上往下开 + 从下往上开 + + + + 点我打开 + + + + 我来啦! + + + +``` +::: + +### 自定义内容 +和 `Dialog` 组件一样, `Drawer` 同样可以在其内部嵌套各种丰富的操作 + +:::demo +```html +打开嵌套表格的 Drawer +打开嵌套 Form 的 Drawer + + + + + + + + + +
+ + + + + + + + + + + + +
+
+ + +``` +::: + +### 多层嵌套 +`Drawer` 组件也拥有多层嵌套的方法 +:::demo 同样, 如果你需要嵌套多层 `Drawer` 请一定要设置 `append-to-body` 属性为 **true** + +```html + + + 点我打开 + + + +
+ 打开里面的! + +

_(:зゝ∠)_

+
+
+
+ + + +``` +::: + +:::tip +Drawer 的内容是懒渲染的,即在第一次被打开之前,传入的默认 slot 不会被渲染到 DOM 上。因此,如果需要执行 DOM 操作,或通过 `ref` 获取相应组件,请在 `open` 事件回调中进行。 +::: + +:::tip +Drawer 提供一个 `destroyOnClose` API, 用来在关闭 Drawer 时销毁子组件内容, 例如清理表单内的状态, 在必要时可以将该属性设置为 **true** 用来保证初始状态的一致性 +::: + +:::tip +如果 `visible` 属性绑定的变量位于 Vuex 的 store 内,那么 `.sync` 不会正常工作。此时需要去除 `.sync` 修饰符,同时监听 Drawer 的 `open` 和 `close` 事件,在事件回调中执行 Vuex 中对应的 mutation 更新 `visible` 属性绑定的变量的值。 +::: + +### Drawer Attributes +| 参数 | 说明 | 类型 | 可选值 | 默认值 | +|---------- |-------------- |---------- |-------------------------------- |-------- | +| append-to-body | Drawer 自身是否插入至 body 元素上。嵌套的 Drawer 必须指定该属性并赋值为 true | boolean | — | false | +| before-close | 关闭前的回调,会暂停 Drawer 的关闭 | function(done),done 用于关闭 Drawer | — | — | +| close-on-press-escape | 是否可以通过按下 ESC 关闭 Drawer | boolean | — | true | +| custom-class | Drawer 的自定义类名 | string | — | — | +| destroy-on-close | 控制是否在关闭 Drawer 之后将子元素全部销毁 | boolean | - | false | +| modal | 是否需要遮罩层 | boolean | — | true | +| modal-append-to-body | 遮罩层是否插入至 body 元素上,若为 false,则遮罩层会插入至 Drawer 的父元素上 | boolean | — | true | +| direction | Drawer 打开的方向 | Direction | rtl / ltr / ttb / tbb | rtl | +| show-close | 是否显示关闭按钮 | boolean | — | true | +| size | Drawer 窗体的大小, 当使用 `number` 类型时, 以像素为单位, 当使用 `string` 类型时, 请传入 'x%', 否则便会以 `number` 类型解释 | number / string | - | '30%' | +| title | Drawer 的标题,也可通过具名 slot (见下表)传入 | string | — | — | +| visible | 是否显示 Drawer,支持 .sync 修饰符 | boolean | — | false | +| wrapperClosable | 点击遮罩层是否可以关闭 Drawer | boolean | - | true | + +### Drawer Slot +| name | 说明 | +|------|--------| +| — | Drawer 的内容 | +| title | Drawer 标题区的内容 | + +### Drawer Methods + +| name | 说明 | +| ---- | --- | +| closeDrawer | 用于关闭 Drawer, 该方法会调用传入的 `before-close` 方法 | + +### Drawer Events +| 事件名称 | 说明 | 回调参数 | +|---------- |-------- |---------- | +| open | Drawer 打开的回调 | — | +| opened | Drawer 打开动画结束时的回调 | — | +| close | Drawer 关闭的回调 | — | +| closed | Drawer 关闭动画结束时的回调 | — | diff --git a/examples/nav.config.json b/examples/nav.config.json index 36e3d3ac851..0daf262df51 100644 --- a/examples/nav.config.json +++ b/examples/nav.config.json @@ -283,6 +283,10 @@ { "path": "/infiniteScroll", "title": "InfiniteScroll 无限滚动" + }, + { + "path": "/drawer", + "title": "Drawer 抽屉" } ] } @@ -573,6 +577,10 @@ { "path": "/avatar", "title": "Avatar" + }, + { + "path": "/drawer", + "title": "Drawer" } ] } @@ -863,6 +871,10 @@ { "path": "/avatar", "title": "Avatar" + }, + { + "path": "/drawer", + "title": "Drawer" } ] } @@ -1153,6 +1165,10 @@ { "path": "/avatar", "title": "Avatar" + }, + { + "path": "/drawer", + "title": "Drawer" } ] } diff --git a/packages/drawer/index.js b/packages/drawer/index.js new file mode 100644 index 00000000000..803e071d099 --- /dev/null +++ b/packages/drawer/index.js @@ -0,0 +1,8 @@ +import Drawer from './src/main'; + +/* istanbul ignore next */ +Drawer.install = function(Vue) { + Vue.component(Drawer.name, Drawer); +}; + +export default Drawer; diff --git a/packages/drawer/src/main.vue b/packages/drawer/src/main.vue new file mode 100644 index 00000000000..e8957388138 --- /dev/null +++ b/packages/drawer/src/main.vue @@ -0,0 +1,167 @@ + + + diff --git a/packages/theme-chalk/src/drawer.scss b/packages/theme-chalk/src/drawer.scss new file mode 100644 index 00000000000..665c81dd704 --- /dev/null +++ b/packages/theme-chalk/src/drawer.scss @@ -0,0 +1,207 @@ +@import "mixins/mixins"; +@import "common/var"; + +@keyframes el-drawer-fade-in { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +@mixin drawer-animation($direction) { + + @keyframes #{$direction}-drawer-in { + 0% { + + @if $direction == ltr { + transform: translate(-100%, 0px); + } + + @if $direction == rtl { + transform: translate(100%, 0px); + } + + @if $direction == ttb { + transform: translate(0px, -100%); + } + + @if $direction == btt { + transform: translate(0px, 100%); + } + } + + 100% { + @if $direction == ltr { + transform: translate(0px, 0px); + } + + @if $direction == rtl { + transform: translate(0px, 0px); + } + + @if $direction == ttb { + transform: translate(0px, 0px); + } + + @if $direction == btt { + transform: translate(0px, 0px); + } + } + } + + @keyframes #{$direction}-drawer-out { + 0% { + @if $direction == ltr { + transform: translate(0px, 0px); + } + + @if $direction == rtl { + transform: translate(0px, 0px);; + } + + @if $direction == ttb { + transform: translate(0px, 0px); + } + + @if $direction == btt { + transform: translate(0px, 0); + } + } + + 100% { + @if $direction == ltr { + transform: translate(-100%, 0px); + } + + @if $direction == rtl { + transform: translate(100%, 0px); + } + + @if $direction == ttb { + transform: translate(0px, -100%); + } + + @if $direction == btt { + transform: translate(0px, 100%); + } + } + } +} + +@mixin animation-in($direction) { + .el-drawer__open &.#{$direction} { + animation: #{$direction}-drawer-in 225ms cubic-bezier(0, 0, .2, 1) 0ms; + } +} + +@mixin animation-out($direction) { + &.#{$direction} { + animation: #{$direction}-drawer-out 225ms cubic-bezier(0, 0, .2, 1) 0ms; + } +} + +@include drawer-animation(rtl) +@include drawer-animation(ltr) +@include drawer-animation(ttb) +@include drawer-animation(btt) + +$directions: rtl, ltr, ttb, btt; + +@include b(drawer) { + position: absolute; + box-sizing: border-box; + background-color: $--dialog-background-color; + display: flex; + flex-direction: column; + box-shadow: 0 8px 10px -5px rgba(0, 0, 0, 0.2), + 0 16px 24px 2px rgba(0, 0, 0, 0.14), + 0 6px 30px 5px rgba(0, 0, 0, 0.12); + overflow: hidden; + + @each $direction in $directions { + @include animation-out($direction); + @include animation-in($direction); + } + + &__header { + align-items: center; + color: rgb(114, 118, 123); + display: flex; + margin-bottom: 32px; + padding: $--dialog-padding-primary; + padding-bottom: 0; + & > :first-child { + flex: 1; + } + } + + &__title { + margin: 0; + flex: 1; + line-height: inherit; + font-size: 1rem; + } + + &__close-btn { + border: none; + cursor: pointer; + font-size: $--font-size-extra-large; + color: inherit; + background-color: transparent; + } + + &__body { + flex: 1; + & > * { + box-sizing: border-box; + } + } + + &.ltr, &.rtl { + height: 100%; + top: 0; + bottom: 0; + } + + &.ttb, &.btt { + width: 100%; + left: 0; + right: 0; + } + + &.ltr { + left: 0; + } + + &.rtl { + right: 0; + } + + &.ttb { + top: 0; + } + + &.btt { + bottom: 0; + } +} + +.el-drawer__container { + position: relative; + left: 0; + right: 0; + top: 0; + bottom: 0; + height: 100%; + width: 100%; +} + +.el-drawer-fade-enter-active { + animation: el-drawer-fade-in 225ms cubic-bezier(0, 0, 0.2, 1) 0ms; +} + +.el-drawer-fade-leave-active { + animation: el-drawer-fade-in 225ms cubic-bezier(0, 0, 0.2, 1) 0ms reverse; +} diff --git a/packages/theme-chalk/src/index.scss b/packages/theme-chalk/src/index.scss index c7b85f7446f..8cdb8c13ce4 100644 --- a/packages/theme-chalk/src/index.scss +++ b/packages/theme-chalk/src/index.scss @@ -76,3 +76,4 @@ @import "./page-header.scss"; @import "./cascader-panel.scss"; @import "./avatar.scss"; +@import "./drawer.scss"; diff --git a/src/index.js b/src/index.js index 74f33d57b5e..b6aa3ef6cd0 100644 --- a/src/index.js +++ b/src/index.js @@ -80,6 +80,7 @@ import InfiniteScroll from '../packages/infinite-scroll/index.js'; import PageHeader from '../packages/page-header/index.js'; import CascaderPanel from '../packages/cascader-panel/index.js'; import Avatar from '../packages/avatar/index.js'; +import Drawer from '../packages/drawer/index.js'; import locale from 'element-ui/src/locale'; import CollapseTransition from 'element-ui/src/transitions/collapse-transition'; @@ -159,6 +160,7 @@ const components = [ PageHeader, CascaderPanel, Avatar, + Drawer, CollapseTransition ]; @@ -278,5 +280,6 @@ export default { InfiniteScroll, PageHeader, CascaderPanel, - Avatar + Avatar, + Drawer }; diff --git a/test/unit/specs/drawer.spec.js b/test/unit/specs/drawer.spec.js new file mode 100644 index 00000000000..90b96cf1792 --- /dev/null +++ b/test/unit/specs/drawer.spec.js @@ -0,0 +1,332 @@ +import { createVue, destroyVM, waitImmediate, wait } from '../util'; + +const title = '我是测试 title'; +const content = 'content'; + +describe('Drawer', () => { + let vm; + afterEach(() => { + destroyVM(vm); + }); + + it('create', async() => { + vm = createVue( + { + template: ` + + `, + data() { + return { + title, + visible: true + }; + } + }, + true + ); + const drawer = vm.$children[0]; + await waitImmediate(); + expect(document.querySelector('.v-modal')).to.exist; + expect(vm.$el.querySelector('.el-drawer__header').textContent).to.equal( + title + ); + expect(drawer.$el.style.display).to.not.equal('none'); + }); + + it('render correct content', async() => { + vm = createVue( + { + template: ` + + 这是一段信息 + 取消 + 确定 + + `, + + data() { + return { + title: 'drawer test', + visible: true + }; + } + }, + true + ); + await waitImmediate(); + expect(vm.$el.querySelector('.el-drawer__body span').textContent).to.equal( + '这是一段信息' + ); + const footerBtns = vm.$el.querySelectorAll('.el-button'); + expect(footerBtns.length).to.equal(2); + expect(footerBtns[0].querySelector('span').textContent).to.equal('取消'); + expect(footerBtns[1].querySelector('span').textContent).to.equal('确定'); + }); + + it('should append to body, when append-to-body flag is true', async() => { + vm = createVue( + { + template: ` + + content + + `, + data() { + return { + title, + visible: true + }; + } + }, + true + ); + await waitImmediate(); + expect(vm.$el.parentNode).to.equal(document.body); + }); + + it('should open and close drawer properly', async() => { + vm = createVue({ + template: ` + + ${content} + + `, + data() { + return { + title, + visible: false + }; + } + }); + let drawer = vm.$children[0].$el; + expect(drawer.style.display).to.equal('none'); + vm.visible = true; + await waitImmediate(); + expect(drawer.style.display).not.to.equal('none'); + vm.visible = false; + await wait(400); + expect(drawer.style.display).to.equal('none'); + }); + + it('should destroy every child after drawer was closed when destroy-on-close flag is true', async() => { + vm = createVue({ + template: ` + + ${content} + + `, + data() { + return { + title, + visible: true + }; + } + }); + + await waitImmediate(); + expect(vm.$el.querySelector('.el-drawer__body span').textContent).to.equal( + content + ); + vm.$refs.drawer.closeDrawer(); + await wait(400); + expect(vm.$el.querySelector('.el-drawer__body')).not.to.exist; + }); + + it('should close dialog by clicking the close button', async() => { + vm = createVue({ + template: ` + + ${content} + + `, + data() { + return { + title, + visible: true + }; + } + }); + + await waitImmediate(); + vm.$children[0].$el.querySelector('.el-drawer__close-btn').click(); + expect(vm.visible).to.equal(false); + }); + + it('should invoke before-close', async() => { + const beforeClose = sinon.spy(); + vm = createVue({ + template: ` + + ${content} + + `, + data() { + return { + title, + visible: true, + beforeClose + }; + } + }); + + await waitImmediate(); + vm.$refs.drawer.closeDrawer(); + await waitImmediate(); + expect(beforeClose.called).to.be.true; + }); + + it('should not show close button when show-close flag is false', async() => { + vm = createVue({ + template: ` + + ${content} + + `, + data() { + return { + title, + visible: false + }; + } + }); + expect(vm.$el.querySelector('.el-drawer__close-btn')).not.to.exist; + }); + + it('should have custom classes when custom classes were given', async() => { + const classes = 'some-custom-class'; + vm = createVue({ + template: ` + + ${content} + + `, + data() { + return { + title, + visible: false + }; + } + }); + + expect(vm.$el.querySelector(`.${classes}`)).to.exist; + }); + + describe('directions', () => { + const renderer = direction => { + return createVue({ + template: ` + + ${content} + + `, + data: { + visible: true, + title + } + }); + }; + it('should render from left to right', async() => { + vm = renderer('ltr'); + await waitImmediate(); + expect(vm.$el.querySelector('.ltr')).to.exist; + }); + + it('should render from right to left', async() => { + vm = renderer('rtl'); + await waitImmediate(); + expect(vm.$el.querySelector('.rtl')).to.exist; + }); + + it('should render from top to bottom', async() => { + vm = renderer('ttb'); + await waitImmediate(); + expect(vm.$el.querySelector('.ttb')).to.exist; + }); + + it('should render from bottom to top', async() => { + vm = renderer('btt'); + await waitImmediate(); + expect(vm.$el.querySelector('.btt')).to.exist; + }); + }); + + it('events', async() => { + const open = sinon.spy(); + const opened = sinon.spy(); + const close = sinon.spy(); + const closed = sinon.spy(); + + vm = createVue({ + template: ` + + ${content} + + `, + data() { + return { + content, + visible: false, + title + }; + }, + methods: { + close, + closed, + open, + opened + } + }); + vm.visible = true; + await wait(400); + expect(open.called).to.be.true; + expect(opened.called).to.be.true; + expect(close.called).to.be.false; + expect(closed.called).to.be.false; + vm.visible = false; + await wait(500); + expect(close.called).to.be.true; + expect(closed.called).to.be.true; + }); + + describe('size', () => { + const renderer = (size, isVertical) => + createVue({ + template: ` + + ${content} + + `, + data: { + visible: true, + title + } + }); + + it('should effect height when drawer is vertical', async() => { + const size = '50%'; + vm = renderer(size, true); + + expect(vm.$el.querySelector('.el-drawer').style.width).to.equal('50%'); + }); + + it('should effect width when drawer is horizontal', async() => { + const size = '50%'; + vm = renderer(size, false); + expect(vm.$el.querySelector('.el-drawer').style.height).to.equal('50%'); + }); + }); +}); diff --git a/types/drawer.d.ts b/types/drawer.d.ts new file mode 100644 index 00000000000..8d2d7f3a520 --- /dev/null +++ b/types/drawer.d.ts @@ -0,0 +1,63 @@ +import { ElementUIComponent } from './component' +import { VNode } from 'vue' + +type hide = (shouldCancel: boolean) => void +declare enum Direction { + LTR = 'ltr', // left to right + RTL = 'rtl', // right to left + TTB = 'ttb', // top to bottom + BTT = 'btt' // bottom to top +} + +interface DrawerSlots { + /* Main Content Slots */ + default: VNode[]; + + /* Title Slots */ + title: VNode[]; + + [key: string]: VNode[] +} +/** Drawer Component */ +export declare class ElDrawer extends ElementUIComponent { + /* Equivalent to `Dialog`'s append to body attribute, when applying nested drawer, make sure this one is set to true */ + appendToBody: boolean + + /* Hook method called before close drawer, the first parameter is a function which should determine if the drawer should be closed */ + beforeClose: (done: hide) => void + + /** Whether the Drawer can be closed by pressing ESC */ + closeOnPressEscape: boolean + + /** Custom class names for Dialog */ + customClass: string + + /* Determine whether the wrapped children should be destroyed, if true, children's destroyed life cycle method will be called all local state will be destroyed */ + destroyOnClose: boolean + + /* Equivalent to `Dialog`'s modal attribute, determines whether the dark shadowing background should show */ + modal: boolean + + /* Equivalent to `Dialog`'s modal-append-to-body attribute, determines whether the shadowing background should be inserted direct to DocumentBody element */ + modalAppendToBody: boolean + + /* Attributes that controls the drawer's direction of display*/ + position: Direction + + /* Whether the close button should be rendered to control the drawer's visible state */ + showClose: boolean + + /* The size of the drawer component, supporting number with unit of pixel, string by percentage e.g. 30% */ + size: number | string + + /* The Drawer's title, also can be replaced by named slot `title` */ + title: string + + /* Whether the drawer component should show, also can be decorated by `.sync` */ + visible: boolean + + /* Flag attribute whi */ + wrapperClosable: boolean + + $slots: DrawerSlots +} diff --git a/types/element-ui.d.ts b/types/element-ui.d.ts index 4abeb7db393..6e6543b2a46 100644 --- a/types/element-ui.d.ts +++ b/types/element-ui.d.ts @@ -78,6 +78,7 @@ import { ElBacktop } from './backtop' import { ElInfiniteScroll } from './infiniteScroll' import { ElPageHeader } from './page-header' import { ElAvatar } from './avatar' +import { ElDrawer } from './drawer' export interface InstallationOptions { locale: any, @@ -336,3 +337,6 @@ export class PageHeader extends ElPageHeader {} /** Avatar Component */ export class Avatar extends ElAvatar {} + +/** Drawer Component */ +export class Drawer extends ElDrawer {} From 6c3638a95058b4f73c927c3be9dc1b12b8b4f1b7 Mon Sep 17 00:00:00 2001 From: JeremyWuuuuu <591449570@qq.com> Date: Wed, 24 Jul 2019 16:39:09 +0800 Subject: [PATCH 3/3] =?UTF-8?q?-=20=E8=B0=83=E6=95=B4=E4=BA=86=20demo=20?= =?UTF-8?q?=E7=9A=84=E6=A0=B7=E5=BC=8F=20Adjust=20demo=20styles=20-=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E6=96=87=E6=A1=A3=E7=9A=84=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=20Modify=20documentation=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/demo-styles/drawer.scss | 5 ++++- examples/docs/en-US/drawer.md | 16 ++++++++++++++++ examples/docs/es/drawer.md | 16 ++++++++++++++++ examples/docs/fr-FR/drawer.md | 16 ++++++++++++++++ examples/docs/zh-CN/drawer.md | 17 +++++++++++++++++ 5 files changed, 69 insertions(+), 1 deletion(-) diff --git a/examples/demo-styles/drawer.scss b/examples/demo-styles/drawer.scss index a8673836070..117136171f8 100644 --- a/examples/demo-styles/drawer.scss +++ b/examples/demo-styles/drawer.scss @@ -3,7 +3,6 @@ display: flex; flex-direction: column; height: 100%; - padding: 10px; form { flex: 1; } @@ -16,3 +15,7 @@ } } } + +.el-drawer__body { + padding: 20px; +} diff --git a/examples/docs/en-US/drawer.md b/examples/docs/en-US/drawer.md index e9fbe243f74..d52ac42419f 100644 --- a/examples/docs/en-US/drawer.md +++ b/examples/docs/en-US/drawer.md @@ -1,9 +1,13 @@ ## Drawer + Sometimes, `Dialog` does not always satisfy our requirements, let's say you have a massive form, or you need space to display something like `terms & conditions`, `Drawer` has almost identical API with `Dialog`, but it introduces different user experience. + ### Basic Usage + Callout a temporary drawer, from multiple direction :::demo You must set `visible` for `Drawer` like `Dialog` does to control the visibility of `Drawer` itself, it's `boolean` type. `Drawer` has to parts: `title` & `body`, the `title` is a named slot, you can also set the title through attribute named `title`, default to an empty string, the `body` part is the main area of `Drawer`, which contains user defined content. When opening, `Drawer` expand itself from the **right corner to left** which size is **30%** of the browser window by default. You can change that default behavior by setting `direction` and `size` attribute. This show case also demonstrated how to use the `before-close` API, check the Attribute section for more detail + ```html left to right @@ -47,9 +51,11 @@ Callout a temporary drawer, from multiple direction ::: ### Customization Content + Like `Dialog`, `Drawer` can do many diverse interaction as you wanted. :::demo + ```html Open Drawer with nested table Open Drawer with nested form @@ -148,6 +154,7 @@ export default { ::: ### Nested Drawer + You can also have multiple layer of `Drawer` just like `Dialog`. :::demo If you need multiple Drawer in different layer, you must set the `append-to-body` attribute to **true** @@ -197,18 +204,25 @@ You can also have multiple layer of `Drawer` just like `Dialog`. ::: :::tip + The content inside Drawer should be lazy rendered, which means that the content inside Drawer will not impact the initial render performance, therefore any DOM operation should be performed through `ref` or after `open` event emitted. + ::: :::tip + Drawer provides an API called `destroyOnClose`, which is a flag variable that indicates should destroy the children content inside Drawer after Drawer was closed. You can use this API when you need your `mounted` life cycle to be called every time the Drawer opens. + ::: :::tip + If the variable bound to `visible` is managed in Vuex store, the `.sync` can not work properly. In this case, please remove the `.sync` modifier, listen to `open` and `close` events of Dialog, and commit Vuex mutations to update the value of that variable in the event handlers. + ::: ### Drawer Attributes + | Parameter| Description | Type | Acceptable Values | Defaults | |---------- |-------------- |---------- |-------------------------------- |-------- | | append-to-body | Controls should Drawer be inserted to DocumentBody Element, nested Drawer must assign this param to **true**| boolean | — | false | @@ -226,6 +240,7 @@ If the variable bound to `visible` is managed in Vuex store, the `.sync` can not | wrapperClosable | Indicates whether user can close Drawer by clicking the shadowing layer. | boolean | - | true | ### Drawer Slot + | Name | Description | |------|--------| | — | Drawer's Content | @@ -238,6 +253,7 @@ If the variable bound to `visible` is managed in Vuex store, the `.sync` can not | closeDrawer | In order to close Drawer, this method will call `before-close`. | ### Drawer Events + | Event Name | Description | Parameter | |---------- |-------- |---------- | | open | Triggered before Drawer opening animation begins | — | diff --git a/examples/docs/es/drawer.md b/examples/docs/es/drawer.md index e9fbe243f74..d52ac42419f 100644 --- a/examples/docs/es/drawer.md +++ b/examples/docs/es/drawer.md @@ -1,9 +1,13 @@ ## Drawer + Sometimes, `Dialog` does not always satisfy our requirements, let's say you have a massive form, or you need space to display something like `terms & conditions`, `Drawer` has almost identical API with `Dialog`, but it introduces different user experience. + ### Basic Usage + Callout a temporary drawer, from multiple direction :::demo You must set `visible` for `Drawer` like `Dialog` does to control the visibility of `Drawer` itself, it's `boolean` type. `Drawer` has to parts: `title` & `body`, the `title` is a named slot, you can also set the title through attribute named `title`, default to an empty string, the `body` part is the main area of `Drawer`, which contains user defined content. When opening, `Drawer` expand itself from the **right corner to left** which size is **30%** of the browser window by default. You can change that default behavior by setting `direction` and `size` attribute. This show case also demonstrated how to use the `before-close` API, check the Attribute section for more detail + ```html left to right @@ -47,9 +51,11 @@ Callout a temporary drawer, from multiple direction ::: ### Customization Content + Like `Dialog`, `Drawer` can do many diverse interaction as you wanted. :::demo + ```html Open Drawer with nested table Open Drawer with nested form @@ -148,6 +154,7 @@ export default { ::: ### Nested Drawer + You can also have multiple layer of `Drawer` just like `Dialog`. :::demo If you need multiple Drawer in different layer, you must set the `append-to-body` attribute to **true** @@ -197,18 +204,25 @@ You can also have multiple layer of `Drawer` just like `Dialog`. ::: :::tip + The content inside Drawer should be lazy rendered, which means that the content inside Drawer will not impact the initial render performance, therefore any DOM operation should be performed through `ref` or after `open` event emitted. + ::: :::tip + Drawer provides an API called `destroyOnClose`, which is a flag variable that indicates should destroy the children content inside Drawer after Drawer was closed. You can use this API when you need your `mounted` life cycle to be called every time the Drawer opens. + ::: :::tip + If the variable bound to `visible` is managed in Vuex store, the `.sync` can not work properly. In this case, please remove the `.sync` modifier, listen to `open` and `close` events of Dialog, and commit Vuex mutations to update the value of that variable in the event handlers. + ::: ### Drawer Attributes + | Parameter| Description | Type | Acceptable Values | Defaults | |---------- |-------------- |---------- |-------------------------------- |-------- | | append-to-body | Controls should Drawer be inserted to DocumentBody Element, nested Drawer must assign this param to **true**| boolean | — | false | @@ -226,6 +240,7 @@ If the variable bound to `visible` is managed in Vuex store, the `.sync` can not | wrapperClosable | Indicates whether user can close Drawer by clicking the shadowing layer. | boolean | - | true | ### Drawer Slot + | Name | Description | |------|--------| | — | Drawer's Content | @@ -238,6 +253,7 @@ If the variable bound to `visible` is managed in Vuex store, the `.sync` can not | closeDrawer | In order to close Drawer, this method will call `before-close`. | ### Drawer Events + | Event Name | Description | Parameter | |---------- |-------- |---------- | | open | Triggered before Drawer opening animation begins | — | diff --git a/examples/docs/fr-FR/drawer.md b/examples/docs/fr-FR/drawer.md index e9fbe243f74..d52ac42419f 100644 --- a/examples/docs/fr-FR/drawer.md +++ b/examples/docs/fr-FR/drawer.md @@ -1,9 +1,13 @@ ## Drawer + Sometimes, `Dialog` does not always satisfy our requirements, let's say you have a massive form, or you need space to display something like `terms & conditions`, `Drawer` has almost identical API with `Dialog`, but it introduces different user experience. + ### Basic Usage + Callout a temporary drawer, from multiple direction :::demo You must set `visible` for `Drawer` like `Dialog` does to control the visibility of `Drawer` itself, it's `boolean` type. `Drawer` has to parts: `title` & `body`, the `title` is a named slot, you can also set the title through attribute named `title`, default to an empty string, the `body` part is the main area of `Drawer`, which contains user defined content. When opening, `Drawer` expand itself from the **right corner to left** which size is **30%** of the browser window by default. You can change that default behavior by setting `direction` and `size` attribute. This show case also demonstrated how to use the `before-close` API, check the Attribute section for more detail + ```html left to right @@ -47,9 +51,11 @@ Callout a temporary drawer, from multiple direction ::: ### Customization Content + Like `Dialog`, `Drawer` can do many diverse interaction as you wanted. :::demo + ```html Open Drawer with nested table Open Drawer with nested form @@ -148,6 +154,7 @@ export default { ::: ### Nested Drawer + You can also have multiple layer of `Drawer` just like `Dialog`. :::demo If you need multiple Drawer in different layer, you must set the `append-to-body` attribute to **true** @@ -197,18 +204,25 @@ You can also have multiple layer of `Drawer` just like `Dialog`. ::: :::tip + The content inside Drawer should be lazy rendered, which means that the content inside Drawer will not impact the initial render performance, therefore any DOM operation should be performed through `ref` or after `open` event emitted. + ::: :::tip + Drawer provides an API called `destroyOnClose`, which is a flag variable that indicates should destroy the children content inside Drawer after Drawer was closed. You can use this API when you need your `mounted` life cycle to be called every time the Drawer opens. + ::: :::tip + If the variable bound to `visible` is managed in Vuex store, the `.sync` can not work properly. In this case, please remove the `.sync` modifier, listen to `open` and `close` events of Dialog, and commit Vuex mutations to update the value of that variable in the event handlers. + ::: ### Drawer Attributes + | Parameter| Description | Type | Acceptable Values | Defaults | |---------- |-------------- |---------- |-------------------------------- |-------- | | append-to-body | Controls should Drawer be inserted to DocumentBody Element, nested Drawer must assign this param to **true**| boolean | — | false | @@ -226,6 +240,7 @@ If the variable bound to `visible` is managed in Vuex store, the `.sync` can not | wrapperClosable | Indicates whether user can close Drawer by clicking the shadowing layer. | boolean | - | true | ### Drawer Slot + | Name | Description | |------|--------| | — | Drawer's Content | @@ -238,6 +253,7 @@ If the variable bound to `visible` is managed in Vuex store, the `.sync` can not | closeDrawer | In order to close Drawer, this method will call `before-close`. | ### Drawer Events + | Event Name | Description | Parameter | |---------- |-------- |---------- | | open | Triggered before Drawer opening animation begins | — | diff --git a/examples/docs/zh-CN/drawer.md b/examples/docs/zh-CN/drawer.md index b075c1b4b52..c211c7f159b 100644 --- a/examples/docs/zh-CN/drawer.md +++ b/examples/docs/zh-CN/drawer.md @@ -1,9 +1,13 @@ ## Drawer 抽屉 + 有些时候, `Dialog` 组件并不满足我们的需求, 比如你的表单很长, 亦或是你需要临时展示一些文档, `Drawer` 拥有和 `Dialog` 几乎相同的 API, 在 UI 上带来不一样的体验. + ### 基本用法 + 呼出一个临时的侧边栏, 可以从多个方向呼出 :::demo 需要设置 `visible` 属性,它的**类型**是 `boolean`,当为 **true** 时显示 Drawer。Drawer 分为两个部分:`title` 和 `body`,`title` 需要具名为 **title** 的 `slot`, 也可以通过 `title` 属性来定义,默认值为空。需要注意的是, Drawer 默认是从右往左打开, 当然可以设置对应的 `direction`, 详细请参考 `direction` 用法 最后,本例还展示了 `before-close` 的用法 + ```html 从左往右开 @@ -47,9 +51,11 @@ ::: ### 自定义内容 + 和 `Dialog` 组件一样, `Drawer` 同样可以在其内部嵌套各种丰富的操作 :::demo + ```html 打开嵌套表格的 Drawer 打开嵌套 Form 的 Drawer @@ -148,7 +154,9 @@ export default { ::: ### 多层嵌套 + `Drawer` 组件也拥有多层嵌套的方法 + :::demo 同样, 如果你需要嵌套多层 `Drawer` 请一定要设置 `append-to-body` 属性为 **true** ```html @@ -197,18 +205,25 @@ export default { ::: :::tip + Drawer 的内容是懒渲染的,即在第一次被打开之前,传入的默认 slot 不会被渲染到 DOM 上。因此,如果需要执行 DOM 操作,或通过 `ref` 获取相应组件,请在 `open` 事件回调中进行。 + ::: :::tip + Drawer 提供一个 `destroyOnClose` API, 用来在关闭 Drawer 时销毁子组件内容, 例如清理表单内的状态, 在必要时可以将该属性设置为 **true** 用来保证初始状态的一致性 + ::: :::tip + 如果 `visible` 属性绑定的变量位于 Vuex 的 store 内,那么 `.sync` 不会正常工作。此时需要去除 `.sync` 修饰符,同时监听 Drawer 的 `open` 和 `close` 事件,在事件回调中执行 Vuex 中对应的 mutation 更新 `visible` 属性绑定的变量的值。 + ::: ### Drawer Attributes + | 参数 | 说明 | 类型 | 可选值 | 默认值 | |---------- |-------------- |---------- |-------------------------------- |-------- | | append-to-body | Drawer 自身是否插入至 body 元素上。嵌套的 Drawer 必须指定该属性并赋值为 true | boolean | — | false | @@ -226,6 +241,7 @@ Drawer 提供一个 `destroyOnClose` API, 用来在关闭 Drawer 时销毁子组 | wrapperClosable | 点击遮罩层是否可以关闭 Drawer | boolean | - | true | ### Drawer Slot + | name | 说明 | |------|--------| | — | Drawer 的内容 | @@ -238,6 +254,7 @@ Drawer 提供一个 `destroyOnClose` API, 用来在关闭 Drawer 时销毁子组 | closeDrawer | 用于关闭 Drawer, 该方法会调用传入的 `before-close` 方法 | ### Drawer Events + | 事件名称 | 说明 | 回调参数 | |---------- |-------- |---------- | | open | Drawer 打开的回调 | — |