Commit 74accbcfc538c91a083d7a34a0b492e4c3953b8b
Committed by
小小鲁班
1 parent
a81a9fb6
[feature] 解决更改组件border渲染问题
Showing
3 changed files
with
150 additions
and
32 deletions
front-end/h5/src/components/core/editor/right-panel/box-model/index.vue
| 1 | <template> | 1 | <template> |
| 2 | - <div class="box-model"> | 2 | + <div v-if="editingElement" class="box-model"> |
| 3 | <div v-if="lastSelect" class="prompt">设置 {{ lastSelect }} 大小</div> | 3 | <div v-if="lastSelect" class="prompt">设置 {{ lastSelect }} 大小</div> |
| 4 | <div v-else>选择 margin/border/padding 设置大小</div> | 4 | <div v-else>选择 margin/border/padding 设置大小</div> |
| 5 | - <PositionCheckbox label="上" /> | 5 | + <PositionCheckbox label="上" label-key="top" /> |
| 6 | <div class="middle"> | 6 | <div class="middle"> |
| 7 | - <PositionCheckbox label="左" /> | 7 | + <PositionCheckbox label="左" label-key="left" /> |
| 8 | <div ref="margin" class="margin" data-type="margin" @click="onBoxModelClick"> | 8 | <div ref="margin" class="margin" data-type="margin" @click="onBoxModelClick"> |
| 9 | margin | 9 | margin |
| 10 | <div ref="border" class="border" data-type="border"> | 10 | <div ref="border" class="border" data-type="border"> |
| @@ -14,13 +14,14 @@ | @@ -14,13 +14,14 @@ | ||
| 14 | </div> | 14 | </div> |
| 15 | </div> | 15 | </div> |
| 16 | </div> | 16 | </div> |
| 17 | - <PositionCheckbox label="右" /> | 17 | + <PositionCheckbox label="右" label-key="right" /> |
| 18 | </div> | 18 | </div> |
| 19 | - <PositionCheckbox label="下" /> | 19 | + <PositionCheckbox label="下" label-key="bottom" /> |
| 20 | </div> | 20 | </div> |
| 21 | </template> | 21 | </template> |
| 22 | 22 | ||
| 23 | <script> | 23 | <script> |
| 24 | + import { mapState, mapActions } from 'vuex' | ||
| 24 | import PositionCheckbox from './position-checkbox' | 25 | import PositionCheckbox from './position-checkbox' |
| 25 | export default { | 26 | export default { |
| 26 | name: 'BoxModel', | 27 | name: 'BoxModel', |
| @@ -32,14 +33,24 @@ | @@ -32,14 +33,24 @@ | ||
| 32 | lastSelect: '' | 33 | lastSelect: '' |
| 33 | } | 34 | } |
| 34 | }, | 35 | }, |
| 35 | - | 36 | + computed: { |
| 37 | + ...mapState('editor', { | ||
| 38 | + editingElement: state => state.editingElement | ||
| 39 | + }) | ||
| 40 | + }, | ||
| 36 | methods: { | 41 | methods: { |
| 42 | + ...mapActions('editor', [ | ||
| 43 | + 'setElementPosition' | ||
| 44 | + ]), | ||
| 37 | onBoxModelClick (e) { | 45 | onBoxModelClick (e) { |
| 38 | const target = e.target | 46 | const target = e.target |
| 39 | const classList = target.classList | 47 | const classList = target.classList |
| 40 | const type = target.dataset.type | 48 | const type = target.dataset.type |
| 41 | const selectClass = type + '-select' | 49 | const selectClass = type + '-select' |
| 42 | - | 50 | + // 更新选中的 boxModelPart,用于判断当前设置的是 margin / border / padding |
| 51 | + this.setElementPosition({ | ||
| 52 | + boxModelPart: type | ||
| 53 | + }) | ||
| 43 | if (this.lastSelect && type !== this.lastSelect) { | 54 | if (this.lastSelect && type !== this.lastSelect) { |
| 44 | this.$refs[this.lastSelect].classList.remove(this.lastSelect + '-select') | 55 | this.$refs[this.lastSelect].classList.remove(this.lastSelect + '-select') |
| 45 | } | 56 | } |
front-end/h5/src/components/core/editor/right-panel/box-model/position-checkbox.vue
| 1 | <template> | 1 | <template> |
| 2 | <div class="position-checkbox"> | 2 | <div class="position-checkbox"> |
| 3 | - <div class="flex"> | ||
| 4 | - <a-checkbox @change="onCheckboxChange"> | ||
| 5 | - </a-checkbox> | ||
| 6 | - <div class="label">{{label}}</div> | ||
| 7 | - </div> | ||
| 8 | - <a-input-number style="width:70px" v-model="value" :min="0" @change="onInputNumberChange" /> | ||
| 9 | - <a-select default-value="px" style="width:70px"> | ||
| 10 | - <a-select-option value="px"> | ||
| 11 | - px | ||
| 12 | - </a-select-option> | ||
| 13 | - <a-select-option value="%"> | ||
| 14 | - % | ||
| 15 | - </a-select-option> | ||
| 16 | - <a-select-option value="em"> | ||
| 17 | - em | ||
| 18 | - </a-select-option> | ||
| 19 | - </a-select> | 3 | + <!-- 只有选中 padding border margin 之后才会显示 --> |
| 4 | + <template v-if="boxModelPart"> | ||
| 5 | + <div class="flex"> | ||
| 6 | + <a-checkbox @change="onCheckboxChange"> | ||
| 7 | + </a-checkbox> | ||
| 8 | + <div class="label">{{label}}</div> | ||
| 9 | + </div> | ||
| 10 | + <a-input-number style="width:70px" :value="value" :min="0" @change="onInputNumberChange" /> | ||
| 11 | + <a-select :default-value="unitList[0]" style="width:70px"> | ||
| 12 | + <a-select-option v-for="(item,index) in unitList" :key="index" :value="item"> | ||
| 13 | + {{ item }} | ||
| 14 | + </a-select-option> | ||
| 15 | + </a-select> | ||
| 16 | + </template> | ||
| 20 | </div> | 17 | </div> |
| 21 | </template> | 18 | </template> |
| 22 | 19 | ||
| 23 | <script> | 20 | <script> |
| 21 | + import { mapState, mapActions } from 'vuex' | ||
| 24 | export default { | 22 | export default { |
| 25 | name: 'PositionCheckbox', | 23 | name: 'PositionCheckbox', |
| 26 | props: { | 24 | props: { |
| 27 | label: { | 25 | label: { |
| 28 | type: String, | 26 | type: String, |
| 29 | default: '' | 27 | default: '' |
| 28 | + }, | ||
| 29 | + labelKey: { | ||
| 30 | + type: String, | ||
| 31 | + default: '' | ||
| 30 | } | 32 | } |
| 31 | }, | 33 | }, |
| 32 | - data () { | ||
| 33 | - return { | ||
| 34 | - value: 1 | 34 | + computed: { |
| 35 | + ...mapState('editor', { | ||
| 36 | + editingElement: state => state.editingElement | ||
| 37 | + }), | ||
| 38 | + boxModelPart () { | ||
| 39 | + return this.editingElement && this.editingElement.commonStyle.boxModelPart | ||
| 40 | + }, | ||
| 41 | + value () { | ||
| 42 | + const { editingElement, labelKey, boxModelPart } = this | ||
| 43 | + return this.boxModelPart ? editingElement.commonStyle[boxModelPart][labelKey].value : '' | ||
| 44 | + }, | ||
| 45 | + unitList () { | ||
| 46 | + return this.boxModelPart === 'border' ? ['px', 'em'] : ['px', '%', 'em'] | ||
| 35 | } | 47 | } |
| 36 | }, | 48 | }, |
| 37 | - | ||
| 38 | methods: { | 49 | methods: { |
| 39 | - onCheckboxChange () {}, | ||
| 40 | - onInputNumberChange () {} | 50 | + ...mapActions('editor', [ |
| 51 | + 'setElementPosition' | ||
| 52 | + ]), | ||
| 53 | + onCheckboxChange (e) { | ||
| 54 | + }, | ||
| 55 | + onInputNumberChange (value) { | ||
| 56 | + const boxModelPart = this.boxModelPart | ||
| 57 | + // 例如 boxModelPart 为 margin 时候 | ||
| 58 | + const boxModelPartStyle = this.editingElement.commonStyle[boxModelPart] | ||
| 59 | + // 更新值例如: padding-top | ||
| 60 | + Object.assign(boxModelPartStyle[this.labelKey], { value }) | ||
| 61 | + this.setElementPosition({ [boxModelPart]: boxModelPartStyle }) | ||
| 62 | + } | ||
| 41 | } | 63 | } |
| 42 | } | 64 | } |
| 43 | </script> | 65 | </script> |
front-end/h5/src/components/core/models/element.js
| @@ -13,7 +13,69 @@ const defaultStyle = { | @@ -13,7 +13,69 @@ const defaultStyle = { | ||
| 13 | textAlign: 'center', | 13 | textAlign: 'center', |
| 14 | color: '#000000', | 14 | color: '#000000', |
| 15 | backgroundColor: 'rgba(255, 255, 255, 0)', | 15 | backgroundColor: 'rgba(255, 255, 255, 0)', |
| 16 | - fontSize: 14 | 16 | + fontSize: 14, |
| 17 | + margin: { | ||
| 18 | + top: { | ||
| 19 | + value: 10, | ||
| 20 | + unit: 'px' | ||
| 21 | + }, | ||
| 22 | + right: { | ||
| 23 | + value: 0, | ||
| 24 | + unit: 'px' | ||
| 25 | + }, | ||
| 26 | + bottom: { | ||
| 27 | + value: 30, | ||
| 28 | + unit: 'px' | ||
| 29 | + }, | ||
| 30 | + left: { | ||
| 31 | + value: 0, | ||
| 32 | + unit: 'px' | ||
| 33 | + } | ||
| 34 | + }, | ||
| 35 | + padding: { | ||
| 36 | + top: { | ||
| 37 | + value: 0, | ||
| 38 | + unit: 'px' | ||
| 39 | + }, | ||
| 40 | + right: { | ||
| 41 | + value: 0, | ||
| 42 | + unit: 'px' | ||
| 43 | + }, | ||
| 44 | + bottom: { | ||
| 45 | + value: 0, | ||
| 46 | + unit: 'px' | ||
| 47 | + }, | ||
| 48 | + left: { | ||
| 49 | + value: 0, | ||
| 50 | + unit: 'px' | ||
| 51 | + } | ||
| 52 | + }, | ||
| 53 | + border: { | ||
| 54 | + top: { | ||
| 55 | + value: 0, | ||
| 56 | + unit: 'px' | ||
| 57 | + }, | ||
| 58 | + right: { | ||
| 59 | + value: 0, | ||
| 60 | + unit: 'px' | ||
| 61 | + }, | ||
| 62 | + bottom: { | ||
| 63 | + value: 0, | ||
| 64 | + unit: 'px' | ||
| 65 | + }, | ||
| 66 | + left: { | ||
| 67 | + value: 0, | ||
| 68 | + unit: 'px' | ||
| 69 | + }, | ||
| 70 | + color: { | ||
| 71 | + value: '#000' | ||
| 72 | + }, | ||
| 73 | + style: { | ||
| 74 | + value: 'solid' | ||
| 75 | + } | ||
| 76 | + }, | ||
| 77 | + 'border-style': 'solid', | ||
| 78 | + boxModelPart: '' // 可选值 margin、padding、border | ||
| 17 | } | 79 | } |
| 18 | 80 | ||
| 19 | class Element { | 81 | class Element { |
| @@ -75,7 +137,25 @@ class Element { | @@ -75,7 +137,25 @@ class Element { | ||
| 75 | 137 | ||
| 76 | return pluginProps | 138 | return pluginProps |
| 77 | } | 139 | } |
| 78 | - | 140 | + packPosData (obj, prefix) { |
| 141 | + let init = {} | ||
| 142 | + Object.keys(obj).forEach(key => { | ||
| 143 | + init[prefix + '-' + key] = obj[key].value + (obj[key].unit || '') | ||
| 144 | + }) | ||
| 145 | + return init | ||
| 146 | + } | ||
| 147 | + packBorderData () { | ||
| 148 | + const { top, right, bottom, left, color, style } = this.commonStyle.border | ||
| 149 | + return { | ||
| 150 | + /** | ||
| 151 | + * 使用 border-left border-right 等方式,在 chrome 浏览器中会导致渲染问题 | ||
| 152 | + * 这里就将他拼接成完整的 border-width解决bug,不知道是什么原因 | ||
| 153 | + */ | ||
| 154 | + 'border-width': `${top.value}px ${right.value}px ${bottom.value}px ${left.value}px `, | ||
| 155 | + 'border-style': style.value, | ||
| 156 | + 'border-color': color.value | ||
| 157 | + } | ||
| 158 | + } | ||
| 79 | getStyle ({ position = 'static', isRem = false } = {}) { | 159 | getStyle ({ position = 'static', isRem = false } = {}) { |
| 80 | if (this.name === 'lbp-background') { | 160 | if (this.name === 'lbp-background') { |
| 81 | return { | 161 | return { |
| @@ -85,12 +165,17 @@ class Element { | @@ -85,12 +165,17 @@ class Element { | ||
| 85 | } | 165 | } |
| 86 | const pluginProps = this.pluginProps | 166 | const pluginProps = this.pluginProps |
| 87 | const commonStyle = this.commonStyle | 167 | const commonStyle = this.commonStyle |
| 168 | + const { margin, padding } = commonStyle | ||
| 169 | + // 由于在 defaultStyle 定义的时候是对象,这里需要将数据重新组装成 margin-top 这种形式 | ||
| 170 | + const boxModel = { ...this.packPosData(margin, 'margin'), ...this.packPosData(padding, 'padding'), ...this.packBorderData() } | ||
| 88 | let style = { | 171 | let style = { |
| 89 | top: parsePx(pluginProps.top || commonStyle.top, isRem), | 172 | top: parsePx(pluginProps.top || commonStyle.top, isRem), |
| 90 | left: parsePx(pluginProps.left || commonStyle.left, isRem), | 173 | left: parsePx(pluginProps.left || commonStyle.left, isRem), |
| 91 | width: parsePx(pluginProps.width || commonStyle.width, isRem), | 174 | width: parsePx(pluginProps.width || commonStyle.width, isRem), |
| 92 | height: parsePx(pluginProps.height || commonStyle.height, isRem), | 175 | height: parsePx(pluginProps.height || commonStyle.height, isRem), |
| 93 | fontSize: parsePx(pluginProps.fontSize || commonStyle.fontSize, isRem), | 176 | fontSize: parsePx(pluginProps.fontSize || commonStyle.fontSize, isRem), |
| 177 | + ...boxModel, | ||
| 178 | + // 'border-style': commonStyle['border-style'], | ||
| 94 | color: pluginProps.color || commonStyle.color, | 179 | color: pluginProps.color || commonStyle.color, |
| 95 | // backgroundColor: pluginProps.backgroundColor || commonStyle.backgroundColor, | 180 | // backgroundColor: pluginProps.backgroundColor || commonStyle.backgroundColor, |
| 96 | textAlign: pluginProps.textAlign || commonStyle.textAlign, | 181 | textAlign: pluginProps.textAlign || commonStyle.textAlign, |