Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Z
zeroing-editor
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
劳工
zeroing-editor
Commits
d5e2284c
Commit
d5e2284c
authored
Sep 25, 2019
by
张晨辰
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 视图编辑面板
parent
1dc2e5de
Changes
24
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
941 additions
and
59 deletions
+941
-59
package.json
package.json
+1
-0
index.js
src/components/customElement/image/index.js
+15
-0
index.vue
src/components/customElement/image/index.vue
+22
-0
index.js
src/components/customElement/label/index.js
+15
-0
index.vue
src/components/customElement/label/index.vue
+51
-0
index.js
src/components/customElement/node/index.js
+14
-0
index.vue
src/components/customElement/node/index.vue
+18
-0
index.js
src/components/customElement/rect/index.js
+15
-0
index.vue
src/components/customElement/rect/index.vue
+52
-0
config.js
src/config.js
+0
-4
main.js
src/main.js
+3
-0
project.js
src/store/modules/project.js
+140
-21
index.scss
src/themes/light/index.scss
+1
-0
playground.scss
src/themes/light/playground.scss
+57
-0
utils.js
src/utils.js
+14
-1
compoleteCmpData.js
src/utils/compoleteCmpData.js
+25
-0
getComposedComponents.js
src/utils/getComposedComponents.js
+21
-0
index.js
src/utils/index.js
+41
-0
properties.js
src/utils/properties.js
+111
-0
Inspector.vue
src/views/Editor/Inspector.vue
+24
-6
Playground.vue
src/views/Editor/Playground.vue
+11
-7
Views.vue
src/views/Editor/Views.vue
+29
-20
drawPanel.vue
src/views/Editor/components/drawPanel.vue
+42
-0
wrapper.vue
src/views/Editor/components/wrapper.vue
+219
-0
No files found.
package.json
View file @
d5e2284c
...
...
@@ -9,6 +9,7 @@
"dependencies"
:
{
"
cookie
"
:
"
^0.4.0
"
,
"
core-js
"
:
"
^2.6.5
"
,
"
duiba-draggable-resizable
"
:
"
^1.0.9
"
,
"
element-ui
"
:
"
^2.4.5
"
,
"
moment
"
:
"
^2.24.0
"
,
"
path
"
:
"
^0.12.7
"
,
...
...
src/components/customElement/image/index.js
0 → 100644
View file @
d5e2284c
// import { set, lensPath } from 'ramda';
import
properties
from
'../../../utils/properties'
;
export
default
{
component
:
require
(
'./index.vue'
),
properties
:
{
...
properties
().
node
,
...
properties
().
image
},
props
:
{
type
:
'image'
},
title
:
'image'
};
src/components/customElement/image/index.vue
0 → 100644
View file @
d5e2284c
<
template
>
<div
class=
"zero-custom-picture"
:style=
"`background-image:url($
{properties.source.value}); background-size: contain;`">
</div>
</
template
>
<
style
>
.zero-custom-picture
{
height
:
100%
;
background-position
:
center
;
}
</
style
>
<
script
>
export
default
{
name
:
'customImage'
,
props
:
{
properties
:
{
type
:
Object
,
default
:
()
=>
{}
}
}
};
</
script
>
src/components/customElement/label/index.js
0 → 100644
View file @
d5e2284c
// import { set, lensPath } from 'ramda';
import
properties
from
'../../../utils/properties'
;
export
default
{
component
:
require
(
'./index.vue'
),
properties
:
{
...
properties
().
node
,
...
properties
().
label
},
props
:
{
type
:
'label'
},
title
:
'label'
};
src/components/customElement/label/index.vue
0 → 100644
View file @
d5e2284c
<
template
>
<div
class=
"zero-custom-text"
:class=
"showPlaceholder && 'placeholder'"
v-html=
"addNBSP + selfText"
></div>
</
template
>
<
style
>
.zero-custom-text
{
font-size
:
14px
;
}
.zero-custom-text.placeholder
:after
{
content
:
'请输入'
;
font-style
:
italic
;
font-size
:
12px
;
}
</
style
>
<
script
>
export
default
{
name
:
'customLabel'
,
props
:
{
properties
:
{
type
:
Object
,
default
:
()
=>
{}
},
isTyping
:
Boolean
},
data
()
{
return
{
selfText
:
'文字'
};
},
computed
:
{
showPlaceholder
()
{
return
(
!
this
.
isTyping
&&
typeof
this
.
properties
.
text
.
value
!==
'undefined'
&&
!
this
.
properties
.
text
.
value
.
replace
(
/
\s
|
(
)
/g
,
''
)
);
},
addNBSP
()
{
return
this
.
selfText
.
replace
(
/
\s
/g
,
''
)
?
''
:
' '
;
}
},
created
()
{
this
.
selfText
=
this
.
properties
.
text
.
value
||
this
.
selfText
;
}
};
</
script
>
src/components/customElement/node/index.js
0 → 100644
View file @
d5e2284c
// import { set, lensPath } from 'ramda';
import
properties
from
'../../../utils/properties'
;
export
default
{
component
:
require
(
'./index.vue'
),
properties
:
{
...
properties
().
node
},
props
:
{
type
:
'node'
},
title
:
'node'
};
src/components/customElement/node/index.vue
0 → 100644
View file @
d5e2284c
<
template
>
<div
class=
"zero-custom-cmp zero-custom-node"
></div>
</
template
>
<
style
>
</
style
>
<
script
>
export
default
{
name
:
'customNode'
,
props
:
{
properties
:
{
type
:
Object
,
default
:
()
=>
{}
}
}
};
</
script
>
src/components/customElement/rect/index.js
0 → 100644
View file @
d5e2284c
// import { set, lensPath } from 'ramda';
import
properties
from
'../../../utils/properties'
;
export
default
{
component
:
require
(
'./index.vue'
),
properties
:
{
...
properties
().
node
,
...
properties
().
rect
},
props
:
{
type
:
'rect'
},
title
:
'rect'
};
src/components/customElement/rect/index.vue
0 → 100644
View file @
d5e2284c
<
template
>
<div
class=
"zero-custom-shape-rect-blue"
:style=
"`background-color: $
{properties.fillColor.value};border-width: ${properties.strokeWidth.value}px; border-color: ${properties.strokeColor.value};`">
</div>
</
template
>
<
style
>
.zero-custom-shape-rect-blue
{
background-color
:
#5396da
;
height
:
100%
;
}
</
style
>
<
script
>
export
default
{
name
:
'customRect'
,
props
:
{
properties
:
{
type
:
Object
,
default
:
()
=>
{}
}
// fillColor: {
// type: Object,
// default: () => {
// return {
// title: '填充色',
// type: 'colorPicker',
// value: '#fff'
// };
// }
// },
// strokeColor: {
// type: Object,
// default: () => {
// return {
// title: '边框颜色',
// type: 'colorPicker',
// value: '#000'
// };
// }
// },
// strokeWidth: {
// type: Object,
// default: () => {
// return {
// title: '边框宽度',
// type: 'inputNumber',
// value: 1
// };
// }
// }
}
};
</
script
>
src/config.js
View file @
d5e2284c
...
...
@@ -3,11 +3,7 @@
*/
export
const
API_HOST
=
'http://10.10.94.31:7777'
;
<<<<<<<
Updated
upstream
//export const API_HOST = 'http://localhost:3002';
=======
// export const API_HOST = 'http://localhost:3002';
>>>>>>>
Stashed
changes
export
const
ASSETS_BASE
=
'http://0.0.0.0:4002/assets'
;
//文件类型图标 t表示展示缩略图
...
...
src/main.js
View file @
d5e2284c
...
...
@@ -10,6 +10,9 @@ import './assets/style.css'
import
'./plugins/element.js'
import
'./themes/light/index.scss'
import
VueDraggableResizable
from
'duiba-draggable-resizable'
;
Vue
.
component
(
'vue-draggable-resizable'
,
VueDraggableResizable
);
new
Vue
({
router
,
store
,
...
...
src/store/modules/project.js
View file @
d5e2284c
...
...
@@ -3,6 +3,74 @@
*/
import
{
projectApi
}
from
"../../api"
;
import
{
compoleteComponentData
}
from
'../../utils/compoleteCmpData'
;
let
testData
=
{
views
:
[{
name
:
'视图1'
,
type
:
'node'
,
children
:
[{
name
:
'image'
,
type
:
'image'
,
properties
:
{
width
:
100
,
height
:
100
,
left
:
1
,
top
:
1
,
source
:
'http://yun.duiba.com.cn/images/201909/ogzik0c3hk.png'
}
},
{
name
:
'label'
,
type
:
'label'
,
properties
:
{
width
:
110
,
height
:
110
,
left
:
100
,
top
:
100
,
text
:
'textlabel'
,
color
:
'#fff'
,
size
:
12
,
align
:
'left'
}
},
{
name
:
'rect'
,
type
:
'rect'
,
properties
:
{
fillColor
:
'#fff'
,
strokeColor
:
'#000'
,
strokeWidth
:
1
,
width
:
120
,
height
:
120
,
left
:
200
,
top
:
200
},
children
:
[{
name
:
'label2'
,
type
:
'label'
,
properties
:
{
text
:
'textlabel2'
,
color
:
'#fff'
,
size
:
12
,
align
:
'left'
,
width
:
130
,
height
:
130
,
left
:
300
,
top
:
300
}
}]
}]
}]
}
// let testData = {
// views: [{
// name: 'rect',
// type: 'rect',
// properties: {
// fillColor: '#fff',
// strokeColor: '#000',
// strokeWidth: 1
// }
// }]
// }
export
const
projectStore
=
{
state
:
{
...
...
@@ -10,57 +78,108 @@ export const projectStore = {
name
:
''
,
creator
:
''
,
data
:
{
views
:
[
{
name
:
'body'
,
children
:
[]
}
],
views
:
[],
assets
:
[],
dataMapping
:
[],
}
},
activeComponent
:
{},
activeIdList
:
[]
},
mutations
:
{
/**
* 更新state中的data
* @param {*} state
* @param {*} project
*/
updateProject
(
state
,
project
)
{
const
{
id
,
name
,
creator
,
data
}
=
project
;
const
{
id
,
name
,
creator
,
data
}
=
project
;
state
.
id
=
id
;
state
.
name
=
name
;
state
.
creator
=
creator
;
if
(
data
)
{
if
(
data
)
{
const
localData
=
state
.
data
;
const
{
views
,
assets
,
dataMapping
}
=
JSON
.
parse
(
data
);
if
(
!
localData
.
views
||
localData
.
views
.
length
===
0
)
{
const
{
views
,
assets
,
dataMapping
}
=
JSON
.
parse
(
data
);
if
(
!
localData
.
views
||
localData
.
views
.
length
===
0
)
{
localData
.
views
=
views
||
[];
}
if
(
!
localData
.
assets
||
localData
.
assets
.
length
===
0
)
{
if
(
!
localData
.
assets
||
localData
.
assets
.
length
===
0
)
{
localData
.
assets
=
assets
||
[];
}
if
(
!
localData
.
dataMapping
||
localData
.
dataMapping
.
length
===
0
)
{
if
(
!
localData
.
dataMapping
||
localData
.
dataMapping
.
length
===
0
)
{
localData
.
dataMapping
=
dataMapping
||
[];
};
}
else
{
state
.
data
.
views
=
testData
.
views
;
}
compoleteComponentData
(
state
.
data
.
views
);
},
createView
(
state
)
{
state
.
data
.
views
.
push
({
name
:
'未命名'
,
children
:
[]
})
console
.
log
(
state
.
data
.
views
);
/**
* 激活组件
* @param {*} state
* @param {*} id
*/
activeComponent
(
state
,
id
)
{
// todo drag
// if (state.cmpListDragging) {
// state.cmpListDragging = false;
// return;
// }
if
(
id
!==
state
.
activeComponent
.
id
)
{
const
_active
=
this
.
getters
.
componentList
.
find
(
cmp
=>
cmp
.
id
===
id
);
state
.
activeComponent
=
_active
||
state
.
activeComponent
;
}
state
.
activeComponent
=
id
;
state
.
activeIdList
=
[
id
];
console
.
log
(
'mutations activeComponent'
,
state
);
}
},
getters
:
{
views
:
state
=>
{
return
state
.
views
/**
* 当前激活的组件
*/
activeComponent
:
state
=>
{
return
state
.
activeComponent
||
{}
},
/**
* 当前激活的组件ID
*/
activeComponentId
:
state
=>
{
return
(
state
.
activeComponent
||
{}).
id
;
},
/**
* 扁平化所有节点
*/
componentList
:
state
=>
{
const
flatten
=
arr
=>
{
return
arr
.
reduce
((
flat
,
toFlat
)
=>
{
return
flat
.
concat
(
toFlat
.
children
?
flatten
(
toFlat
.
children
).
concat
([
toFlat
])
:
[
toFlat
]);
},
[]);
};
let
result
=
flatten
(
state
.
data
.
views
).
map
(
v
=>
{
delete
v
.
children
;
return
v
;
});
// let result = state.data.views.flatMap(v => [v, v.children || []])
console
.
log
(
'componentList'
,
result
);
return
result
;
}
},
actions
:
{
async
updateProject
({
commit
},
projectID
)
{
async
updateProject
({
commit
},
projectID
)
{
const
project
=
await
projectApi
.
getData
(
projectID
);
commit
(
'updateProject'
,
project
);
},
/**
* 新建视图
* 选中节点
* @param {*} param0
* @param {*} data
*/
async
createView
({
commit
})
{
commit
(
'createView'
);
activeComponent
({
commit
},
data
)
{
console
.
log
(
'actions activeComponent'
,
data
);
commit
(
'activeComponent'
,
data
);
}
},
};
src/themes/light/index.scss
View file @
d5e2284c
...
...
@@ -6,6 +6,7 @@
@import
"./base.scss"
;
@import
"./home.scss"
;
@import
"./editor.scss"
;
@import
"./playground.scss"
;
@import
"~element-ui/packages/theme-chalk/src/index.scss"
;
...
...
src/themes/light/playground.scss
0 → 100644
View file @
d5e2284c
.zero-playground-body-center
{
position
:
relative
;
width
:
375px
;
margin
:
10px
auto
;
height
:
100%
;
max-height
:
600px
;
background-color
:
transparent
;
box-shadow
:
0
0
10px
rgba
(
0
,
0
,
0
,
0
.4
);
overflow
:
hidden
;
}
.zero-playground-draw-panel
{
height
:
600px
;
background
:
url(data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAiUlEQVQ4jZ1TSxLFIAhLOp7C+19NjyFvlQ7lUUvLRgXzgVGOMQyb6L3/5cwMJAEAxw6sy3FP8tw/EkhJqp7klQMBtKpWcpC1oVp7IoiqviXg4xBFRPL7EM/6WsviYDxwzrkVaBHsz5U4MlWfKxHEySpXIdk6qLRzcXBHVnKQfZRKCy1Ty979XfwApOBe0rB0KiIAAAAASUVORK5CYII=)
;
background-repeat
:
repeat
;
overflow-y
:
auto
;
overflow-x
:
hidden
;
}
.zero-draw-panel-container
{
position
:
relative
;
// border: 5px #000 solid;
width
:
375px
;
// 谨慎修改,要和drawPanel宽度保持一致
min-height
:
600px
;
}
.zero-draw-panel-container.scroll
{
height
:
1200px
;
}
/* 重置background相关属性*/
.zero-draw-panel-container
*
{
background-repeat
:
no-repeat
;
}
.zero-draw-panel-body
{
position
:
absolute
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
z-index
:
1
;
background
:
transparent
;
}
.zero-components-container
{
width
:
100%
;
height
:
100%
;
}
.zero-components-container.playingAnime
{
position
:
absolute
;
z-index
:
2
;
}
.zero-custom-wrapper
{
position
:
absolute
;
cursor
:
default
;
user-select
:
none
;
}
.active
{
border
:
2px
dashed
rgb
(
20
,
100
,
206
);
}
src/utils.js
View file @
d5e2284c
...
...
@@ -2,7 +2,7 @@
* Created by rockyl on 2019-09-19.
*/
import
{
Message
,
Loading
}
from
"element-ui"
;
import
{
Message
,
Loading
}
from
"element-ui"
;
import
i18n
from
'./i18n'
export
function
messageError
(
e
)
{
...
...
@@ -26,3 +26,16 @@ export function playWaiting(promise, text) {
loading
.
close
();
})
}
export
function
guid
()
{
function
s4
()
{
return
Math
.
floor
((
1
+
Math
.
random
())
*
0x10000
)
.
toString
(
16
)
.
substring
(
1
);
}
// querySelector method uses CSS3 selectors for querying the DOM and CSS3
// doesn't support ID selectors that start with a digit
// for more:
// https://stackoverflow.com/questions/37270787/uncaught-syntaxerror-failed-to-execute-queryselector-on-document
return
`xy-
${
s4
()}${
s4
()}
-
${
s4
()}
-
${
s4
()}
-
${
s4
()}
-
${
s4
()}${
s4
()}${
s4
()}
`
;
}
src/utils/compoleteCmpData.js
0 → 100644
View file @
d5e2284c
import
{
guid
}
from
'./index'
;
import
{
getComposedComponents
}
from
'./getComposedComponents'
;
const
composedComponents
=
getComposedComponents
();
export
const
compoleteComponentData
=
(
views
)
=>
{
views
.
forEach
(
view
=>
{
view
.
id
=
view
.
id
||
guid
();
let
_composedCmp
=
composedComponents
[
view
.
type
];
view
.
component
=
_composedCmp
.
component
.
default
;
let
_composedProps
=
{...
_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
;
if
(
view
.
children
)
{
compoleteComponentData
(
view
.
children
);
}
});
}
\ No newline at end of file
src/utils/getComposedComponents.js
0 → 100644
View file @
d5e2284c
export
const
getComposedComponents
=
()
=>
{
// 去中心化;
const
context
=
require
.
context
(
'../components/customElement'
,
true
,
/index
\.
js$/
);
const
composedComponents
=
{};
context
.
keys
().
forEach
((
key
)
=>
{
const
componentName
=
key
.
slice
(
2
,
-
9
);
const
component
=
context
(
key
);
composedComponents
[
componentName
]
=
component
.
default
;
});
console
.
log
(
'composedComponents'
,
composedComponents
);
return
composedComponents
;
}
src/utils/index.js
0 → 100644
View file @
d5e2284c
/**
* Created by rockyl on 2019-09-19.
*/
import
{
Message
,
Loading
}
from
"element-ui"
;
import
i18n
from
'../i18n'
export
function
messageError
(
e
)
{
Message
({
dangerouslyUseHTMLString
:
true
,
message
:
`<p style="margin-bottom: 5px;"><strong>
${
i18n
.
t
(
e
.
message
)}
</strong></p><p>
${
e
.
name
}
</p>`
,
type
:
'error'
})
}
export
function
playWaiting
(
promise
,
text
)
{
const
loading
=
Loading
.
service
({
lock
:
true
,
text
:
text
||
i18n
.
t
(
'In processing'
),
});
return
promise
.
catch
(
e
=>
{
messageError
(
e
);
throw
e
;
}).
finally
(()
=>
{
loading
.
close
();
})
}
export
function
guid
()
{
function
s4
()
{
return
Math
.
floor
((
1
+
Math
.
random
())
*
0x10000
)
.
toString
(
16
)
.
substring
(
1
);
}
// querySelector method uses CSS3 selectors for querying the DOM and CSS3
// doesn't support ID selectors that start with a digit
// for more:
// https://stackoverflow.com/questions/37270787/uncaught-syntaxerror-failed-to-execute-queryselector-on-document
return
`xy-
${
s4
()}${
s4
()}
-
${
s4
()}
-
${
s4
()}
-
${
s4
()}
-
${
s4
()}${
s4
()}${
s4
()}
`
;
}
src/utils/properties.js
0 → 100644
View file @
d5e2284c
// 属性
export
default
()
=>
({
node
:
{
groupName
:
'基础'
,
left
:
{
title
:
'X坐标'
,
type
:
'inputNumber'
,
value
:
50
},
top
:
{
title
:
'Y坐标'
,
type
:
'inputNumber'
,
value
:
50
},
width
:
{
title
:
'宽度'
,
type
:
'inputNumber'
,
value
:
100
},
height
:
{
title
:
'高度'
,
type
:
'inputNumber'
,
value
:
50
},
rotate
:
{
title
:
'旋转'
,
type
:
'slider'
,
props
:
{
min
:
-
180
,
max
:
180
},
value
:
0
},
scaleX
:
{
title
:
'X轴缩放'
,
type
:
'inputNumber'
,
value
:
1
},
scaleY
:
{
title
:
'Y轴缩放'
,
type
:
'inputNumber'
,
value
:
1
},
visible
:
{
title
:
'是否可见'
,
type
:
'switch'
,
value
:
true
}
},
label
:
{
groupName
:
'文本'
,
text
:
{
title
:
'文本内容'
,
type
:
'input'
,
value
:
''
},
color
:
{
title
:
'颜色'
,
type
:
'colorPicker'
,
value
:
'#fff'
},
size
:
{
title
:
'字体大小'
,
type
:
'swSelect'
,
props
:
{
optionType
:
'fontSize'
},
value
:
12
},
align
:
{
title
:
'文本对齐'
,
type
:
'select'
,
options
:
[
{
label
:
'靠左'
,
value
:
'left'
},
{
label
:
'居中'
,
value
:
'center'
},
{
label
:
'靠右'
,
value
:
'right'
}
],
value
:
'left'
}
},
image
:
{
groupName
:
'来源'
,
source
:
{
title
:
'来源'
,
type
:
'source'
,
value
:
''
}
},
rect
:
{
groupName
:
'形状'
,
fillColor
:
{
title
:
'填充色'
,
type
:
'colorPicker'
,
value
:
'#fff'
},
strokeColor
:
{
title
:
'边框颜色'
,
type
:
'colorPicker'
,
value
:
'#000'
},
strokeWidth
:
{
title
:
'边框宽度'
,
type
:
'inputNumber'
,
value
:
1
,
props
:
{
min
:
0
}
}
}
});
src/views/Editor/Inspector.vue
View file @
d5e2284c
<
template
>
<pane
icon=
"el-icon-s-operation"
:title=
"$t('panes.Inspector')"
>
<div
class=
"inspec-test"
style=
"background-color:#fff; width: 100%;height: 100px;"
@
click
.
native=
"testGetter"
>
{{
JSON
.
stringify
(
activeComponent
.
properties
)
}}
</div>
<el-button
@
click=
"testGetter"
>
默认按钮
</el-button>
</pane>
</
template
>
<
script
>
import
Pane
from
"../../components/Pane"
;
export
default
{
name
:
"Inspector"
,
components
:
{
Pane
}
import
{
mapState
,
mapActions
,
mapGetters
}
from
'vuex'
;
import
Pane
from
'../../components/Pane'
;
export
default
{
name
:
'Inspector'
,
components
:
{
Pane
},
computed
:
{
...
mapGetters
([
'activeComponent'
])
},
methods
:
{
testGetter
()
{
console
.
log
(
'testGetter'
,
this
.
activeComponent
);
debugger
;
this
.
$store
;
debugger
;
}
}
};
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/Playground.vue
View file @
d5e2284c
<
template
>
<pane
icon=
"el-icon-s-open"
:title=
"$t('panes.Playground')"
>
<div
class=
"zero-playground-body-center"
>
<div
class=
"zero-playground-draw-panel"
>
<draw-panel></draw-panel>
</div>
</div>
</pane>
</
template
>
<
script
>
import
Pane
from
"../../components/Pane"
;
export
default
{
name
:
"Playground"
,
components
:
{
Pane
}
}
import
Pane
from
'../../components/Pane'
;
import
DrawPanel
from
'./components/drawPanel'
;
export
default
{
name
:
'Playground'
,
components
:
{
Pane
,
DrawPanel
}
};
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/Views.vue
View file @
d5e2284c
...
...
@@ -11,6 +11,8 @@
:props=
"defaultProps"
:expand-on-click-node=
"false"
highlight-current
:default-expand-all=
"true"
@
node-click=
"handleNodeClick"
empty-text=
""
/>
</el-scrollbar>
...
...
@@ -19,28 +21,35 @@
</
template
>
<
script
>
import
{
mapState
,
mapActions
}
from
'vuex'
import
Pane
from
"../../components/Pane"
;
import
{
mapState
,
mapActions
}
from
'vuex'
;
import
Pane
from
'../../components/Pane'
;
export
default
{
name
:
"Views"
,
components
:
{
Pane
},
data
()
{
return
{
defaultProps
:
{
children
:
'children'
,
label
:
'name'
},
}
},
computed
:
{
...
mapState
({
views
:
state
=>
state
.
project
.
data
.
views
}),
}
}
export
default
{
name
:
'Views'
,
components
:
{
Pane
},
data
()
{
return
{
defaultProps
:
{
children
:
'children'
,
label
:
'name'
}
};
},
computed
:
{
...
mapState
({
views
:
state
=>
state
.
project
.
data
.
views
})
},
methods
:
{
/**
* 点击左侧视图列表
*/
handleNodeClick
(
data
)
{
this
.
$store
.
commit
(
'activeComponent'
,
data
);
}
}
};
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/components/drawPanel.vue
0 → 100644
View file @
d5e2284c
<
template
>
<div
class=
"zero-draw-panel-container"
>
<div
class=
"zero-components-container"
>
<div
v-if=
"item.id"
:key=
"item.id"
:id=
"item.id"
v-for=
"item in componentList"
@
click
.
exact=
"activeComponent(item.id)"
@
click
.
shift
.
exact=
"changeActiveIdList(item.id)"
@
contextmenu
.
prevent=
"activeComponent(item.id)"
>
<wrapper
:component-data=
"item"
/>
</div>
</div>
<div
class=
"zero-draw-panel-body"
></div>
</div>
</
template
>
<
style
lang=
"less"
>
</
style
>
<
script
>
import
{
mapState
,
mapActions
,
mapGetters
}
from
'vuex'
;
import
wrapper
from
'./wrapper'
;
export
default
{
components
:
{
wrapper
},
methods
:
{
activeComponent
(
id
)
{
this
.
$store
.
dispatch
(
'activeComponent'
,
id
);
},
changeActiveIdList
(
id
)
{
this
.
$store
.
commit
(
'changeActiveIdList'
,
id
);
}
},
computed
:
{
...
mapGetters
([
'componentList'
])
}
};
</
script
>
src/views/Editor/components/wrapper.vue
0 → 100644
View file @
d5e2284c
<
template
>
<vue-draggable-resizable
:minw=
"1"
:minh=
"1"
:cmp-id=
"cmpId"
:z=
"99"
:otherstatus=
"true"
:class=
"[active ? 'choosed-cmp' : 'unchoosed-cmp', isTyping && 'isTyping']"
v-bind=
"position"
@
dragging=
"handleDragging"
@
resizing=
"handleResize"
@
deactivated=
"handleDeactivated"
>
<div
class=
"sword-compomnent-content-wrapper"
:contenteditable=
"false"
@
dblclick=
"handleEnableInput"
@
input=
"handleInput"
@
keyup
.
delete
.
prevent=
"changeEditRange"
>
<component
:is=
"componentData.component"
:is-typing=
"false"
:properties=
"componentData.properties"
/>
</div>
</vue-draggable-resizable>
</
template
>
<
script
>
export
default
{
props
:
{
from
:
{
type
:
String
},
componentData
:
{
type
:
Object
,
require
:
true
}
},
methods
:
{
handleEnableInput
()
{
// 处于编辑状态的组件不可进行 删除、移动、缩放操作
this
.
$store
.
dispatch
(
'changeEditaleStatus'
,
this
.
canTyping
);
},
handleDeactivated
()
{
this
.
$store
.
dispatch
(
'changeEditaleStatus'
,
false
);
},
changeEditRange
(
e
)
{
// this.isTyping && setEditRange(e.target);
},
handleInput
(
e
)
{
const
textContent
=
e
.
target
.
innerHTML
.
replace
(
/<br>/g
,
''
)
.
replace
(
/<
\/
.+
?
>/g
,
''
)
.
replace
(
/<.+
?
>/g
,
'<br>'
)
.
replace
(
/^<br>/
,
''
);
// this.$store.dispatch('modifyComponent', {
// key: ['props', 'text'],
// value: textContent || ' ',
// id: this.cmpId
// });
},
handleResize
(
left
,
top
,
w
,
h
)
{
const
id
=
this
.
cmpId
;
// this.$store.dispatch('batchModifyComponent', [
// {
// key: ['bindings', 'outline', 'position', 'top', 'v'],
// value: top,
// id
// },
// {
// key: ['bindings', 'outline', 'position', 'left', 'v'],
// value: left,
// id
// },
// {
// key: ['bindings', 'outline', 'position', 'width', 'v'],
// value: w,
// id
// },
// {
// key: ['bindings', 'outline', 'position', 'height', 'v'],
// value: h,
// id
// }
// ]);
},
handleDragging
(
left
,
top
)
{
// 文本编辑状态 与 位置锁定状态无法拖动
// if (
// this.isTyping ||
// path(
// ['bindings', 'outline', 'position', 'fixed', 'v'],
// this.componentData
// )
// ) {
// 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', {
// leftDistance: left - path(leftKeys, this.componentData),
// topDistance: top - path(topKeys, this.componentData)
// });
// } else {
// // 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
()
{
console
.
log
(
'this.componentData'
,
this
.
componentData
);
return
this
.
componentData
.
id
;
},
active
()
{
return
this
.
$store
.
state
.
project
.
activeIdList
.
indexOf
(
this
.
cmpId
)
!==
-
1
},
isTyping
()
{
return
this
.
componentData
.
editable
;
},
canTyping
()
{
// 只有文字才可以编辑
return
this
.
componentData
.
group
===
'text'
;
},
styleObject
()
{
return
styles
.
getStyleObject
(
this
.
componentData
);
},
position
()
{
const
componentData
=
this
.
componentData
;
return
{
x
:
componentData
.
properties
.
left
.
value
,
y
:
componentData
.
properties
.
top
.
value
,
w
:
componentData
.
properties
.
width
.
value
,
h
:
componentData
.
properties
.
height
.
value
}
// 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
// )
// };
}
}
};
</
script
>
<
style
>
.vdr
{
box-sizing
:
content-box
;
border
:
1px
solid
transparent
;
}
.vdr.active
{
border-color
:
transparent
;
}
.vdr.choosed-cmp
{
border-color
:
rgba
(
157
,
172
,
255
,
0.9
);
cursor
:
move
;
}
.vdr.isTyping
{
cursor
:
text
;
}
/* .handle {
border-radius: 50%;
} */
.vdr.choosed-cmp
>
.handle
{
display
:
block
!important
;
}
.vdr.unchoosed-cmp
>
.handle
{
display
:
none
!important
;
}
.otherstatus.active
{
border-color
:
transparent
;
}
.sword-compomnent-content-wrapper
{
height
:
100%
;
border
:
none
;
}
</
style
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment