Commit 841cb1fe67c9b6143a89d30f8c51ef0f4264e57d

Authored by Aresn
1 parent 75c32564

Menu support transition fixed #514

examples/routers/form.vue
... ... @@ -2,12 +2,7 @@
2 2 <div style="width: 300px;">
3 3 <i-form ref="formValidate" :model="formValidate" :rules="ruleValidate" :label-width="80">
4 4 <Form-item label="爱好" prop="interest">
5   - <Checkbox-group v-model="formValidate.interest">
6   - <Checkbox label="吃饭"></Checkbox>
7   - <Checkbox label="睡觉"></Checkbox>
8   - <Checkbox label="跑步"></Checkbox>
9   - <Checkbox label="看电影"></Checkbox>
10   - </Checkbox-group>
  5 + <Input v-model="formValidate.interest" number></Input>
11 6 </Form-item>
12 7 <Form-item>
13 8 <i-button type="primary" @click="handleSubmit('formValidate')">提交</i-button>
... ... @@ -21,12 +16,15 @@
21 16 data () {
22 17 return {
23 18 formValidate: {
24   - interest: ['吃饭', '跑步']
  19 + interest: ''
25 20 },
26 21 ruleValidate: {
27 22 interest: [
28   - { required: true, type: 'array', min: 1, message: '至少选择一个爱好', trigger: 'change' },
29   - { type: 'array', max: 2, message: '最多选择两个爱好', trigger: 'change' }
  23 + {
  24 + required: true,
  25 + type: 'number',
  26 + trigger: 'change'
  27 + }
30 28 ]
31 29 }
32 30 }
... ...
examples/routers/menu.vue
1 1 <template>
2 2 <div>
3   - <Menu mode="horizontal" :theme="theme1" @on-select="s">
4   - <Row type="flex" justify="center" align="middle">
5   - <i-col span="12">
6   - <Menu-item name="1">
  3 + <Row>
  4 + <i-col span="8">
  5 + <Menu :theme="theme2">
  6 + <Submenu name="1">
  7 + <template slot="title">
7 8 <Icon type="ios-paper"></Icon>
8 9 内容管理
9   - </Menu-item>
10   - <Menu-item name="2">
  10 + </template>
  11 + <Menu-item name="1-1">文章管理</Menu-item>
  12 + <Menu-item name="1-2">评论管理</Menu-item>
  13 + <Menu-item name="1-3">举报管理</Menu-item>
  14 + </Submenu>
  15 + <Submenu name="2">
  16 + <template slot="title">
11 17 <Icon type="ios-people"></Icon>
12 18 用户管理
13   - </Menu-item>
14   - <Submenu name="3">
15   - <template slot="title">
16   - <Icon type="stats-bars"></Icon>
17   - 统计分析
18   - </template>
19   - <Menu-group title="使用">
20   - <Menu-item name="3-1">新增和启动</Menu-item>
21   - <Menu-item name="3-2">活跃分析</Menu-item>
22   - <Menu-item name="3-3">时段分析</Menu-item>
23   - </Menu-group>
24   - <Menu-group title="留存">
25   - <Menu-item name="3-4">用户留存</Menu-item>
26   - <Menu-item name="3-5">流失用户</Menu-item>
27   - </Menu-group>
28   - </Submenu>
29   - <Menu-item name="4">
30   - <Icon type="settings"></Icon>
31   - 综合设置
32   - </Menu-item>
33   - </i-col>
34   - </Row>
35   - </Menu>
  19 + </template>
  20 + <Menu-item name="2-1">新增用户</Menu-item>
  21 + <Menu-item name="2-2">活跃用户</Menu-item>
  22 + </Submenu>
  23 + <Submenu name="3">
  24 + <template slot="title">
  25 + <Icon type="stats-bars"></Icon>
  26 + 统计分析
  27 + </template>
  28 + <Menu-group title="使用">
  29 + <Menu-item name="3-1">新增和启动</Menu-item>
  30 + <Menu-item name="3-2">活跃分析</Menu-item>
  31 + <Menu-item name="3-3">时段分析</Menu-item>
  32 + </Menu-group>
  33 + <Menu-group title="留存">
  34 + <Menu-item name="3-4">用户留存</Menu-item>
  35 + <Menu-item name="3-5">流失用户</Menu-item>
  36 + </Menu-group>
  37 + </Submenu>
  38 + </Menu>
  39 + </i-col>
  40 + </Row>
36 41 <br>
37 42 <p>切换主题</p>
38   - <Radio-group v-model="theme1">
  43 + <Radio-group v-model="theme2">
39 44 <Radio label="light"></Radio>
40 45 <Radio label="dark"></Radio>
41   - <Radio label="primary"></Radio>
42 46 </Radio-group>
43 47 </div>
44 48 </template>
... ... @@ -46,149 +50,8 @@
46 50 export default {
47 51 data () {
48 52 return {
49   - theme1: 'light'
50   - }
51   - },
52   - methods: {
53   - s (s) {
54   - console.log(s)
  53 + theme2: 'light'
55 54 }
56 55 }
57 56 }
58 57 </script>
59   -
60   -
61   -<!--<template>-->
62   - <!--<div>-->
63   - <!--<Row>-->
64   - <!--<i-col span="8">-->
65   - <!--<Menu :theme="theme2" @on-select="s">-->
66   - <!--<Submenu name="1">-->
67   - <!--<template slot="title">-->
68   - <!--<Icon type="ios-paper"></Icon>-->
69   - <!--内容管理-->
70   - <!--</template>-->
71   - <!--<Menu-item name="1-1">文章管理</Menu-item>-->
72   - <!--<Menu-item name="1-2">评论管理</Menu-item>-->
73   - <!--<Menu-item name="1-3">举报管理</Menu-item>-->
74   - <!--</Submenu>-->
75   - <!--<Submenu name="2">-->
76   - <!--<template slot="title">-->
77   - <!--<Icon type="ios-people"></Icon>-->
78   - <!--用户管理-->
79   - <!--</template>-->
80   - <!--<Menu-item name="2-1">新增用户</Menu-item>-->
81   - <!--<Menu-item name="2-2">活跃用户</Menu-item>-->
82   - <!--</Submenu>-->
83   - <!--<Submenu name="3">-->
84   - <!--<template slot="title">-->
85   - <!--<Icon type="stats-bars"></Icon>-->
86   - <!--统计分析-->
87   - <!--</template>-->
88   - <!--<Menu-group title="使用">-->
89   - <!--<Menu-item name="3-1">新增和启动</Menu-item>-->
90   - <!--<Menu-item name="3-2">活跃分析</Menu-item>-->
91   - <!--<Menu-item name="3-3">时段分析</Menu-item>-->
92   - <!--</Menu-group>-->
93   - <!--<Menu-group title="留存">-->
94   - <!--<Menu-item name="3-4">用户留存</Menu-item>-->
95   - <!--<Menu-item name="3-5">流失用户</Menu-item>-->
96   - <!--</Menu-group>-->
97   - <!--</Submenu>-->
98   - <!--</Menu>-->
99   - <!--</i-col>-->
100   - <!--<i-col span="8">-->
101   - <!--<Menu :theme="theme2" active-name="1-2" :open-names="['1']" @on-select="s">-->
102   - <!--<Submenu name="1">-->
103   - <!--<template slot="title">-->
104   - <!--<Icon type="ios-paper"></Icon>-->
105   - <!--内容管理-->
106   - <!--</template>-->
107   - <!--<Menu-item name="1-1">文章管理</Menu-item>-->
108   - <!--<Menu-item name="1-2">评论管理</Menu-item>-->
109   - <!--<Menu-item name="1-3">举报管理</Menu-item>-->
110   - <!--</Submenu>-->
111   - <!--<Submenu name="2">-->
112   - <!--<template slot="title">-->
113   - <!--<Icon type="ios-people"></Icon>-->
114   - <!--用户管理-->
115   - <!--</template>-->
116   - <!--<Menu-item name="2-1">新增用户</Menu-item>-->
117   - <!--<Menu-item name="2-2">活跃用户</Menu-item>-->
118   - <!--</Submenu>-->
119   - <!--<Submenu name="3">-->
120   - <!--<template slot="title">-->
121   - <!--<Icon type="stats-bars"></Icon>-->
122   - <!--统计分析-->
123   - <!--</template>-->
124   - <!--<Menu-group title="使用">-->
125   - <!--<Menu-item name="3-1">新增和启动</Menu-item>-->
126   - <!--<Menu-item name="3-2">活跃分析</Menu-item>-->
127   - <!--<Menu-item name="3-3">时段分析</Menu-item>-->
128   - <!--</Menu-group>-->
129   - <!--<Menu-group title="留存">-->
130   - <!--<Menu-item name="3-4">用户留存</Menu-item>-->
131   - <!--<Menu-item name="3-5">流失用户</Menu-item>-->
132   - <!--</Menu-group>-->
133   - <!--</Submenu>-->
134   - <!--</Menu>-->
135   - <!--</i-col>-->
136   - <!--<i-col span="8">-->
137   - <!--<Menu :theme="theme2" :open-names="['1']" accordion @on-select="s">-->
138   - <!--<Submenu name="1">-->
139   - <!--<template slot="title">-->
140   - <!--<Icon type="ios-paper"></Icon>-->
141   - <!--内容管理-->
142   - <!--</template>-->
143   - <!--<Menu-item name="1-1">文章管理</Menu-item>-->
144   - <!--<Menu-item name="1-2">评论管理</Menu-item>-->
145   - <!--<Menu-item name="1-3">举报管理</Menu-item>-->
146   - <!--</Submenu>-->
147   - <!--<Submenu name="2">-->
148   - <!--<template slot="title">-->
149   - <!--<Icon type="ios-people"></Icon>-->
150   - <!--用户管理-->
151   - <!--</template>-->
152   - <!--<Menu-item name="2-1">新增用户</Menu-item>-->
153   - <!--<Menu-item name="2-2">活跃用户</Menu-item>-->
154   - <!--</Submenu>-->
155   - <!--<Submenu name="3">-->
156   - <!--<template slot="title">-->
157   - <!--<Icon type="stats-bars"></Icon>-->
158   - <!--统计分析-->
159   - <!--</template>-->
160   - <!--<Menu-group title="使用">-->
161   - <!--<Menu-item name="3-1">新增和启动</Menu-item>-->
162   - <!--<Menu-item name="3-2">活跃分析</Menu-item>-->
163   - <!--<Menu-item name="3-3">时段分析</Menu-item>-->
164   - <!--</Menu-group>-->
165   - <!--<Menu-group title="留存">-->
166   - <!--<Menu-item name="3-4">用户留存</Menu-item>-->
167   - <!--<Menu-item name="3-5">流失用户</Menu-item>-->
168   - <!--</Menu-group>-->
169   - <!--</Submenu>-->
170   - <!--</Menu>-->
171   - <!--</i-col>-->
172   - <!--</Row>-->
173   - <!--<br>-->
174   - <!--<p>切换主题</p>-->
175   - <!--<Radio-group v-model="theme2">-->
176   - <!--<Radio label="light"></Radio>-->
177   - <!--<Radio label="dark"></Radio>-->
178   - <!--</Radio-group>-->
179   - <!--</div>-->
180   -<!--</template>-->
181   -<!--<script>-->
182   - <!--export default {-->
183   - <!--data () {-->
184   - <!--return {-->
185   - <!--theme2: 'light'-->
186   - <!--}-->
187   - <!--},-->
188   - <!--methods: {-->
189   - <!--s (s) {-->
190   - <!--console.log(s);-->
191   - <!--}-->
192   - <!--}-->
193   - <!--}-->
194   -<!--</script>-->
... ...
src/components/base/collapse-transition.js 0 → 100644
  1 +// Thanks to https://github.com/ElemeFE/element/blob/dev/src/transitions/collapse-transition.js
  2 +
  3 +import { addClass, removeClass } from '../../utils/assist';
  4 +
  5 +const Transition = {
  6 + beforeEnter(el) {
  7 + addClass(el, 'collapse-transition');
  8 + if (!el.dataset) el.dataset = {};
  9 +
  10 + el.dataset.oldPaddingTop = el.style.paddingTop;
  11 + el.dataset.oldPaddingBottom = el.style.paddingBottom;
  12 +
  13 + el.style.height = '0';
  14 + el.style.paddingTop = 0;
  15 + el.style.paddingBottom = 0;
  16 + },
  17 +
  18 + enter(el) {
  19 + el.dataset.oldOverflow = el.style.overflow;
  20 + if (el.scrollHeight !== 0) {
  21 + el.style.height = el.scrollHeight + 'px';
  22 + el.style.paddingTop = el.dataset.oldPaddingTop;
  23 + el.style.paddingBottom = el.dataset.oldPaddingBottom;
  24 + } else {
  25 + el.style.height = '';
  26 + el.style.paddingTop = el.dataset.oldPaddingTop;
  27 + el.style.paddingBottom = el.dataset.oldPaddingBottom;
  28 + }
  29 +
  30 + el.style.overflow = 'hidden';
  31 + },
  32 +
  33 + afterEnter(el) {
  34 + // for safari: remove class then reset height is necessary
  35 + removeClass(el, 'collapse-transition');
  36 + el.style.height = '';
  37 + el.style.overflow = el.dataset.oldOverflow;
  38 + },
  39 +
  40 + beforeLeave(el) {
  41 + if (!el.dataset) el.dataset = {};
  42 + el.dataset.oldPaddingTop = el.style.paddingTop;
  43 + el.dataset.oldPaddingBottom = el.style.paddingBottom;
  44 + el.dataset.oldOverflow = el.style.overflow;
  45 +
  46 + el.style.height = el.scrollHeight + 'px';
  47 + el.style.overflow = 'hidden';
  48 + },
  49 +
  50 + leave(el) {
  51 + if (el.scrollHeight !== 0) {
  52 + // for safari: add class after set height, or it will jump to zero height suddenly, weired
  53 + addClass(el, 'collapse-transition');
  54 + el.style.height = 0;
  55 + el.style.paddingTop = 0;
  56 + el.style.paddingBottom = 0;
  57 + }
  58 + },
  59 +
  60 + afterLeave(el) {
  61 + removeClass(el, 'collapse-transition');
  62 + el.style.height = '';
  63 + el.style.overflow = el.dataset.oldOverflow;
  64 + el.style.paddingTop = el.dataset.oldPaddingTop;
  65 + el.style.paddingBottom = el.dataset.oldPaddingBottom;
  66 + }
  67 +};
  68 +
  69 +export default {
  70 + name: 'CollapseTransition',
  71 + functional: true,
  72 + render(h, { children }) {
  73 + const data = {
  74 + on: Transition
  75 + };
  76 +
  77 + return h('transition', data, children);
  78 + }
  79 +};
... ...
src/components/menu/submenu.vue
... ... @@ -4,7 +4,9 @@
4 4 <slot name="title"></slot>
5 5 <Icon type="ios-arrow-down" :class="[prefixCls + '-submenu-title-icon']"></Icon>
6 6 </div>
7   - <ul :class="[prefixCls]" v-if="mode === 'vertical'" v-show="opened"><slot></slot></ul>
  7 + <collapse-transition v-if="mode === 'vertical'">
  8 + <ul :class="[prefixCls]" v-show="opened"><slot></slot></ul>
  9 + </collapse-transition>
8 10 <transition name="slide-up" v-else>
9 11 <Drop
10 12 v-show="opened"
... ... @@ -17,6 +19,7 @@
17 19 <script>
18 20 import Drop from '../select/dropdown.vue';
19 21 import Icon from '../icon/icon.vue';
  22 + import CollapseTransition from '../base/collapse-transition';
20 23 import { getStyle, findComponentUpward } from '../../utils/assist';
21 24 import Emitter from '../../mixins/emitter';
22 25  
... ... @@ -25,7 +28,7 @@
25 28 export default {
26 29 name: 'Submenu',
27 30 mixins: [ Emitter ],
28   - components: { Icon, Drop },
  31 + components: { Icon, Drop, CollapseTransition },
29 32 props: {
30 33 name: {
31 34 type: [String, Number],
... ...
src/styles/animation/index.less
... ... @@ -25,4 +25,8 @@
25 25 @import "fade";
26 26 @import "move";
27 27 @import "ease";
28   -@import "slide";
29 28 \ No newline at end of file
  29 +@import "slide";
  30 +
  31 +.collapse-transition {
  32 + transition: @transition-time height ease-in-out, @transition-time padding-top ease-in-out, @transition-time padding-bottom ease-in-out;
  33 +}
30 34 \ No newline at end of file
... ...
src/utils/assist.js
... ... @@ -232,4 +232,66 @@ function findComponentsDownward (context, componentName, components = []) {
232 232 }
233 233 return components;
234 234 }
235   -export {findComponentsDownward};
236 235 \ No newline at end of file
  236 +export {findComponentsDownward};
  237 +
  238 +/* istanbul ignore next */
  239 +const trim = function(string) {
  240 + return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '');
  241 +};
  242 +
  243 +/* istanbul ignore next */
  244 +export function hasClass(el, cls) {
  245 + if (!el || !cls) return false;
  246 + if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.');
  247 + if (el.classList) {
  248 + return el.classList.contains(cls);
  249 + } else {
  250 + return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1;
  251 + }
  252 +}
  253 +
  254 +/* istanbul ignore next */
  255 +export function addClass(el, cls) {
  256 + if (!el) return;
  257 + let curClass = el.className;
  258 + const classes = (cls || '').split(' ');
  259 +
  260 + for (let i = 0, j = classes.length; i < j; i++) {
  261 + const clsName = classes[i];
  262 + if (!clsName) continue;
  263 +
  264 + if (el.classList) {
  265 + el.classList.add(clsName);
  266 + } else {
  267 + if (!hasClass(el, clsName)) {
  268 + curClass += ' ' + clsName;
  269 + }
  270 + }
  271 + }
  272 + if (!el.classList) {
  273 + el.className = curClass;
  274 + }
  275 +}
  276 +
  277 +/* istanbul ignore next */
  278 +export function removeClass(el, cls) {
  279 + if (!el || !cls) return;
  280 + const classes = cls.split(' ');
  281 + let curClass = ' ' + el.className + ' ';
  282 +
  283 + for (let i = 0, j = classes.length; i < j; i++) {
  284 + const clsName = classes[i];
  285 + if (!clsName) continue;
  286 +
  287 + if (el.classList) {
  288 + el.classList.remove(clsName);
  289 + } else {
  290 + if (hasClass(el, clsName)) {
  291 + curClass = curClass.replace(' ' + clsName + ' ', ' ');
  292 + }
  293 + }
  294 + }
  295 + if (!el.classList) {
  296 + el.className = trim(curClass);
  297 + }
  298 +}
237 299 \ No newline at end of file
... ...