Commit d04cf043b7558729a15123456fbc2a0025f08c3e
1 parent
714b898c
chore(editor): #2 edit plugin props in the props editor panel
Showing
1 changed file
with
104 additions
and
82 deletions
front-end/h5/src/views/Editor.vue
| ... | ... | @@ -84,14 +84,12 @@ const LbpButton = { |
| 84 | 84 | } |
| 85 | 85 | }, |
| 86 | 86 | editorConfig: { |
| 87 | - propConfig: { | |
| 88 | - name: { | |
| 87 | + propsConfig: { | |
| 88 | + text: { | |
| 89 | 89 | type: 'el-input', |
| 90 | 90 | label: '按钮文字', |
| 91 | 91 | require: true, |
| 92 | - widgetProps: { | |
| 93 | - value: '按钮' | |
| 94 | - } | |
| 92 | + defaultPropValue: '按钮' | |
| 95 | 93 | }, |
| 96 | 94 | fontSize: { |
| 97 | 95 | type: 'el-input-number', |
| ... | ... | @@ -102,10 +100,7 @@ const LbpButton = { |
| 102 | 100 | min: 12, |
| 103 | 101 | max: 144 |
| 104 | 102 | }, |
| 105 | - widgetProps: { | |
| 106 | - value: 14 | |
| 107 | - | |
| 108 | - } | |
| 103 | + defaultPropValue: 14 | |
| 109 | 104 | }, |
| 110 | 105 | color: { |
| 111 | 106 | type: 'el-input', |
| ... | ... | @@ -115,9 +110,7 @@ const LbpButton = { |
| 115 | 110 | type: 'color' |
| 116 | 111 | }, |
| 117 | 112 | require: true, |
| 118 | - widgetProps: { | |
| 119 | - value: '' | |
| 120 | - } | |
| 113 | + defaultPropValue: 'black' | |
| 121 | 114 | }, |
| 122 | 115 | backgroundColor: { |
| 123 | 116 | type: 'el-input', // lbs-color-picker |
| ... | ... | @@ -126,9 +119,7 @@ const LbpButton = { |
| 126 | 119 | type: 'color' |
| 127 | 120 | }, |
| 128 | 121 | require: true, |
| 129 | - widgetProps: { | |
| 130 | - value: '' | |
| 131 | - } | |
| 122 | + defaultPropValue: '#ffffff' // TODO why logogram for color does't work? | |
| 132 | 123 | }, |
| 133 | 124 | borderColor: { |
| 134 | 125 | type: 'el-input', // lbs-color-picker |
| ... | ... | @@ -137,9 +128,7 @@ const LbpButton = { |
| 137 | 128 | type: 'color' |
| 138 | 129 | }, |
| 139 | 130 | require: true, |
| 140 | - widgetProps: { | |
| 141 | - value: '#ced4da' | |
| 142 | - } | |
| 131 | + defaultPropValue: '#eeeeee' | |
| 143 | 132 | }, |
| 144 | 133 | borderWidth: { |
| 145 | 134 | type: 'el-input-number', |
| ... | ... | @@ -150,9 +139,7 @@ const LbpButton = { |
| 150 | 139 | min: 1, |
| 151 | 140 | max: 10 |
| 152 | 141 | }, |
| 153 | - widgetProps: { | |
| 154 | - value: 1 | |
| 155 | - } | |
| 142 | + defaultPropValue: 1 | |
| 156 | 143 | }, |
| 157 | 144 | borderRadius: { |
| 158 | 145 | type: 'el-input-number', |
| ... | ... | @@ -163,10 +150,7 @@ const LbpButton = { |
| 163 | 150 | min: 0, |
| 164 | 151 | max: 10 |
| 165 | 152 | }, |
| 166 | - widgetProps: { | |
| 167 | - value: 0 | |
| 168 | - | |
| 169 | - } | |
| 153 | + defaultPropValue: 0 | |
| 170 | 154 | }, |
| 171 | 155 | lineHeight: { |
| 172 | 156 | type: 'el-input-number', |
| ... | ... | @@ -177,19 +161,13 @@ const LbpButton = { |
| 177 | 161 | min: 0.1, |
| 178 | 162 | max: 10 |
| 179 | 163 | }, |
| 180 | - widgetProps: { | |
| 181 | - value: 1 | |
| 182 | - | |
| 183 | - } | |
| 164 | + defaultPropValue: 1 | |
| 184 | 165 | }, |
| 185 | 166 | textAlign: { |
| 186 | 167 | type: 'lbs-text-align', |
| 187 | 168 | label: '文字对齐', |
| 188 | 169 | require: true, |
| 189 | - widgetProps: { | |
| 190 | - value: 'center' | |
| 191 | - | |
| 192 | - } | |
| 170 | + defaultPropValue: 'center' | |
| 193 | 171 | } |
| 194 | 172 | }, |
| 195 | 173 | components: { |
| ... | ... | @@ -293,21 +271,51 @@ const PluginList = [ |
| 293 | 271 | } |
| 294 | 272 | ] |
| 295 | 273 | |
| 274 | +const defaultProps = { | |
| 275 | + top: 100, | |
| 276 | + left: 100, | |
| 277 | + width: 100, | |
| 278 | + height: 40, | |
| 279 | + zindex: 1, | |
| 280 | + textAlign: 'center', | |
| 281 | + color: '#000000', | |
| 282 | + backgroundColor: '#ffffff', | |
| 283 | + fontSize: 14 | |
| 284 | +} | |
| 285 | + | |
| 296 | 286 | class Element { |
| 297 | 287 | constructor (ele) { |
| 298 | - const { defaultPropsValue = {} } = ele | |
| 299 | - this.type = ele.name | |
| 288 | + // TODO 需要处理plugin的prop中是 name 的,会覆盖 this.name, | |
| 289 | + // 或者将plugin的props赋值给this.pluginProps,这样可以避免冲突,也可以知道哪些是plugin 的props | |
| 300 | 290 | this.name = ele.name |
| 301 | - this.zindex = ele.zindex || defaultPropsValue.zindex || 1 | |
| 302 | - this.style = { | |
| 303 | - top: ele.top || defaultPropsValue.top || 100, | |
| 304 | - left: ele.left || defaultPropsValue.left || 100, | |
| 305 | - ...defaultPropsValue | |
| 306 | - } | |
| 291 | + this.editorConfig = ele.editorConfig || {} | |
| 292 | + this.init() | |
| 307 | 293 | } |
| 308 | 294 | |
| 309 | - getStyle () { | |
| 295 | + init () { | |
| 296 | + // init common props | |
| 297 | + Object.keys(defaultProps).forEach(key => { | |
| 298 | + this[key] = defaultProps[key] | |
| 299 | + }) | |
| 300 | + | |
| 301 | + // init prop of plugin | |
| 302 | + const propConf = this.editorConfig.propsConfig | |
| 303 | + Object.keys(propConf).forEach(key => { | |
| 304 | + this[key] = propConf[key].defaultPropValue | |
| 305 | + }) | |
| 306 | + } | |
| 310 | 307 | |
| 308 | + getStyle () { | |
| 309 | + return { | |
| 310 | + top: `${this.top}px`, | |
| 311 | + left: `${this.left}px`, | |
| 312 | + width: `${this.width}px`, | |
| 313 | + height: `${this.height}px`, | |
| 314 | + fontSize: `${this.fontSize}px`, | |
| 315 | + color: this.color, | |
| 316 | + backgroundColor: this.backgroundColor, | |
| 317 | + textAlign: this.textAlign | |
| 318 | + } | |
| 311 | 319 | } |
| 312 | 320 | |
| 313 | 321 | getClass () { |
| ... | ... | @@ -322,27 +330,29 @@ class Element { |
| 322 | 330 | const Editor = { |
| 323 | 331 | name: 'Editor', |
| 324 | 332 | components: { |
| 325 | - EditorPanel: { | |
| 326 | - template: '<div>Editor Panel</div>' | |
| 327 | - } | |
| 328 | 333 | }, |
| 329 | 334 | data: () => ({ |
| 330 | 335 | pages: [], |
| 331 | - elements: [] | |
| 336 | + elements: [], | |
| 337 | + editingElement: null | |
| 332 | 338 | }), |
| 333 | 339 | methods: { |
| 340 | + getEditorConfig (pluginName) { | |
| 341 | + return this.$options.components[pluginName].editorConfig | |
| 342 | + }, | |
| 334 | 343 | /** |
| 335 | 344 | * !#zh 点击插件,copy 其基础数据到组件树(中间画布) |
| 336 | 345 | * pluginInfo {Object}: 插件列表中的基础数据, {name}=pluginInfo |
| 337 | 346 | */ |
| 338 | 347 | clone ({ name }) { |
| 348 | + debugger | |
| 339 | 349 | const zindex = this.elements.length + 1 |
| 340 | - const defaultPropsValue = this.getPropsDefaultValue(name) | |
| 341 | - this.elements.push(new Element({ name, zindex, defaultPropsValue })) | |
| 342 | - // return new Element({ name, zindex }) | |
| 350 | + // const defaultPropsValue = this.getPropsDefaultValue(name) | |
| 351 | + const editorConfig = this.getEditorConfig(name) | |
| 352 | + this.elements.push(new Element({ name, zindex, editorConfig })) | |
| 343 | 353 | }, |
| 344 | 354 | setCurrentEditingElement (element) { |
| 345 | - | |
| 355 | + this.editingElement = element | |
| 346 | 356 | }, |
| 347 | 357 | /** |
| 348 | 358 | * #!zh: renderCanvas 将拖拽过来的组件渲染到中间画布 上 |
| ... | ... | @@ -357,16 +367,8 @@ const Editor = { |
| 357 | 367 | {elements.map((element, index) => { |
| 358 | 368 | return (() => { |
| 359 | 369 | const data = { |
| 360 | - style: { | |
| 361 | - top: '100px', | |
| 362 | - fontSize: '16px', | |
| 363 | - textAlign: 'center', | |
| 364 | - color: 'orange', | |
| 365 | - width: '100px', | |
| 366 | - height: '30px', | |
| 367 | - position: 'absolute' | |
| 368 | - }, | |
| 369 | - on: { | |
| 370 | + style: element.getStyle(), | |
| 371 | + nativeOn: { | |
| 370 | 372 | click: this.setCurrentEditingElement.bind(this, element) |
| 371 | 373 | } |
| 372 | 374 | } |
| ... | ... | @@ -404,27 +406,54 @@ const Editor = { |
| 404 | 406 | </el-tabs> |
| 405 | 407 | ) |
| 406 | 408 | }, |
| 407 | - renderPropsEditorPanel () { | |
| 408 | - return (<EditorPanel />) | |
| 409 | + renderPropsEditorPanel (h) { | |
| 410 | + if (!this.editingElement) return (<span>请先选择一个元素</span>) | |
| 411 | + const editingElement = this.editingElement | |
| 412 | + const propsConfig = editingElement.editorConfig.propsConfig | |
| 413 | + return ( | |
| 414 | + <el-form ref="form" label-width="80px"> | |
| 415 | + { | |
| 416 | + Object.keys(propsConfig).map(propKey => { | |
| 417 | + const item = propsConfig[propKey] | |
| 418 | + // https://vuejs.org/v2/guide/render-function.html | |
| 419 | + const data = { | |
| 420 | + props: { | |
| 421 | + ...item.prop, | |
| 422 | + // https://vuejs.org/v2/guide/render-function.html#v-model | |
| 423 | + ...{ value: editingElement[propKey] || item.defaultPropValue } | |
| 424 | + }, | |
| 425 | + on: { | |
| 426 | + // https://vuejs.org/v2/guide/render-function.html#v-model | |
| 427 | + input (value) { | |
| 428 | + editingElement[propKey] = value | |
| 429 | + } | |
| 430 | + } | |
| 431 | + } | |
| 432 | + return ( | |
| 433 | + <el-form-item label={item.label}> | |
| 434 | + { h(item.type, data) } | |
| 435 | + </el-form-item> | |
| 436 | + ) | |
| 437 | + }) | |
| 438 | + } | |
| 439 | + </el-form> | |
| 440 | + ) | |
| 409 | 441 | } |
| 410 | 442 | }, |
| 411 | 443 | render (h) { |
| 412 | 444 | return ( |
| 413 | - <div style='height: 100vh;'> | |
| 414 | - <div id='designer-page'> | |
| 415 | - <div class='el-col-5'> | |
| 416 | - { this.renderPluginListPanel() } | |
| 417 | - </div> | |
| 418 | - <div class='el-col-13'> | |
| 419 | - <div class='canvas-wrapper'> | |
| 420 | - { this.renderCanvas(h, this.elements) } | |
| 421 | - { this.hasEleEditing && <Shape elementStyle={this.editingElement.style || {}} /> } | |
| 422 | - </div> | |
| 423 | - </div> | |
| 424 | - <div class='el-col-6'> | |
| 425 | - { this.renderPropsEditorPanel() } | |
| 445 | + <div id='designer-page'> | |
| 446 | + <div class='el-col-5'> | |
| 447 | + { this.renderPluginListPanel() } | |
| 448 | + </div> | |
| 449 | + <div class='el-col-13'> | |
| 450 | + <div class='canvas-wrapper'> | |
| 451 | + { this.renderCanvas(h, this.elements) } | |
| 426 | 452 | </div> |
| 427 | 453 | </div> |
| 454 | + <div class='el-col-6' style="border-left: 1px solid #eee;"> | |
| 455 | + { this.renderPropsEditorPanel(h) } | |
| 456 | + </div> | |
| 428 | 457 | </div> |
| 429 | 458 | ) |
| 430 | 459 | } |
| ... | ... | @@ -439,13 +468,6 @@ export default { |
| 439 | 468 | } |
| 440 | 469 | }, |
| 441 | 470 | methods: { |
| 442 | - getPropsDefaultValue (pluginName) { | |
| 443 | - const defaultPropsValue = {} | |
| 444 | - const component = this.$options.components[pluginName] | |
| 445 | - const propConfig = component.editorConfig.propConfig | |
| 446 | - Object.keys(propConfig).forEach(key => { defaultPropsValue[key] = propConfig[key].widgetProps.value }) | |
| 447 | - return defaultPropsValue | |
| 448 | - }, | |
| 449 | 471 | mixinPlugins2Editor () { |
| 450 | 472 | PluginList.forEach(plugin => { |
| 451 | 473 | this.$options.components[plugin.name] = plugin.component | ... | ... |