Commit 2de2fc0ad0001f45b93bd7513c1bce8298367101

Authored by ly525
1 parent e181c274

refactor: merge props config to props

front-end/h5/src/components/core/editor/edit-panel/props.js
1 1 import { mapState, mapActions } from 'vuex'
  2 +import { getVM } from '../../../../utils/element'
2 3  
3 4 export default {
4 5 props: {
... ... @@ -25,7 +26,9 @@ export default {
25 26 }
26 27 },
27 28 renderPropsEditorPanel (h, editingElement) {
28   - const propsConfig = this.editingElementEditorConfig.propsConfig
  29 + const vm = getVM(editingElement.name)
  30 + const props = vm.$options.props
  31 +
29 32 return (
30 33 <a-form
31 34 ref="form"
... ... @@ -34,48 +37,51 @@ export default {
34 37 layout={this.layout}
35 38 >
36 39 {
37   - Object.keys(propsConfig).map(propKey => {
38   - const item = propsConfig[propKey]
39   - // https://vuejs.org/v2/guide/render-function.html
40   - const data = {
41   - style: { width: '100%' },
42   - props: {
43   - ...item.prop || {},
44   - // https://vuejs.org/v2/guide/render-function.html#v-model
  40 + Object
  41 + .entries(props)
  42 + .filter(([propKey, obj]) => obj.editor)
  43 + .map(([propKey, obj]) => {
  44 + const item = obj.editor
  45 + // https://vuejs.org/v2/guide/render-function.html
  46 + const data = {
  47 + style: { width: '100%' },
  48 + props: {
  49 + ...item.prop || {},
  50 + // https://vuejs.org/v2/guide/render-function.html#v-model
45 51  
46   - // #!zh:不设置默认值的原因(下一行的代码,注释的代码):
47   - // 比如表单 input,如果用户手动删除了 placeholder的内容,程序会用defaultPropValue填充,
48   - // 表现在UI上就是:用户永远无法彻底删掉默认值(必须保留至少一个字符)
49   - // value: editingElement.pluginProps[propKey] || item.defaultPropValue
50   - value: editingElement.pluginProps[propKey]
51   - },
52   - on: {
  52 + // #!zh:不设置默认值的原因(下一行的代码,注释的代码):
  53 + // 比如表单 input,如果用户手动删除了 placeholder的内容,程序会用defaultPropValue填充,
  54 + // 表现在UI上就是:用户永远无法彻底删掉默认值(必须保留至少一个字符)
  55 + // value: editingElement.pluginProps[propKey] || item.defaultPropValue
  56 + value: editingElement.pluginProps[propKey]
  57 + },
  58 + on: {
53 59 // https://vuejs.org/v2/guide/render-function.html#v-model
54 60 // input (e) {
55 61 // editingElement.pluginProps[propKey] = e.target ? e.target.value : e
56 62 // }
57   - change (e) {
  63 + change (e) {
58 64 // TODO fixme: update plugin props in vuex with dispatch
59   - editingElement.pluginProps[propKey] = e.target ? e.target.value : e
  65 + editingElement.pluginProps[propKey] = e.target ? e.target.value : e
  66 + }
60 67 }
61 68 }
62   - }
63   - const formItemLayout = this.layout === 'horizontal' ? {
64   - labelCol: { span: 6 }, wrapperCol: { span: 16, offset: 2 }
65   - } : {}
66   - const formItemData = {
67   - props: {
68   - ...formItemLayout,
69   - label: item.label
  69 + const formItemLayout = this.layout === 'horizontal' ? {
  70 + labelCol: { span: 6 }, wrapperCol: { span: 16, offset: 2 }
  71 + } : {}
  72 + const formItemData = {
  73 + props: {
  74 + ...formItemLayout,
  75 + label: item.label
  76 + }
70 77 }
71   - }
72   - return (
73   - <a-form-item {...formItemData}>
74   - { item.extra && <div slot="extra">{typeof item.extra === 'function' ? item.extra(h) : item.extra}</div>}
75   - { h(item.type, data) }
76   - </a-form-item>
77   - )
78   - })
  78 + return (
  79 + <a-form-item {...formItemData}>
  80 + { item.extra && <div slot="extra">{typeof item.extra === 'function' ? item.extra(h) : item.extra}</div>}
  81 + { h(item.type, data) }
  82 + </a-form-item>
  83 + )
  84 + })
79 85 }
80 86 </a-form>
81 87 )
... ...
front-end/h5/src/components/core/editor/index.js
1 1 import { mapState, mapActions } from 'vuex'
2 2 import undoRedoHistory from '../../../store/plugins/undo-redo/History'
3   -import { getEditorConfigForEditingElement } from '../../../utils/element'
4 3  
5 4 import '../styles/index.scss'
6 5 import 'animate.css'
... ... @@ -139,11 +138,9 @@ export default {
139 138 * pluginInfo {Object}: 插件列表中的基础数据, {name}=pluginInfo
140 139 */
141 140 clone ({ name }) {
142   - // const zindex = this.elements.length + 1
143   - const editorConfig = getEditorConfigForEditingElement(name)
144 141 this.elementManager({
145 142 type: 'add',
146   - value: { name, editorConfig }
  143 + value: { name }
147 144 })
148 145 },
149 146 _renderMenuContent () {
... ...
front-end/h5/src/components/core/models/element.js
... ... @@ -37,20 +37,34 @@ class Element {
37 37 this.animations = ele.animations || []
38 38 }
39 39  
40   - getDefaultPluginProps (editorConfig) {
41   - // init prop of plugin
42   - const propConf = editorConfig.propsConfig
  40 + // init prop of plugin
  41 + getDefaultPluginProps (propsConfig) {
43 42 const pluginProps = {}
44   - Object.keys(propConf).forEach(key => {
  43 + Object.keys(propsConfig).forEach(key => {
45 44 // #6
46 45 if (key === 'name') {
47 46 console.warn('Please do not use {name} as plugin prop')
48 47 return
49 48 }
50   - pluginProps[key] = propConf[key].defaultPropValue
  49 + const defaultValue = propsConfig[key].default
  50 + pluginProps[key] = typeof defaultValue === 'function' ? defaultValue() : defaultValue
51 51 })
52 52 return pluginProps
53 53 }
  54 + // getDefaultPluginProps (editorConfig) {
  55 + // // init prop of plugin
  56 + // const propConf = editorConfig.propsConfig
  57 + // const pluginProps = {}
  58 + // Object.keys(propConf).forEach(key => {
  59 + // // #6
  60 + // if (key === 'name') {
  61 + // console.warn('Please do not use {name} as plugin prop')
  62 + // return
  63 + // }
  64 + // pluginProps[key] = propConf[key].defaultPropValue
  65 + // })
  66 + // return pluginProps
  67 + // }
54 68  
55 69 getStyle ({ position = 'static', isRem = false } = {}) {
56 70 if (this.name === 'lbp-background') {
... ...
front-end/h5/src/components/plugins/common/props.js
... ... @@ -7,10 +7,15 @@ export default {
7 7 type: String,
8 8 default: 'radio'
9 9 },
10   - placeholder: {
11   - type: String,
12   - default: '请填写提示文字'
13   - },
  10 + // placeholder: {
  11 + // type: String,
  12 + // default: '请填写提示文字',
  13 + // editor: {
  14 + // type: 'a-input',
  15 + // label: '提示文字',
  16 + // require: true
  17 + // }
  18 + // },
14 19 required: {
15 20 type: Boolean,
16 21 default: false
... ... @@ -21,34 +26,104 @@ export default {
21 26 },
22 27 backgroundColor: {
23 28 type: String,
24   - default: 'transparent'
  29 + default: 'transparent',
  30 + editor: {
  31 + type: 'a-input', // lbs-color-picker
  32 + label: '背景颜色',
  33 + prop: {
  34 + type: 'color'
  35 + },
  36 + require: true
  37 + }
25 38 },
26 39 color: {
27 40 type: String,
28   - default: 'black'
  41 + default: 'black',
  42 + editor: {
  43 + type: 'a-input',
  44 + label: '文字颜色',
  45 + // !#zh 为编辑组件指定 prop
  46 + prop: {
  47 + type: 'color'
  48 + },
  49 + require: true
  50 + }
29 51 },
30 52 fontSize: {
31 53 type: Number,
32   - default: 14
  54 + default: 14,
  55 + editor: {
  56 + type: 'a-input-number',
  57 + label: '字号(px)',
  58 + require: true,
  59 + prop: {
  60 + step: 1,
  61 + min: 12,
  62 + max: 144
  63 + }
  64 + }
33 65 },
34 66 lineHeight: {
35 67 type: Number,
36   - default: 1
  68 + default: 1,
  69 + editor: {
  70 + type: 'a-input-number',
  71 + label: '行高',
  72 + require: true,
  73 + prop: {
  74 + step: 0.1,
  75 + min: 0.1,
  76 + max: 10
  77 + }
  78 + }
37 79 },
38 80 borderWidth: {
39 81 type: Number,
40   - default: 1
  82 + default: 1,
  83 + editor: {
  84 + type: 'a-input-number',
  85 + label: '边框宽度(px)',
  86 + require: true,
  87 + prop: {
  88 + step: 1,
  89 + min: 0,
  90 + max: 10
  91 + }
  92 + }
41 93 },
42 94 borderRadius: {
43 95 type: Number,
44   - default: 0
  96 + default: 0,
  97 + editor: {
  98 + type: 'a-input-number',
  99 + label: '圆角(px)',
  100 + require: true,
  101 + prop: {
  102 + step: 0.1,
  103 + min: 0,
  104 + max: 200
  105 + }
  106 + }
45 107 },
46 108 borderColor: {
47 109 type: String,
48   - default: '#ced4da'
  110 + default: '#ced4da',
  111 + editor: {
  112 + type: 'a-input', // lbs-color-picker
  113 + label: '边框颜色',
  114 + prop: {
  115 + type: 'color'
  116 + },
  117 + require: true
  118 + }
49 119 },
50 120 textAlign: {
51 121 type: String,
52   - default: 'center'
  122 + default: 'center',
  123 + editor: {
  124 + type: 'lbs-text-align',
  125 + label: '文字对齐',
  126 + require: true
  127 + }
53 128 }
54 129 }
... ...
front-end/h5/src/components/plugins/lbp-button.js
1 1 import LbpTextAlign from '@luban-h5/lbs-text-align'
  2 +import commonProps from './common/props.js'
2 3  
3 4 export default {
4 5 render () {
... ... @@ -32,18 +33,20 @@ export default {
32 33 },
33 34 name: 'lbp-button',
34 35 props: {
  36 + ...commonProps,
35 37 text: {
36 38 type: String,
37   - default: '按钮'
  39 + default: '按钮',
  40 + editor: {
  41 + type: 'a-input',
  42 + label: '按钮文字',
  43 + require: true
  44 + }
38 45 },
39 46 type: {
40 47 type: String,
41 48 default: 'text'
42 49 },
43   - placeholder: {
44   - type: String,
45   - default: '请填写提示文字'
46   - },
47 50 required: {
48 51 type: Boolean,
49 52 default: false
... ... @@ -51,149 +54,9 @@ export default {
51 54 disabled: {
52 55 type: Boolean,
53 56 default: false
54   - },
55   - backgroundColor: {
56   - type: String,
57   - default: 'transparent'
58   - },
59   - color: {
60   - type: String,
61   - default: 'black'
62   - },
63   - fontSize: {
64   - type: Number,
65   - default: 14
66   - },
67   - lineHeight: {
68   - type: Number,
69   - default: 1
70   - },
71   - borderWidth: {
72   - type: Number,
73   - default: 1
74   - },
75   - borderRadius: {
76   - type: Number,
77   - default: 0
78   - },
79   - borderColor: {
80   - type: String,
81   - default: '#ced4da'
82   - },
83   - textAlign: {
84   - type: String,
85   - default: 'center'
86 57 }
87 58 },
88 59 editorConfig: {
89   - propsConfig: {
90   - text: {
91   - type: 'a-input',
92   - label: '按钮文字',
93   - require: true,
94   - defaultPropValue: '按钮'
95   - },
96   - fontSize: {
97   - type: 'a-input-number',
98   - label: '字号(px)',
99   - require: true,
100   - prop: {
101   - step: 1,
102   - min: 12,
103   - max: 144
104   - },
105   - defaultPropValue: 14
106   - },
107   - color: {
108   - type: 'a-input',
109   - label: '文字颜色',
110   - // !#zh 为编辑组件指定 prop
111   - prop: {
112   - type: 'color'
113   - },
114   - require: true,
115   - defaultPropValue: 'black'
116   - },
117   - backgroundColor: {
118   - type: 'a-input', // lbs-color-picker
119   - label: '背景颜色',
120   - prop: {
121   - type: 'color'
122   - },
123   - require: true,
124   - defaultPropValue: '#ffffff' // TODO why logogram for color does't work?
125   - },
126   - borderColor: {
127   - type: 'a-input', // lbs-color-picker
128   - label: '边框颜色',
129   - prop: {
130   - type: 'color'
131   - },
132   - require: true,
133   - defaultPropValue: '#eeeeee'
134   - },
135   - borderWidth: {
136   - type: 'a-input-number',
137   - label: '边框宽度(px)',
138   - require: true,
139   - prop: {
140   - step: 1,
141   - min: 0,
142   - max: 10
143   - },
144   - defaultPropValue: 1
145   - },
146   - borderRadius: {
147   - type: 'a-input-number',
148   - label: '圆角(px)',
149   - require: true,
150   - prop: {
151   - step: 0.1,
152   - min: 0,
153   - max: 200
154   - },
155   - defaultPropValue: 0
156   - },
157   - lineHeight: {
158   - type: 'a-input-number',
159   - label: '行高',
160   - require: true,
161   - prop: {
162   - step: 0.1,
163   - min: 0.1,
164   - max: 10
165   - },
166   - defaultPropValue: 1
167   - },
168   - textAlign: {
169   - /**
170   - * #!en: you can also config type like below:
171   - * #!zh: 可以直接这样写:
172   - textAlign: {
173   - type: component(component definition json/自定义的组件,比如下面的 components[''lbs-text-align'])
174   - }
175   -
176   - * more explanation
177   - textAlign: {
178   - type: {
179   - render() {},
180   - props: {},
181   - methods: {},
182   - }
183   - }
184   - * #!en: reference: how to judge the tag is custom component or a HTML element in React or Vue?
185   - * !#zh:
186   - * 思路来源:
187   - * React 中 深入JSX 中,如何判断 h(tag) 中的 tag 是自定义组件还是普通 HTML 元素呢?React 是判断该 tag 是否为 function 来实现的
188   - * Vue 中的自定义组件 是一个普通的 JSON 对象,最后自定义组件被转换成了函数,输入是 JSON 输出是 函数,可以看看 Vue 中 createElement 也就是 h 的实现·
189   - * 参见:http://hcysun.me/2018/01/05/%E6%8E%A2%E7%B4%A2Vue%E9%AB%98%E9%98%B6%E7%BB%84%E4%BB%B6/
190   - */
191   - type: 'lbs-text-align',
192   - label: '文字对齐',
193   - require: true,
194   - defaultPropValue: 'center'
195   - }
196   - },
197 60 components: {
198 61 'lbs-text-align': LbpTextAlign
199 62 }
... ...
front-end/h5/src/mixins/load-plugins.js
1 1 import Vue from 'vue'
2   -import LbpButton from '@luban-h5/lbc-button'
3   -import LbpPicture from '../components/plugins/lbp-picture'
4   -import LbpVideo from '../components/plugins/lbp-video'
5   -import LbpText from '../components/plugins/lbp-text'
6   -import LbpFormInput from '../components/plugins/lbp-form-input'
7   -import LbpFormButton from '../components/plugins/lbp-form-button'
8   -import LbpFormRadioGroup from '../components/plugins/lbp-form-radio-group'
9   -import LbpFormCheckboxGroup from '../components/plugins/lbp-form-checkbox-group'
  2 +// import LbpButton from '@luban-h5/lbc-button'
  3 +import LbpButton from '../components/plugins/lbp-button'
  4 +// import LbpPicture from '../components/plugins/lbp-picture'
  5 +// import LbpVideo from '../components/plugins/lbp-video'
  6 +// import LbpText from '../components/plugins/lbp-text'
  7 +// import LbpFormInput from '../components/plugins/lbp-form-input'
  8 +// import LbpFormButton from '../components/plugins/lbp-form-button'
  9 +// import LbpFormRadioGroup from '../components/plugins/lbp-form-radio-group'
  10 +// import LbpFormCheckboxGroup from '../components/plugins/lbp-form-checkbox-group'
10 11 import LbpBackground from '../components/plugins/lbp-background'
11   -import LbpSlide from '../components/plugins/lbp-slide'
  12 +// import LbpSlide from '../components/plugins/lbp-slide'
12 13  
13 14 export const pluginsList = [
14   - {
15   - title: '图片',
16   - i18nTitle: {
17   - 'en-US': 'Picture',
18   - 'zh-CN': '图片'
19   - },
20   - icon: 'photo',
21   - component: LbpPicture,
22   - visible: true,
23   - name: LbpPicture.name
24   - },
25   - {
26   - i18nTitle: {
27   - 'en-US': 'Text',
28   - 'zh-CN': '文字'
29   - },
30   - title: '文字',
31   - icon: 'text-width',
32   - component: LbpText,
33   - visible: true,
34   - name: LbpText.name
35   - },
  15 + // {
  16 + // title: '图片',
  17 + // i18nTitle: {
  18 + // 'en-US': 'Picture',
  19 + // 'zh-CN': '图片'
  20 + // },
  21 + // icon: 'photo',
  22 + // component: LbpPicture,
  23 + // visible: true,
  24 + // name: LbpPicture.name
  25 + // },
  26 + // {
  27 + // i18nTitle: {
  28 + // 'en-US': 'Text',
  29 + // 'zh-CN': '文字'
  30 + // },
  31 + // title: '文字',
  32 + // icon: 'text-width',
  33 + // component: LbpText,
  34 + // visible: true,
  35 + // name: LbpText.name
  36 + // },
36 37 {
37 38 i18nTitle: {
38 39 'en-US': 'Button',
... ... @@ -44,99 +45,99 @@ export const pluginsList = [
44 45 visible: true,
45 46 name: LbpButton.name
46 47 },
47   - {
48   - i18nTitle: {
49   - 'en-US': 'Carousel',
50   - 'zh-CN': '轮播图'
51   - },
52   - title: '轮播图',
53   - icon: 'photo',
54   - component: LbpSlide,
55   - visible: true,
56   - name: LbpSlide.name
57   - // disabled: true
58   - },
59   - {
60   - i18nTitle: {
61   - 'en-US': 'Map',
62   - 'zh-CN': '地图'
63   - },
64   - title: '地图',
65   - icon: 'map-o',
66   - component: LbpFormRadioGroup,
67   - visible: true,
68   - name: LbpFormRadioGroup.name,
69   - disabled: true
70   - },
71   - {
72   - i18nTitle: {
73   - 'en-US': 'Video',
74   - 'zh-CN': '视频'
75   - },
76   - title: '视频',
77   - icon: 'file-video-o',
78   - component: LbpVideo,
79   - visible: true,
80   - name: LbpVideo.name
81   - },
82 48 // {
  49 + // i18nTitle: {
  50 + // 'en-US': 'Carousel',
  51 + // 'zh-CN': '轮播图'
  52 + // },
  53 + // title: '轮播图',
  54 + // icon: 'photo',
  55 + // component: LbpSlide,
  56 + // visible: true,
  57 + // name: LbpSlide.name
  58 + // // disabled: true
  59 + // },
  60 + // {
  61 + // i18nTitle: {
  62 + // 'en-US': 'Map',
  63 + // 'zh-CN': '地图'
  64 + // },
  65 + // title: '地图',
  66 + // icon: 'map-o',
  67 + // component: LbpFormRadioGroup,
  68 + // visible: true,
  69 + // name: LbpFormRadioGroup.name,
  70 + // disabled: true
  71 + // },
  72 + // {
  73 + // i18nTitle: {
  74 + // 'en-US': 'Video',
  75 + // 'zh-CN': '视频'
  76 + // },
83 77 // title: '视频',
84   - // icon: 'play-circle-o',
  78 + // icon: 'file-video-o',
85 79 // component: LbpVideo,
86 80 // visible: true,
87 81 // name: LbpVideo.name
88 82 // },
89   - {
90   - i18nTitle: {
91   - 'en-US': 'Form Input',
92   - 'zh-CN': '表单输入'
93   - },
94   - title: '表单输入',
95   - icon: 'pencil-square-o',
96   - component: LbpFormInput,
97   - visible: true,
98   - name: LbpFormInput.name
99   - },
100   - {
101   - i18nTitle: {
102   - 'en-US': 'Form Submit',
103   - 'zh-CN': '表单提交'
104   - },
105   - title: '表单提交',
106   - icon: 'hand-pointer-o',
107   - component: LbpFormButton,
108   - visible: true,
109   - name: LbpFormButton.name
110   - },
  83 + // // {
  84 + // // title: '视频',
  85 + // // icon: 'play-circle-o',
  86 + // // component: LbpVideo,
  87 + // // visible: true,
  88 + // // name: LbpVideo.name
  89 + // // },
111 90 // {
112   - // title: '表单单选',
  91 + // i18nTitle: {
  92 + // 'en-US': 'Form Input',
  93 + // 'zh-CN': '表单输入'
  94 + // },
  95 + // title: '表单输入',
  96 + // icon: 'pencil-square-o',
  97 + // component: LbpFormInput,
  98 + // visible: true,
  99 + // name: LbpFormInput.name
  100 + // },
  101 + // {
  102 + // i18nTitle: {
  103 + // 'en-US': 'Form Submit',
  104 + // 'zh-CN': '表单提交'
  105 + // },
  106 + // title: '表单提交',
113 107 // icon: 'hand-pointer-o',
114   - // component: LbpFormRadio,
  108 + // component: LbpFormButton,
115 109 // visible: true,
116   - // name: LbpFormRadio.name
  110 + // name: LbpFormButton.name
  111 + // },
  112 + // // {
  113 + // // title: '表单单选',
  114 + // // icon: 'hand-pointer-o',
  115 + // // component: LbpFormRadio,
  116 + // // visible: true,
  117 + // // name: LbpFormRadio.name
  118 + // // },
  119 + // {
  120 + // i18nTitle: {
  121 + // 'en-US': 'Form Checkbox',
  122 + // 'zh-CN': '表单多选'
  123 + // },
  124 + // title: '表单多选',
  125 + // icon: 'check-square-o',
  126 + // component: LbpFormCheckboxGroup,
  127 + // visible: true,
  128 + // name: LbpFormCheckboxGroup.name
  129 + // },
  130 + // {
  131 + // i18nTitle: {
  132 + // 'en-US': 'Form Radio',
  133 + // 'zh-CN': '表单单选'
  134 + // },
  135 + // title: '表单单选',
  136 + // icon: 'dot-circle-o',
  137 + // component: LbpFormRadioGroup,
  138 + // visible: true,
  139 + // name: LbpFormRadioGroup.name
117 140 // },
118   - {
119   - i18nTitle: {
120   - 'en-US': 'Form Checkbox',
121   - 'zh-CN': '表单多选'
122   - },
123   - title: '表单多选',
124   - icon: 'check-square-o',
125   - component: LbpFormCheckboxGroup,
126   - visible: true,
127   - name: LbpFormCheckboxGroup.name
128   - },
129   - {
130   - i18nTitle: {
131   - 'en-US': 'Form Radio',
132   - 'zh-CN': '表单单选'
133   - },
134   - title: '表单单选',
135   - icon: 'dot-circle-o',
136   - component: LbpFormRadioGroup,
137   - visible: true,
138   - name: LbpFormRadioGroup.name
139   - },
140 141 {
141 142 i18nTitle: {
142 143 'en-US': 'Background',
... ...
front-end/h5/src/store/modules/element.js
1 1 import Element from '../../components/core/models/element'
2   -import { getEditorConfigForEditingElement, swapZindex } from '../../utils/element'
  2 +import { getEditorConfigForEditingElement, swapZindex, getVM } from '../../utils/element'
3 3  
4 4 // actions
5 5 export const actions = {
... ... @@ -44,11 +44,15 @@ export const mutations = {
44 44  
45 45 switch (type) {
46 46 case 'add':
  47 + // value.name => pluginName
  48 + const { name } = value
  49 + const vm = getVM(value.name)
  50 + const props = vm.$options.props
47 51 value = {
48 52 ...value,
49 53 zindex: len + 1
50 54 }
51   - const element = new Element(value)
  55 + const element = new Element({ name, editorConfig: props })
52 56 elements.push(element)
53 57 break
54 58 case 'copy':
... ...
front-end/h5/src/utils/element.js
... ... @@ -9,6 +9,11 @@ export function getEditorConfigForEditingElement (elementName) {
9 9 return new Ctor().$options.editorConfig
10 10 }
11 11  
  12 +export function getVM (pluginName) {
  13 + const Ctor = Vue.component(pluginName)
  14 + return new Ctor()
  15 +}
  16 +
12 17 export function swapZindex (x, y) {
13 18 const tmp = y[styleKey].zindex
14 19 y[styleKey].zindex = x[styleKey].zindex
... ...