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

feat: 属性面板

parents f407bbb9 26881ed0
...@@ -7,9 +7,6 @@ ...@@ -7,9 +7,6 @@
</template> </template>
<style> <style>
.zero-custom-text {
font-size: 14px;
}
.zero-custom-text.placeholder:after { .zero-custom-text.placeholder:after {
content: '请输入'; content: '请输入';
font-style: italic; font-style: italic;
......
...@@ -31,13 +31,10 @@ export default { ...@@ -31,13 +31,10 @@ export default {
}, },
data() { data() {
return { return {
selected: '', selected: this.value || '',
optionMapper optionMapper
}; };
}, },
created() {
this.selected = this.value;
},
computed: { computed: {
options() { options() {
return this.optionList || this.optionMapper[this.optionType]; return this.optionList || this.optionMapper[this.optionType];
...@@ -49,10 +46,6 @@ export default { ...@@ -49,10 +46,6 @@ export default {
watch: { watch: {
selected(v) { selected(v) {
this.$emit('change', v); this.$emit('change', v);
},
value(v) {
console.log('selector value change', v);
this.selected = this.value;
} }
} }
}; };
......
<template> <template>
<el-slider class="zero-slider" v-model="swvalue" :min="min" :max="max" :step="step"></el-slider> <el-slider class="zero-slider" v-model="swvalue" :min="min" :max="max" :step="step" show-input :show-input-controls="false" input-size="mini"></el-slider>
</template> </template>
<style> <style>
/* .zero-slider { .el-slider.zero-slider {
width: 180px;
}
.zero-slider .el-slider__runway.show-input {
width: 100px;
}
.zero-slider > .el-slider__input {
width: 60px;
}
/* .zero-slider > .el-slider__input > span {
display: none;
}
.zero-slider > .el-slider__input input {
padding: 0 10px;
} */
/* .zero-slider {
position: relative; position: relative;
} }
.zero-slider > .el-slider__input { .zero-slider > .el-slider__input {
...@@ -11,9 +26,7 @@ ...@@ -11,9 +26,7 @@
top: -250%; top: -250%;
width: 60px; width: 60px;
} }
.zero-slider > .el-slider__input > span {
display: none;
}
.zero-slider > .el-slider__input input { .zero-slider > .el-slider__input input {
padding: 0 10px; padding: 0 10px;
} */ } */
...@@ -28,13 +41,11 @@ export default { ...@@ -28,13 +41,11 @@ export default {
}, },
data() { data() {
return { return {
swvalue: 0 swvalue: this.value || 0
}; };
}, },
created() { mounted() {
console.log('slider created', this.value); console.log('slider created', this.value);
this.swvalue = this.value;
}, },
watch: { watch: {
swvalue(v) { swvalue(v) {
......
<template>
<el-switch v-model="swvalue"></el-switch>
</template>
<style>
</style>
<script>
export default {
props: {
value: [String, Number, Boolean],
},
data() {
return {
swvalue: true
};
},
mounted() {
console.log('switch created', this.swvalue);
},
watch: {
swvalue(v) {
console.log('switch value change', this.swvalue);
this.$emit('change', v);
}
}
};
</script>
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Created by rockyl on 2019-09-19. * Created by rockyl on 2019-09-19.
*/ */
export const API_HOST = 'http://10.10.94.31:7777'; export const API_HOST = 'http://10.10.93.73:7777';
//export const API_HOST = 'http://localhost:3002'; //export const API_HOST = 'http://localhost:3002';
export const UPLOAD_FILE_URL = API_HOST + '/api/uploadFile'; export const UPLOAD_FILE_URL = API_HOST + '/api/uploadFile';
......
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
import Vue from "vue"; import Vue from "vue";
import { projectApi } from "../../api"; import { projectApi } from "../../api";
import { compoleteComponentData } from '../../utils/compoleteCmpData'; // import { compoleteComponentData } from '../../utils/compoleteCmpData';
import path from "path"; import path from "path";
import generateUUID from "uuid/v4"; import generateUUID from "uuid/v4";
import { getCmpProps } from '../../utils/common';
export const projectStore = { export const projectStore = {
state: { state: {
...@@ -44,7 +45,7 @@ export const projectStore = { ...@@ -44,7 +45,7 @@ export const projectStore = {
if (!localData.dataMapping || localData.dataMapping.length === 0) { if (!localData.dataMapping || localData.dataMapping.length === 0) {
Vue.set(localData, 'dataMapping', dataMapping || []); Vue.set(localData, 'dataMapping', dataMapping || []);
} }
}else{ } else {
Vue.set(localData, 'views', []); Vue.set(localData, 'views', []);
Vue.set(localData, 'assets', []); Vue.set(localData, 'assets', []);
Vue.set(localData, 'dataMapping', []); Vue.set(localData, 'dataMapping', []);
...@@ -57,11 +58,6 @@ export const projectStore = { ...@@ -57,11 +58,6 @@ export const projectStore = {
* @param {*} id * @param {*} id
*/ */
activeComponent(state, item) { activeComponent(state, item) {
// todo drag
// if (state.cmpListDragging) {
// state.cmpListDragging = false;
// return;
// }
if (item !== state.activeComponent) { if (item !== state.activeComponent) {
state.activeComponent = item || state.activeComponent; state.activeComponent = item || state.activeComponent;
} }
...@@ -79,9 +75,33 @@ export const projectStore = { ...@@ -79,9 +75,33 @@ export const projectStore = {
if (!data || !data.label) { if (!data || !data.label) {
return; return;
} }
state.activeComponent.properties[data.label] = data.value; // state.activeComponent.properties[data.label] = data.value;
Vue.set(state.activeComponent.properties, data.label, data.value);
console.log('modifyProperties', state.activeComponent); console.log('modifyProperties', state.activeComponent);
},
/**
* 修改当前组件
* @param {*} state
* @param {*} data
*/
modifyComponent(state, data) {
if (!data || !data.label) {
return;
}
Vue.set(state.activeComponent, data.label, data.value);
if (data.label === 'type') {
// 如果修改了组件类型,需要删除无用的属性
let defaultProps = Object.keys(getCmpProps(data.value));
let cmpProps = _.cloneDeep(state.activeComponent.properties);
_.forIn(cmpProps, (value, key, prop) => {
if (defaultProps.indexOf(key) === -1) {
delete prop[key];
}
});
console.log('new properties', cmpProps);
Vue.set(state.activeComponent, 'properties', cmpProps);
}
console.log('modifyComponent', state.activeComponent);
}, },
modifyProject(state, ) { modifyProject(state, ) {
...@@ -90,6 +110,7 @@ export const projectStore = { ...@@ -90,6 +110,7 @@ export const projectStore = {
const child = { const child = {
name, name,
type, type,
uuid: generateUUID(),
}; };
if (node) { if (node) {
if (!node.children) { if (!node.children) {
...@@ -168,15 +189,16 @@ export const projectStore = { ...@@ -168,15 +189,16 @@ export const projectStore = {
* 当前激活的组件 * 当前激活的组件
*/ */
activeComponent: state => { activeComponent: state => {
console.log('activeComponent', state.activeComponent || {}); let _cmp = state.activeComponent || {}
console.log('activeComponent', _cmp);
return { ...(state.activeComponent || {}), uuid: generateUUID() } return { ..._cmp, uuid: _cmp.uuid || generateUUID() }
}, },
/** /**
* 当前激活的组件ID * 当前激活的组件ID
*/ */
activeComponentId: state => { activeComponentId: state => {
return (state.activeComponent || {}).id; return (state.activeComponent || {}).uuid;
}, },
/** /**
* 扁平化所有节点 * 扁平化所有节点
...@@ -243,8 +265,17 @@ export const projectStore = { ...@@ -243,8 +265,17 @@ export const projectStore = {
commit('activeComponent', data); commit('activeComponent', data);
}, },
/**
* 修改属性
*/
modifyProperties({ commit }, data) { modifyProperties({ commit }, data) {
commit('modifyProperties', data) commit('modifyProperties', data)
},
/**
* 修改组件
*/
modifyComponent({ commit }, data) {
commit('modifyComponent', data)
} }
}, },
......
import _ from 'lodash';
import properties from './properties';
export const componentsMap = [{ export const componentsMap = [{
label: '文本', label: '文本',
value: 'label' value: 'label'
...@@ -12,13 +15,127 @@ export const componentsMap = [{ ...@@ -12,13 +15,127 @@ export const componentsMap = [{
value: 'rect' value: 'rect'
}]; }];
const isClient = typeof window !== 'undefined';
function changeCamle(s) {
return s ? s.replace(/([A-Z])/g, '-$1').toLowerCase() : '';
}
function invalidAttr(key, value) {
return !key || typeof value === 'undefined' || value === '';
}
// 属性简称 对照表
const attrShortMapper = {
align: 'text-align',
size: 'font-size',
alpha: 'opacity',
'strokeColor': 'border-color',
'strokeWidth': 'border-width',
'fillColor': 'background-color',
'source': 'background-image'
};
// 属性单位 对照表, 如果是数值的时候需要添加单位
const attrUnitMapper = {
top: 'px',
left: 'px',
width: 'px',
height: 'px',
fontSize: 'px',
size: 'px',
letterSpacing: 'px',
borderRadius: 'px',
borderWidth: 'px',
strokeWidth: 'px',
minHeight: 'px'
};
export const styles = { export const styles = {
getStyles() { getStyles(value, key) {
const attr = attrShortMapper[key] || changeCamle(key);
const unit = attrUnitMapper[key] || '';
if (invalidAttr(key, value)) return '';
switch (attr) {
case 'rotate':
return ['transform', [`rotate(${value}deg)`]]; //`transform: rotate(${value}deg);`;
case 'background-image':
return ['background-image', [`url(${value})`]]; //`background-image: url(${value});background-position:center;background-size:contain;`;
case 'scale-x':
return ['transform', [`scaleX(${value})`]]; //`transform: scaleX(${value});`;
case 'scale-y':
return ['transform', [`scaleY(${value})`]]; //`transform: scaleY(${value});`;
case 'visible':
return ['display', [value ? 'block' : 'none']]; // `display: ${value ? 'block' : 'none'};`;
default:
return [attr, [`${value}${Number.isNaN(value) ? '' : unit}`]]; //`${attr}:${value}${Number.isNaN(value) ? '' : unit};`;
}
},
/**
* 根据Object类型的属性对象,生成dom中style属性可用的数据格式
* @param {*} obj
*/
getStylesFromObj(obj) {
let resultObj = {};
_.forIn(obj, (value, key) => {
let _style = styles.getStyles(value, key);
if (!_style) {
return;
}
if (resultObj[_style[0]]) {
resultObj[_style[0]] = resultObj[_style[0]].concat(_style[1]);
} else {
resultObj[_style[0]] = _style[1];
}
});
return resultObj;
}, },
getStyleObject(properties) { /**
console.log('getStyleObject', properties); * 根据组件数据,生成完整的style
* @param {*} component
*/
getComponentStyle(component) {
let result = '';
// 根据组件类型,获取默认属性
let defaultProps = getCmpProps(component.type);
defaultProps = _.omit(defaultProps, _.keys(component.properties));
defaultProps = _.mapValues(defaultProps, o => (o.value));
let _cmpProps = styles.getStylesFromObj(component.properties);
let _defaultProps = styles.getStylesFromObj(defaultProps);
_.forIn({
..._defaultProps,
..._cmpProps
}, (value, key) => {
result += `${key}: ${value.join(' ')};`
});
result += `background-position: center;background-size: contain;`
console.log('getComponentStyle', result);
return result;
}
}
export const getCmpProps = function (type) {
if (!type) {
return {} return {}
} else {
let _nodeProps = _.cloneDeep(properties.node);
let _typeProps = {};
if (type !== 'node') {
_typeProps = _.cloneDeep(properties[type]);
}
let result = {
..._nodeProps,
..._typeProps
};
delete result.groupName;
return result
} }
} }
\ No newline at end of file
...@@ -7,17 +7,17 @@ const composedComponents = getComposedComponents(); ...@@ -7,17 +7,17 @@ const composedComponents = getComposedComponents();
export const compoleteComponentData = (views) => { export const compoleteComponentData = (views) => {
views.forEach(view => { views.forEach(view => {
view.id = view.id || guid(); view.uuid = view.uuid || guid();
let _composedCmp = composedComponents[view.type]; // let _composedCmp = composedComponents[view.type];
view.component = _composedCmp.component.default; // view.component = _composedCmp.component.default;
let _composedProps = _.cloneDeep(_composedCmp.properties); // 组件预设的属性,Object类型 // let _composedProps = _.cloneDeep(_composedCmp.properties); // 组件预设的属性,Object类型
let _viewProps = view.properties || {}; // 组件对象的具体属性,key:value // let _viewProps = view.properties || {}; // 组件对象的具体属性,key:value
let _keys = Object.keys(_viewProps); // let _keys = Object.keys(_viewProps);
_keys.forEach(k => { // _keys.forEach(k => {
_composedProps[k].value = _viewProps[k] // _composedProps[k].value = _viewProps[k]
}); // });
view.properties = _composedProps; // view.properties = _composedProps;
if (view.children) { if (view.children) {
compoleteComponentData(view.children); compoleteComponentData(view.children);
......
<template> <template>
<pane icon="el-icon-s-operation" :title="$t('panes.Inspector')"> <pane icon="el-icon-s-operation" :title="$t('panes.Inspector')">
<div class="zero-inspector-form"> <div class="zero-inspector-form">
<el-form ref="form" size="mini" v-if="activeComponent.name" :model="activeComponent.properties" label-width="80px"> <el-form ref="form" size="mini" v-if="activeComponent.name" :model="form" label-width="80px">
<el-form-item > <el-form-item >
<el-button @click="testGetter">test</el-button> <el-button @click="testGetter">test</el-button>
</el-form-item> </el-form-item>
<el-divider content-position="left">配置</el-divider> <el-divider content-position="left">配置</el-divider>
<el-form-item label="名称"> <el-form-item label="名称">
<el-input v-model="activeComponent.name"></el-input> <el-input v-model="form.name" @input="v => handleChange('name', v)"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="类型"> <el-form-item label="类型">
<el-select v-model="activeComponent.type" placeholder="请选择类型"> <el-select v-model="form.type" @change="v => handleChange('type', v)" placeholder="请选择类型">
<el-option v-for="cmp in componentsMap" :key="cmp.value" :label="cmp.label" :value="cmp.value"></el-option> <el-option v-for="cmp in componentsMap" :key="cmp.value" :label="cmp.label" :value="cmp.value"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
...@@ -22,9 +22,6 @@ ...@@ -22,9 +22,6 @@
</template> </template>
</el-form> </el-form>
</div> </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">
{{JSON.stringify(activeComponent.properties)}}
</div> -->
</pane> </pane>
</template> </template>
...@@ -32,8 +29,7 @@ ...@@ -32,8 +29,7 @@
import { mapState, mapActions, mapGetters } from 'vuex'; import { mapState, mapActions, mapGetters } from 'vuex';
import Pane from '../../components/Pane'; import Pane from '../../components/Pane';
import _ from 'lodash'; import _ from 'lodash';
import properties from '../../utils/properties'; import { componentsMap, getCmpProps } from '../../utils/common';
import { componentsMap } from '../../utils/common';
import dynamicComponent from './components/dynamicComponent'; import dynamicComponent from './components/dynamicComponent';
export default { export default {
...@@ -41,30 +37,27 @@ export default { ...@@ -41,30 +37,27 @@ export default {
components: { Pane, 'dynamic-component': dynamicComponent }, components: { Pane, 'dynamic-component': dynamicComponent },
data() { data() {
return { return {
componentsMap componentsMap,
form: {
name: '',
type: '',
properties: {}
}
}; };
}, },
computed: { computed: {
...mapGetters(['activeComponent', 'activeComponentId']), ...mapGetters(['activeComponent', 'componentList']),
form: function() {
console.log(this.activeComponent.properties);
return this.activeComponent.properties;
},
cmpProps: function() { cmpProps: function() {
if (!this.activeComponent.type) { return getCmpProps(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 { watch: {
..._nodeProps, activeComponent: {
..._typeProps deep: true,
}; handler: function(val) {
this.form.name = val.name || '';
this.form.type = val.type || '';
this.form.properties = val.properties || {};
} }
} }
}, },
...@@ -72,7 +65,13 @@ export default { ...@@ -72,7 +65,13 @@ export default {
testGetter() { testGetter() {
console.log(this.$store); console.log(this.$store);
console.log('testGetter', this.activeComponentId, this.activeComponent); console.log('testGetter', JSON.stringify(this.$store.state.project.data));
},
handleChange(label, v) {
this.$store.dispatch('modifyComponent', {
label: label,
value: v
});
} }
} }
}; };
......
<template> <template>
<component :is="componentType" v-model="cmpValue" v-bind="itemProps" @change="v => handleChange(v)" @input="v=>handleInput(v)"> <component v-if="cmpValue !== null" :is="componentType" v-model="cmpValue" v-bind="itemProps" @change="v => handleChange(v)" @input="v=>handleInput(v)">
<d-slot <d-slot
v-for="oitem in itemProps.options" v-for="oitem in itemProps.options"
:is="itemProps.slotComponent" :is="itemProps.slotComponent"
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
<script> <script>
import swSlider from '../../../components/customSettings/slider'; import swSlider from '../../../components/customSettings/slider';
import swSelect from '../../../components/customSettings/selector'; import swSelect from '../../../components/customSettings/selector';
// 为什么上面template中的 :label要这么写?see :https://github.com/ElemeFE/element/issues/7910 // 为什么上面template中的 :label要这么写?see :https://github.com/ElemeFE/element/issues/7910
// 判断的有点粗糙 // 判断的有点粗糙
...@@ -80,7 +81,7 @@ export default { ...@@ -80,7 +81,7 @@ export default {
}, },
data() { data() {
return { return {
cmpValue: '' cmpValue: null
}; };
}, },
mounted() { mounted() {
...@@ -88,43 +89,28 @@ export default { ...@@ -88,43 +89,28 @@ export default {
if (_value === undefined || _value === null) { if (_value === undefined || _value === null) {
_value = this.item.value; _value = this.item.value;
} }
// console.log('dynamic mounted', this.label, _value);
this.cmpValue = _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: { computed: {
itemComponent() { itemComponent() {
return componentMapper[this.item.type] || {}; 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() { itemProps() {
let _value = this.properties[this.label];
if (_value === undefined || _value === null) {
_value = this.item.value;
}
let result = { let result = {
size: 'mini', size: 'mini',
...(this.itemComponent.props || {}), ...(this.itemComponent.props || {}),
...this.item.props, ...this.item.props,
options: this.item.options, options: this.item.options || {}
value: this.cmpValue // value: _value
}; };
if (this.item.title === '字体大小') { // console.log('itemProps', this.componentType, this.label, result);
console.log('itemProps', result);
}
return result; return result;
}, },
componentType() { componentType() {
...@@ -138,18 +124,6 @@ export default { ...@@ -138,18 +124,6 @@ export default {
label: this.label, label: this.label,
value: v 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) { handleInput(v) {
if (this.item.type === 'input') { if (this.item.type === 'input') {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex';
import { getComposedComponents } from '../../../utils/getComposedComponents'; import { getComposedComponents } from '../../../utils/getComposedComponents';
import { styles } from '../../../utils/common'; import { styles } from '../../../utils/common';
import properties from '../../../utils/properties'; import properties from '../../../utils/properties';
...@@ -136,8 +137,12 @@ export default { ...@@ -136,8 +137,12 @@ export default {
} }
}, },
computed: { computed: {
...mapGetters(['activeComponentId']),
active() { active() {
return this.$store.state.project.activeIdList.indexOf(this.cmpId) !== -1; // todo
console.log('active', this.componentData);
return this.activeComponentId === (this.componentData || {}).uuid;
}, },
isTyping() { isTyping() {
return this.componentData.editable; return this.componentData.editable;
...@@ -147,7 +152,9 @@ export default { ...@@ -147,7 +152,9 @@ export default {
return this.componentData.group === 'text'; return this.componentData.group === 'text';
}, },
styleObject() { styleObject() {
return styles.getStyleObject(this.componentData.properties); console.log('wrapper styleObject');
return styles.getComponentStyle(this.componentData);
}, },
position() { position() {
const componentData = this.componentData; const componentData = this.componentData;
...@@ -160,6 +167,15 @@ export default { ...@@ -160,6 +167,15 @@ export default {
h: componentData.properties.height || _node.height.value h: componentData.properties.height || _node.height.value
}; };
} }
},
watch: {
componentData: {
deep: true,
handler: function(v) {
console.log('wrapper componentData change', v);
}
}
} }
}; };
</script> </script>
......
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