Commit 65958437 authored by 张晨辰's avatar 张晨辰

feat: 属性编辑

parent ca3a2dc2
......@@ -29,7 +29,6 @@ export default {
},
data() {
return {
selfText: '文字'
};
},
computed: {
......@@ -42,10 +41,10 @@ export default {
},
addNBSP() {
return this.selfText.replace(/\s/g, '') ? '' : ' ';
},
selfText() {
return this.properties.text || '文字';
}
},
created() {
this.selfText = this.properties.text || this.selfText;
}
};
</script>
<template>
<el-select v-model="selected" :filterable="filterable" allow-create placeholder="请选择">
<el-option
v-for="item in options"
:style="`${optionStyle}${item.value}`"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
<script>
import optionMapper from './optionMapper';
export default {
props: {
/*
* fontFamily: 字体
* fontSize: 字体大小选择列表
* borderStyle: 边框类型
* animeCount: 动效次数
*/
optionType: {
type: String,
default: 'fontSize:'
},
optionList: Array, // 若有 optionList 则groupType 不起作用
value: [String, Number, Boolean],
filterable: Boolean
},
data() {
return {
selected: '',
optionMapper
};
},
created() {
this.selected = this.value;
},
computed: {
options() {
return this.optionList || this.optionMapper[this.optionType];
},
optionStyle() {
return this.optionType === 'fontFamily' ? 'font-family: ' : '';
}
},
watch: {
selected(v) {
this.$emit('change', v);
},
value(v) {
console.log('selector value change', v);
this.selected = this.value;
}
}
};
</script>
import _ from 'lodash'
const rangeStep = (start, step, stop) =>
_.map(
_.range(0, (1 + (stop - start) / step) >>> 0),
(n) => (start + step * n).toFixed(0),
);
export default {
fontFamily: [
{
label: '默认字体',
value: ''
},
{ label: '微软雅黑', value: 'Microsoft Yahei' },
// { label: '方正黑体简体', value: 'FZHei-B01S' },
// { label: '方正楷体简体', value: 'FZKai-Z03S' },
// { label: '方正书宋简体', value: 'FZShuSong-Z01S' },
// { label: '方正仿宋简体', value: 'FZFangSong-Z02S' },
// { label: '思源极细体', value: 'NotoSansSC-Thin' },
// { label: '思源细体', value: 'NotoSansSC-Light' },
// { label: '思源正常', value: 'NotoSansSC-DemiLight' },
// { label: '思源常规', value: 'NotoSansSC-Regular' },
// { label: '思源中等粗体', value: 'NotoSansSC-Medium' },
// { label: '思源粗体', value: 'NotoSansSC-Bold' },
// { label: '思源特粗', value: 'NotoSansSC-Black' },
{ label: '宋体', value: 'SimSun' },
// { label: '黑体', value: 'SimHei' },
{ label: 'fantasy', value: 'fantasy' },
{ label: 'Cursive', value: 'Cursive' }
],
borderStyle: [
{ label: '实线', value: 'solid' },
{ label: '点线', value: 'dotted' },
{ label: '虚线', value: 'dashed' },
{ label: '双线', value: 'double' }
],
backgroundSize: [
{ label: '全覆盖', value: 'cover' },
{ label: '完全显示图片', value: 'contain' }
],
backgroundRepeat: [
{ label: '显示一次', value: 'no-repeat' },
{ label: '重复', value: 'repeat' },
{ label: '水平方向重复', value: 'repeat-x' },
{ label: '垂直方向重复', value: 'repeat-y' }
],
backgroundPosition: [
{ label: '居中', value: 'center' },
{ label: '左上', value: 'top left' },
{ label: '顶部居中', value: 'top center' },
{ label: '右上', value: 'top right' },
{ label: '靠左', value: 'center left' },
{ label: '靠右', value: 'center right' },
{ label: '左下', value: 'bottom left' },
{ label: '底部居中', value: 'bottom center' },
{ label: '右下', value: 'bottom right' }
],
weekIndex: [
{ label: '周日', value: 0 },
{ label: '周一', value: 1 },
{ label: '周二', value: 2 },
{ label: '周三', value: 3 },
{ label: '周四', value: 4 },
{ label: '周五', value: 5 },
{ label: '周六', value: 6 }
],
fontSize: rangeStep(12, 1, 120).map((v) => ({ value: v, label: v })),
animeCount: rangeStep(1, 1, 10)
.map((v) => ({ value: v, label: v }))
.concat({ label: '无限循环', value: true })
};
<template>
<el-slider class="zero-slider" v-model="swvalue" :min="min" :max="max" :step="step"></el-slider>
</template>
<style>
/* .zero-slider {
position: relative;
}
.zero-slider > .el-slider__input {
position: absolute;
left: 110%;
top: -250%;
width: 60px;
}
.zero-slider > .el-slider__input > span {
display: none;
}
.zero-slider > .el-slider__input input {
padding: 0 10px;
} */
</style>
<script>
export default {
props: {
min: Number,
max: Number,
value: [String, Number, Boolean],
step: Number
},
data() {
return {
swvalue: 0
};
},
created() {
console.log('slider created', this.value);
this.swvalue = this.value;
},
watch: {
swvalue(v) {
this.$emit('change', v);
}
}
};
</script>
......@@ -63,9 +63,22 @@ export const projectStore = {
}
state.activeComponent = item;
// state.activeIdList = [id];
state.activeComponent.properties = state.activeComponent.properties || {};
console.log('mutations activeComponent', state);
},
/**
* 修改当前组件的属性
* @param {*} state
* @param {*} data
*/
modifyProperties(state, data) {
if (!data || !data.label) {
return;
}
state.activeComponent.properties[data.label] = data.value;
console.log('modifyProperties', state.activeComponent);
},
modifyProject(state, ) {
},
......@@ -151,7 +164,9 @@ export const projectStore = {
* 当前激活的组件
*/
activeComponent: state => {
return state.activeComponent || {}
console.log('activeComponent', state.activeComponent || {});
return { ...(state.activeComponent || {}), uuid: generateUUID() }
},
/**
* 当前激活的组件ID
......@@ -224,6 +239,9 @@ export const projectStore = {
commit('activeComponent', data);
},
modifyProperties({ commit }, data) {
commit('modifyProperties', data)
}
},
};
......@@ -10,4 +10,15 @@ export const componentsMap = [{
}, {
label: '形状',
value: 'rect'
}];
\ No newline at end of file
}];
export const styles = {
getStyles() {
},
getStyleObject(properties) {
console.log('getStyleObject', properties);
return {}
}
}
\ No newline at end of file
......@@ -4,24 +4,20 @@ import { getComposedComponents } from './getComposedComponents';
const composedComponents = getComposedComponents();
/**
* 初始化配置中的views数据
* @param {*} views
*/
export const compoleteComponentData = (views) => {
views.forEach(view => {
// view.id = view.id || guid();
// let _composedCmp = composedComponents[view.type];
// // view.component = _composedCmp.component.default;
// let _composedProps = _.cloneDeep(_composedCmp.properties); // 组件预设的属性,Object类型
view.id = view.id || guid();
let _composedCmp = composedComponents[view.type];
view.component = _composedCmp.component.default;
let _composedProps = _.cloneDeep(_composedCmp.properties); // 组件预设的属性,Object类型
// let _viewProps = view.properties || {}; // 组件对象的具体属性,key:value
// let _keys = Object.keys(_viewProps);
// _keys.forEach(k => {
// _composedProps[k].value = _viewProps[k]
// });
// view.properties = _composedProps;
let _viewProps = view.properties || {}; // 组件对象的具体属性,key:value
let _keys = Object.keys(_viewProps);
_keys.forEach(k => {
_composedProps[k].value = _viewProps[k]
});
view.properties = _composedProps;
if (view.children) {
compoleteComponentData(view.children);
......
......@@ -25,26 +25,46 @@ export default {
},
rotate: {
title: '旋转',
type: 'slider',
type: 'inputNumber',
props: {
min: -180,
max: 180
max: 180,
step: 1
},
value: 0
},
scaleX: {
title: 'X轴缩放',
type: 'inputNumber',
value: 1
value: 1,
props: {
min: 0
}
},
scaleY: {
title: 'Y轴缩放',
type: 'inputNumber',
value: 1
value: 1,
props: {
min: 0
}
},
alpha: {
title: '透明度',
type: 'slider',
value: 1,
props: {
min: 0,
max: 1,
step: 0.1
}
},
visible: {
title: '是否可见',
type: 'switch',
props: {
width: 40
},
value: true
}
},
......
<template>
<pane icon="el-icon-s-operation" :title="$t('panes.Inspector')">
<div class="zero-inspector-form">
<el-form ref="form" size="mini" v-if="activeComponentId" :model="activeComponent.properties" label-width="80px">
<el-form ref="form" size="mini" v-if="activeComponent.name" :model="activeComponent.properties" label-width="80px">
<el-form-item >
<el-button @click="testGetter">test</el-button>
</el-form-item>
<!-- <p>基础</p> -->
<!-- <el-divider></el-divider> -->
<el-divider content-position="left">基础</el-divider>
<el-divider content-position="left">配置</el-divider>
<el-form-item label="名称">
<el-input v-model="activeComponent.name"></el-input>
</el-form-item>
<el-form-item label="类型">
<el-select v-model="activeComponent.type" placeholder="请选择类型">
<el-option v-for="cmp in componentsMap" :key="cmp.value" :label="cmp.label" :value="cmp.value"></el-option>
</el-select>
</el-form-item>
<el-divider content-position="left">{{activeComponent.properties.groupName}}</el-divider>
<!-- <template v-for=""></template> -->
<template v-for="(p, key) in cmpProps">
<el-form-item v-if="key !== 'groupName'" :id="activeComponent.uuid + '-' + key" :key="activeComponent.uuid + key" :label="p.title">
<!-- {{key}} -->
<dynamic-component :label="key" :item="p" :properties="activeComponent.properties"></dynamic-component>
</el-form-item>
</template>
</el-form>
</div>
<div class="inspec-test" style="word-break: break-all;position: absolute;bottom: 0;font-size: 12px;background-color:#fff; width: 100%;height: 100px;" @click.native="testGetter">
<!-- <div class="inspec-test" style="word-break: break-all;position: absolute;bottom: 0;font-size: 12px;background-color:#fff; width: 100%;height: 100px;" @click.native="testGetter">
{{JSON.stringify(activeComponent.properties)}}
</div>
</div> -->
</pane>
</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex';
import Pane from '../../components/Pane';
import _ from 'lodash';
import properties from '../../utils/properties';
import { componentsMap } from '../../utils/common';
import dynamicComponent from './components/dynamicComponent';
export default {
name: 'Inspector',
components: { Pane },
components: { Pane, 'dynamic-component': dynamicComponent },
data() {
return {
componentsMap
......@@ -45,12 +52,20 @@ export default {
return this.activeComponent.properties;
},
cmpProps: function() {
if (!this.activeComponentId) {
return [];
} else {
let _node = Object.keys(properties.node);
if (!this.activeComponent.type) {
return [];
} else {
let _nodeProps = _.cloneDeep(properties.node); // Object.keys(properties.node) || [];
let _typeProps = {};
if (this.activeComponent.type !== 'node') {
_typeProps = _.cloneDeep(properties[this.activeComponent.type]); // Object.keys(properties[this.activeComponent.type]) || [];
}
}
return {
..._nodeProps,
..._typeProps
};
}
}
},
methods: {
......@@ -66,11 +81,12 @@ export default {
<style lang="scss">
.zero-inspector-form {
width: 100%;
padding-right: 10px;
.el-form-item--mini.el-form-item {
margin-bottom: 10px;
}
.el-divider__text{
background-color: #e9e9e9;
}
}
.el-divider__text {
background-color: #e9e9e9;
}
}
</style>
\ No newline at end of file
<template>
<component :is="componentType" v-model="cmpValue" v-bind="itemProps" @change="v => handleChange(v)" @input="v=>handleInput(v)">
<d-slot
v-for="oitem in itemProps.options"
:is="itemProps.slotComponent"
:key="oitem.value"
:label="oitem.label || oitem.value"
:value="oitem.value"
>
</d-slot>
</component>
</template>
<script>
import swSlider from '../../../components/customSettings/slider';
import swSelect from '../../../components/customSettings/selector';
// 为什么上面template中的 :label要这么写?see :https://github.com/ElemeFE/element/issues/7910
// 判断的有点粗糙
// 是否是uuid,即是否是划入的组件
// function isId(v) {
// return String(v).indexOf('xy-') !== -1 && v.length === 39;
// }
const componentMapper = {
switch: {
component: 'el-switch',
props: {
activeColor: '#13ce66',
inactiveColor: '#eee',
width: 100
}
},
select: {
component: 'el-select',
props: {
slotComponent: 'el-option'
}
},
swSelect: {
component: 'sw-select' // 无需传入options
},
slider: {
component: 'sw-slider'
},
inputNumber: {
component: 'el-input-number',
props: {
size: 'mini'
}
},
input: {
component: 'el-input'
},
colorPicker: {
component: 'el-color-picker',
props: {
'show-alpha': true
}
}
};
export default {
components: {
swSlider,
swSelect
},
props: {
item: {
type: Object,
require: true
},
label: {
type: String,
default: ''
},
properties: {
type: Object,
default: () => {}
}
},
data() {
return {
cmpValue: ''
};
},
mounted() {
let _value = this.properties[this.label];
if (_value === undefined || _value === null) {
_value = this.item.value;
}
this.cmpValue = _value;
console.log('label value:', this.label, this.cmpValue);
},
watch: {
// properties: {
// deep: true,
// handler: function(value) {
// console.log('properties change', value);
// }
// }
},
computed: {
itemComponent() {
return componentMapper[this.item.type] || {};
},
// cmpValue() {
// if (!this.label) {
// return '';
// }
// let _value = this.properties[this.label];
// if (_value === undefined || _value === null) {
// _value = this.item.value;
// }
// return _value;
// },
itemProps() {
let result = {
size: 'mini',
...(this.itemComponent.props || {}),
...this.item.props,
options: this.item.options,
value: this.cmpValue
};
if (this.item.title === '字体大小') {
console.log('itemProps', result);
}
return result;
},
componentType() {
return this.itemComponent.component || this.item.type;
}
},
methods: {
handleChange(v) {
console.log('handleChange', v);
this.$store.dispatch('modifyProperties', {
label: this.label,
value: v
});
// const pathKeys = this.item.pathKeys;
// update fakeValue
// this.fakeValue = v;
// this.$store.dispatch(
// this.$store.getters.isBody() ? 'modifyPageSettings' : 'modifyComponent',
// {
// value: v,
// key: pathKeys.concat('v')
// }
// );
},
handleInput(v) {
if (this.item.type === 'input') {
this.handleChange(v);
}
}
}
};
</script>
......@@ -2,9 +2,9 @@
<vue-draggable-resizable
:minw="1"
:minh="1"
:cmp-id="cmpId"
:z="99"
:otherstatus="true"
:style="styleObject"
:class="[active ? 'choosed-cmp' : 'unchoosed-cmp', isTyping && 'isTyping']"
v-bind="position"
@dragging="handleDragging"
......@@ -26,12 +26,11 @@
<script>
import { getComposedComponents } from '../../../utils/getComposedComponents';
import { styles } from '../../../utils/common';
import properties from '../../../utils/properties';
const composedComponents = getComposedComponents();
console.log('composedComponents', composedComponents);
export default {
props: {
from: {
......@@ -45,7 +44,7 @@ export default {
data() {
return {
composedComponents
}
};
},
methods: {
handleEnableInput() {
......@@ -109,10 +108,8 @@ export default {
// ) {
// return -1;
// }
// const leftKeys = ['bindings', 'outline', 'position', 'left', 'v'];
// const topKeys = ['bindings', 'outline', 'position', 'top', 'v'];
// if (this.$store.state.activeIdList.length > 1) {
// // 多组件移动
// this.$store.dispatch('modifyComponentListPosition', {
......@@ -123,31 +120,24 @@ export default {
// // console.log('active component change---------');
// // 单组件移动
// const id = this.cmpId;
// this.$store.dispatch('activeComponent', id);
// this.$store.dispatch('modifyComponent', {
// key: leftKeys,
// value: left,
// id
// });
// this.$store.dispatch('modifyComponent', {
// key: topKeys,
// value: top,
// id
// });
// }
// return 0;
}
},
computed: {
cmpId() {
return this.componentData.id;
},
active() {
return this.$store.state.project.activeIdList.indexOf(this.cmpId) !== -1
return this.$store.state.project.activeIdList.indexOf(this.cmpId) !== -1;
},
isTyping() {
return this.componentData.editable;
......@@ -157,40 +147,18 @@ export default {
return this.componentData.group === 'text';
},
styleObject() {
return styles.getStyleObject(this.componentData);
return styles.getStyleObject(this.componentData.properties);
},
position() {
const componentData = this.componentData;
console.log('componentData', componentData);
componentData.properties = componentData.properties || {};
const _node = properties.node;
return {
x: componentData.properties.left || 0,
y: componentData.properties.top || 0,
w: componentData.properties.width || 10,
h: componentData.properties.height || 10
}
// return !componentData
// ? {}
// : {
// x: path(
// ['bindings', 'outline', 'position', 'left', 'v'],
// componentData
// ),
// y: path(
// ['bindings', 'outline', 'position', 'top', 'v'],
// componentData
// ),
// w: path(
// ['bindings', 'outline', 'position', 'width', 'v'],
// componentData
// ),
// h: path(
// ['bindings', 'outline', 'position', 'height', 'v'],
// componentData
// )
// };
x: componentData.properties.left || _node.left.value,
y: componentData.properties.top || _node.top.value,
w: componentData.properties.width || _node.width.value,
h: componentData.properties.height || _node.height.value
};
}
}
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment