7 | * ```
8 | */
9 | const clickoutsideContext = '@@clickoutsideContext'
10 |
11 | export default {
12 | bind (el, binding, vnode) {
13 | const documentHandler = function (e) {
14 | if (vnode.context && !el.contains(e.target)) {
15 | vnode.context[el[clickoutsideContext].methodName]()
16 | }
17 | }
18 | el[clickoutsideContext] = {
19 | documentHandler,
20 | methodName: binding.expression,
21 | arg: binding.arg || 'click'
22 | }
23 | document.addEventListener(el[clickoutsideContext].arg, documentHandler)
24 | },
25 |
26 | update (el, binding) {
27 | el[clickoutsideContext].methodName = binding.expression
28 | },
29 |
30 | unbind (el) {
31 | document.removeEventListener(
32 | el[clickoutsideContext].arg,
33 | el[clickoutsideContext].documentHandler)
34 | },
35 |
36 | install (Vue) {
37 | Vue.directive('clickoutside', {
38 | bind: this.bind,
39 | unbind: this.unbind
40 | })
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import App from './App'
5 | import router from './router'
6 | import ElementUI from 'element-ui'
7 | import 'element-ui/lib/theme-chalk/index.css'
8 | import '../styles/element-variables.scss'
9 | import store from '../src/store'
10 | import clickoutside from './directive'
11 | import axios from './request'
12 | import Vant from 'vant'
13 | import 'vant/lib/index.css'
14 | import VueHighlightJS from 'vue-highlightjs'
15 |
16 | Vue.use(Vant)
17 | Vue.use(VueHighlightJS)
18 |
19 | Vue.prototype.axios = axios
20 |
21 | Vue.use(ElementUI)
22 |
23 | Vue.config.productionTip = false
24 |
25 | Vue.directive('clickoutside', clickoutside)
26 |
27 | /* eslint-disable no-new */
28 | new Vue({
29 | el: '#app',
30 | router,
31 | store,
32 | components: { App },
33 | template: '
'
34 | })
35 |
36 | // new Vue({
37 | // router,
38 | // store,
39 | // render: h => h(App)
40 | // }).$mount('#app')
41 |
--------------------------------------------------------------------------------
/src/modules/attr-area/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
53 |
54 |
--------------------------------------------------------------------------------
/src/modules/attr-area/info.vue:
--------------------------------------------------------------------------------
1 |
2 |
28 |
29 |
30 |
93 |
94 |
124 |
--------------------------------------------------------------------------------
/src/modules/attr-area/struct.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 | onHover(node,data)"
9 | @mouseout.stop="() => noHover(node,data)"
10 | >
11 | onActive(data)">
12 |
13 | {{node.label}}
14 | {{data.className}}
15 |
16 |
17 |
20 | remove(node, data)">
21 |
22 |
23 |
24 |
25 |
26 |
69 |
70 |
90 |
91 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/src/modules/code-area/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
80 |
81 |
109 |
110 |
117 |
118 |
--------------------------------------------------------------------------------
/src/modules/edit-area/attr-box/config.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 | {{item.label}}:
12 |
13 |
14 |
20 |
21 |
25 |
26 |
31 |
36 |
37 |
38 |
39 |
41 |
42 |
43 |
46 |
47 |
56 | 点击上传
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
139 |
140 |
145 |
146 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/src/modules/edit-area/attr-box/configTable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
数据源配置
4 |
25 |
26 | 新增行
27 |
28 |
29 |
30 |
31 |
63 |
64 |
89 |
90 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/src/modules/edit-area/attr-box/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
暂无选中元素
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
46 |
47 |
48 |
65 |
66 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/src/modules/edit-area/attr-box/link.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 链接:
5 |
6 | 该项目还没有其它页面哦!
7 |
8 |
9 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
58 |
59 |
64 |
--------------------------------------------------------------------------------
/src/modules/edit-area/page.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
14 |
22 |
23 |
24 | 拖动调整高度 {{height}}px
25 |
26 |
27 |
28 |
29 |
114 |
115 |
158 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/div/div00.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
61 |
62 |
64 |
65 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/div/div01.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
62 |
63 |
65 |
66 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/div/div10.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
81 |
82 |
84 |
85 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/div/div11.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
82 |
83 |
85 |
86 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/index.js:
--------------------------------------------------------------------------------
1 | import TypeDiv from './type-div'
2 | import TypeSpan from './type-span'
3 | import TypeH1 from './type-h1'
4 | import TypeP from './type-p'
5 | import TypeButton from './type-button'
6 | import TypeRadio from './type-radio'
7 | import TypeSearch from './type-search'
8 | import TypeSwitch from './type-switch'
9 | import TypeNavbar from './type-navbar'
10 | import TypeTabbar from './type-tabbar'
11 | import TypeTag from './type-tag'
12 | import TypeImg from './preview/type-img'
13 | import TypeFlexbox from './type-flexbox'
14 | import TypeGrid from './type-grid'
15 | import TypeSwiper from './type-swiper'
16 | import TypeIcon from './type-icon'
17 | import TypeIcontext from './type-icontext'
18 | import TypeRate from './type-rate'
19 |
20 | export default {
21 | TypeButton,
22 | TypeDiv,
23 | TypeSearch,
24 | TypeSwitch,
25 | TypeRadio,
26 | TypeSpan,
27 | TypeTabbar,
28 | TypeNavbar,
29 | TypeTag,
30 | TypeImg,
31 | TypeFlexbox,
32 | TypeGrid,
33 | TypeSwiper,
34 | TypeIcon,
35 | TypeP,
36 | TypeH1,
37 | TypeIcontext,
38 | TypeRate
39 | }
40 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/preview.js:
--------------------------------------------------------------------------------
1 | import TypeDiv from './preview/type-div'
2 | import TypeSpan from './type-span'
3 | import TypeH1 from './type-h1'
4 | import TypeP from './type-p'
5 | import TypeButton from './type-button'
6 | import TypeRadio from './type-radio'
7 | import TypeSearch from './type-search'
8 | import TypeSwitch from './type-switch'
9 | import TypeNavbar from './type-navbar'
10 | import TypeTabbar from './type-tabbar'
11 | import TypeTag from './type-tag'
12 | import TypeImg from './preview/type-img'
13 | import TypeFlexbox from './preview/type-flexbox'
14 | import TypeGrid from './preview/type-grid'
15 | import TypeSwiper from './type-swiper'
16 | import TypeIcon from './type-icon'
17 | import TypeIcontext from './type-icontext'
18 | import TypeRate from './type-rate'
19 |
20 | export default {
21 | TypeButton,
22 | TypeDiv,
23 | TypeSearch,
24 | TypeSwitch,
25 | TypeRadio,
26 | TypeSpan,
27 | TypeTabbar,
28 | TypeNavbar,
29 | TypeTag,
30 | TypeImg,
31 | TypeFlexbox,
32 | TypeGrid,
33 | TypeSwiper,
34 | TypeIcon,
35 | TypeP,
36 | TypeH1,
37 | TypeIcontext,
38 | TypeRate
39 | }
40 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/preview/div/div00.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
15 |
16 |
18 |
19 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/preview/div/div01.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
17 |
18 |
20 |
21 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/preview/div/div10.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
36 |
37 |
39 |
40 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/preview/div/div11.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
38 |
39 |
41 |
42 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/preview/type-div.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
30 |
31 |
33 |
34 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/preview/type-flexbox.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
84 |
85 |
97 |
98 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/preview/type-grid.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
25 |
26 |
36 |
37 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/preview/type-img.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
24 |
25 |
27 |
28 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-button.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ele.config[2].data}}
4 |
5 |
6 |
7 |
15 |
16 |
18 |
19 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-div.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
30 |
31 |
33 |
34 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-flexbox.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
84 |
85 |
97 |
98 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-grid.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
72 |
73 |
83 |
84 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-h1.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ele.config[0].data}}
4 |
5 |
6 |
7 |
15 |
16 |
18 |
19 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-icon.vue:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
20 |
21 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-icontext.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ele.config[1].data}}
5 |
6 |
7 |
8 |
22 |
23 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-img.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
15 |
51 |
52 |
82 |
83 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-navbar.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 | {{ele.config[2].data}}
11 |
12 |
13 |
14 |
15 | {{ele.config[4].data}}
16 |
17 |
18 |
19 |
20 |
28 |
29 |
35 |
36 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-p.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ele.config[0].data}}
4 |
5 |
6 |
7 |
15 |
16 |
18 |
19 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-radio.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
19 |
21 |
22 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-rate.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
33 |
34 |
36 |
37 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-search.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
31 |
32 |
34 |
35 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-span.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ele.config[0].data}}
4 |
5 |
6 |
7 |
15 |
16 |
18 |
19 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-swiper.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
22 |
23 |
29 |
30 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-switch.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
19 |
21 |
22 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-tabbar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | - onActive(index)"
7 | >
8 |
12 |
16 |
{{item.info}}
17 |
20 | {{item.label}}
21 |
22 |
23 |
24 |
25 |
26 |
55 |
56 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/src/modules/edit-area/types/type-tag.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ele.config[0].data}}
4 |
5 |
6 |
7 |
15 |
16 |
--------------------------------------------------------------------------------
/src/modules/head-area/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 | {{pageInfo.name}}
11 |
12 |
13 | {{info.name}}
14 |
15 |
16 | {{left}}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 | {{title || info.name}}
29 |
30 |
34 |
35 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
119 |
120 |
--------------------------------------------------------------------------------
/src/modules/head-area/menu-bar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 | 字号
6 |
7 | -
8 |
9 | 撤销
10 |
11 | -
12 |
13 | 放大
14 |
15 | -
16 |
17 | 缩小
18 |
19 |
20 |
21 |
22 |
30 |
31 |
--------------------------------------------------------------------------------
/src/modules/head-area/mobile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | x
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | %
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
70 |
71 |
76 |
77 |
90 |
91 |
--------------------------------------------------------------------------------
/src/modules/head-area/tool-bar.vue:
--------------------------------------------------------------------------------
1 |
2 |
45 |
46 |
47 |
84 |
85 |
--------------------------------------------------------------------------------
/src/modules/head-area/user-avatar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 登录
5 |
6 |
7 |
8 |
9 |
10 |
11 | 个人中心
12 |
13 |
14 | 退出
15 |
16 |
17 |
18 |
19 |
20 |
64 |
65 |
74 |
75 |
--------------------------------------------------------------------------------
/src/modules/me/Comp.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
25 |
26 |
33 |
34 |
55 |
56 |
--------------------------------------------------------------------------------
/src/modules/me/Menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
35 |
36 |
37 |
52 |
53 |
62 |
63 |
--------------------------------------------------------------------------------
/src/modules/me/Mod.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
34 |
--------------------------------------------------------------------------------
/src/modules/me/Project.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
37 |
38 |
45 |
--------------------------------------------------------------------------------
/src/modules/me/Templ.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
27 |
28 |
35 |
36 |
67 |
68 |
--------------------------------------------------------------------------------
/src/modules/preview-area/custom-element.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
13 |
14 |
15 |
16 |
17 |
23 |
24 |
25 |
31 |
32 |
33 |
38 |
39 |
40 |
41 |
42 |
43 |
73 |
74 |
75 |
77 |
78 |
--------------------------------------------------------------------------------
/src/modules/preview-area/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
42 |
43 |
49 |
--------------------------------------------------------------------------------
/src/modules/resource-area/comp.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 按
6 |
7 |
8 |
9 | 从资源库中选取需要的组件
10 |
11 |
16 |
17 |
18 |
19 | {{item.name}}
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
81 |
82 |
137 |
--------------------------------------------------------------------------------
/src/modules/resource-area/compUse.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 | {{item.name}}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
34 |
35 |
84 |
--------------------------------------------------------------------------------
/src/modules/resource-area/components.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "c1",
4 | "name": "按钮",
5 | "type": "button",
6 | "icon": "button",
7 | "style": "background:#fff;color:red;fontSize:12px;borderRadius:0px;",
8 | "config": [
9 | { "name": "text", "label": "内容", "type": "input", "data": "按钮" }
10 | ]
11 | },
12 | {
13 | "id": "c2",
14 | "name": "标签",
15 | "icon": "tag",
16 | "type": "tag",
17 | "style": "background:#fff;color:#F36D6E;fontSize:12px;border:1px solid #F36D6E;padding:2px 4px 2px 4px;borderRadius:2px;",
18 | "config": [
19 | { "name": "text", "label": "文字", "type": "input", "data": "标签" }
20 | ]
21 | },
22 | {
23 | "id": "c22",
24 | "name": "图文标",
25 | "icon": "icontext",
26 | "type": "icontext",
27 | "style": "color:#888;padding:2px;",
28 | "config": [
29 | { "name": "icon", "label": "图标", "type": "input", "data": "icon-ziyuan" },
30 | { "name": "label", "label": "文字", "type": "input", "data": "123万" },
31 | { "name": "gutter", "label": "间距", "type": "number", "data": 0 }
32 | ]
33 | },
34 | {
35 | "id": "c3",
36 | "name": "单选框",
37 | "icon": "radio",
38 | "type": "radio",
39 | "config": []
40 | },
41 | {
42 | "id": "c4",
43 | "name": "多选框",
44 | "icon": "checkbox",
45 | "type": "checkbox",
46 | "config": []
47 | },
48 | {
49 | "id": "c5",
50 | "name": "开关",
51 | "icon": "switch",
52 | "type": "switch",
53 | "config": []
54 | },
55 | {
56 | "id": "c6",
57 | "name": "搜索框",
58 | "icon": "search",
59 | "type": "search",
60 | "config": []
61 | },
62 | {
63 | "id": "c7",
64 | "name": "底部栏",
65 | "icon": "tabbar",
66 | "type": "tabbar",
67 | "style": "position:absolute;bottom:0;display:flex;",
68 | "config": [
69 | { "name": "data", "label": "数据", "type": "table", "data": [
70 | {"icon": "icon-paihangbang", "label": "排行榜", "info": "5"},
71 | {"icon": "icon-yonghu", "label": "我的", "info": ""},
72 | {"icon": "icon-faxian", "label": "发现", "info": ""}
73 | ]},
74 | { "name": "normal", "label": "普通色", "type": "color", "data": "#666" },
75 | { "name": "active", "label": "高亮色", "type": "color", "data": "#EC0E0E" }
76 | ]
77 | },
78 | {
79 | "id": "c8",
80 | "name": "导航栏",
81 | "icon": "navbar",
82 | "type": "navbar",
83 | "style": "background:#171717;color:#fff;",
84 | "config": [
85 | { "name": "title", "label": "标题", "type": "input", "data": "标题" },
86 | { "name": "leftIcon", "label": "左图标", "type": "input", "data": "icon-fanhui" },
87 | { "name": "leftText", "label": "左文字", "type": "input", "data": "返回" },
88 | { "name": "rightIcon", "label": "右图标", "type": "input", "data": "icon-user" },
89 | { "name": "rightText", "label": "右文字", "type": "input", "data": "" }
90 | ]
91 | },
92 | {
93 | "id": "c9",
94 | "name": "轮播图",
95 | "icon": "swiper",
96 | "type": "swiper",
97 | "config": [
98 | { "name": "image", "label": "图片", "type": "table", "data": [
99 | {"url": "http://localhost/static/1.jpg"},
100 | {"url": "http://localhost/static/2.jpg"}
101 | ]}
102 | ]
103 | },
104 | {
105 | "id": "c10",
106 | "name": "布局盒子",
107 | "icon": "layout",
108 | "type": "flexbox",
109 | "config": [
110 | { "name": "num", "label": "数量", "type": "number", "data": 3 },
111 | { "name": "gutter", "label": "间隔", "type": "number", "data": 8 },
112 | { "name": "orient", "label": "间隔", "type": "select", "data": "horizontal", "options": ["horizontal", "vertical"]},
113 | { "name": "justify", "label": "水平排列", "type": "select", "data": "flex-start",
114 | "options": ["flex-start", "flex-end", "center", "space-between", "space-around"]
115 | },
116 | { "name": "align", "label": "竖向排列", "type": "select", "data": "flex-start",
117 | "options": ["flex-start", "flex-end", "center", "space-between", "space-around", "stretch"]
118 | },
119 | { "name": "wrap", "label": "间隔", "type": "select", "data": "row",
120 | "options": ["row", "row-reverse", "column", "column-reverse"]
121 | },
122 | { "name": "direction", "label": "间隔", "type": "select", "data": "wrap",
123 | "options": ["wrap", "nowrap"]
124 | }
125 | ]
126 | },
127 | {
128 | "id": "c11",
129 | "name": "网格布局",
130 | "icon": "9box",
131 | "type": "grid",
132 | "config": [
133 | { "name": "cols", "label": "列数", "type": "number", "data": 3 },
134 | { "name": "show-lr-borders", "label": "是否显示左右边框", "type": "bool", "data": true},
135 | { "name": "show-vertical-dividers", "label": "是否显示分割线", "type": "bool", "data": true}
136 | ]
137 | }
138 |
139 | ]
--------------------------------------------------------------------------------
/src/modules/resource-area/images.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 | 点击上传
14 |
15 |
16 | -
20 |
21 |
22 |
23 | 点击复制链接
24 |
25 |
26 |
27 |
28 |
29 |
30 |
91 |
92 |
121 |
--------------------------------------------------------------------------------
/src/modules/resource-area/module.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 切换 'e' 键,进入/退出模块划分模式,选取元素即可划分模块;按 'esc' 键清除当前框选
5 |
6 |
7 | -
11 |
12 |
13 |
22 |
23 |
{{item.name}}
24 |
25 | {{item.developer}}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
82 |
83 |
154 |
--------------------------------------------------------------------------------
/src/modules/resource-area/templ.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 按
6 |
7 |
8 |
9 | 从资源库中选取需要的模版
10 |
11 |
16 |
17 |
18 |
19 |
28 |
29 |
30 | {{item.name}}-{{item.id}}
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
95 |
96 |
160 |
--------------------------------------------------------------------------------
/src/modules/resource-area/type.js:
--------------------------------------------------------------------------------
1 | const components = [
2 | {icon: 'div', label: '容器', value: 'div'},
3 | {icon: 'text', label: '文字', value: 'span'},
4 | {icon: 'h1', label: '标题', value: 'h1'},
5 | {icon: 'p', label: '描述', value: 'p'},
6 | {icon: 'image', label: '图片', value: 'img'},
7 | {icon: 'h-divider', label: '横分隔', value: 'h-divider'},
8 | {icon: 'v-divider', label: '竖分隔', value: 'v-divider'},
9 | {icon: 'info', label: '图标', value: 'icon'}
10 | ]
11 |
12 | const layouts = [
13 | {icon: 'layout', label: '等分', value: 'flex'},
14 | {icon: 'flex', label: '九宫格', value: 'ninebox'},
15 | {icon: 'list', label: '列表', value: 'list'}
16 | ]
17 |
18 | export { components, layouts }
19 |
--------------------------------------------------------------------------------
/src/pages/edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
119 |
120 |
--------------------------------------------------------------------------------
/src/pages/login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
H5 Editor
5 |
34 |
还没有账号?
35 | 马上注册
36 |
37 |
38 |
39 |
40 |
41 |
42 |
70 |
71 |
188 |
--------------------------------------------------------------------------------
/src/pages/me.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | H5 Editor
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | {{user.name}}
16 | {{user.desc || '这个同学很懒,都没有写签名哦~'}}
17 |
18 |
19 |
20 |
21 |
22 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | 暂时没有数据哦
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
114 |
115 |
206 |
207 |
218 |
--------------------------------------------------------------------------------
/src/pages/pageDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
15 |
18 |
19 |
20 |
21 |
22 |
43 |
44 |
--------------------------------------------------------------------------------
/src/pages/preview.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 组
件
列
表
17 |
18 |
19 | 模
件
列
表
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
31 |
72 |
73 |
--------------------------------------------------------------------------------
/src/pages/projectDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
29 |
30 |
31 |
32 |
33 |
34 |
91 |
92 |
131 |
132 |
142 |
--------------------------------------------------------------------------------
/src/pages/register.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
H5 Editor
5 |
34 |
已有账号?
35 | 马上登录
36 |
37 |
38 |
39 |
40 |
41 |
42 |
69 |
70 |
187 |
--------------------------------------------------------------------------------
/src/request.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import Vue from 'vue'
3 | const vm = new Vue()
4 | axios.defaults.withCredentials = true
5 | // Add a request interceptor
6 | axios.interceptors.request.use(function (config) {
7 | // Do something before request is sent
8 | return config
9 | }, function (error) {
10 | // Do something with request error
11 | return Promise.reject(error)
12 | })
13 |
14 | axios.interceptors.response.use(response => {
15 | // if (response.data.errno === undefined) return response
16 | const { data, errmsg, errno } = response.data
17 | const status = response.status
18 |
19 | if (status === 200) {
20 | if (errno !== 0) {
21 | vm.$message.error(errmsg || '操作失败')
22 | return 1000 // 用于判断是否错误
23 | } else {
24 | return data
25 | }
26 | } else {
27 | vm.$message.error('与服务器连接失败')
28 | return 1000
29 | }
30 | }, error => {
31 | if (error && error.response) {
32 | switch (error.response.status) {
33 | case 403:
34 | error.message = '你还未登录'
35 | location.href = 'http://localhost/#/login'
36 | break
37 | case 500:
38 | error.message = '服务器发生错误了'
39 | break
40 | case 502:
41 | error.message = '连接服务器超时'
42 | break
43 | default:
44 | }
45 | vm.$message.error(error.message)
46 | }
47 | return Promise.reject(error)
48 | })
49 |
50 | export default axios
51 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import Edit from '@/pages/edit'
4 | import Home from '@/pages/home'
5 | import Preview from '@/pages/preview'
6 | import PageDetail from '@/pages/pageDetail'
7 | import ProjectDetail from '@/pages/projectDetail'
8 | import Mobile from '@/modules/preview-area'
9 | import Me from '@/pages/me'
10 | import Login from '@/pages/login'
11 | import Register from '@/pages/register'
12 |
13 | Vue.use(Router)
14 |
15 | export default new Router({
16 | routes: [
17 | {
18 | path: '/',
19 | name: 'Welcome',
20 | component: Home
21 | },
22 | {
23 | path: '/edit',
24 | name: 'Edit',
25 | component: Edit
26 | },
27 | {
28 | path: '/home',
29 | name: 'Home',
30 | component: Home
31 | },
32 | {
33 | path: '/preview',
34 | name: 'Preview',
35 | component: Preview,
36 | children: [{
37 | path: 'mobile',
38 | component: Mobile
39 | }]
40 | },
41 | {
42 | path: '/mobile',
43 | name: 'Mobile',
44 | component: Mobile
45 | },
46 | {
47 | path: '/page',
48 | name: 'PageDetail',
49 | component: PageDetail
50 | },
51 | {
52 | path: '/project',
53 | name: 'ProjectDetail',
54 | component: ProjectDetail
55 | },
56 | {
57 | path: '/me',
58 | name: 'Me',
59 | component: Me
60 | },
61 | {
62 | path: '/login',
63 | name: 'Login',
64 | component: Login
65 | },
66 | {
67 | path: '/register',
68 | name: 'Register',
69 | component: Register
70 | }
71 | ]
72 | })
73 |
--------------------------------------------------------------------------------
/src/utils/Bus.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | const Bus = new Vue()
4 |
5 | export default Bus
6 |
--------------------------------------------------------------------------------
/src/utils/attrShow.js:
--------------------------------------------------------------------------------
1 | export default {
2 | div: {padding: true, margin: true, width: true, height: true, background: true, borderRadius: true, border: true, position: true, display: true},
3 | span: {padding: true, margin: true, width: true, height: true, background: true, borderRadius: true, border: true, position: true, display: true, fontSize: true, color: true, fontWeight: true},
4 | h1: {padding: true, margin: true, position: true, display: true, fontSize: true, color: true, fontWeight: true, textAlign: true},
5 | p: {padding: true, margin: true, position: true, display: true, fontSize: true, color: true, fontWeight: true, textAlign: true},
6 | icon: {margin: true, position: true, display: true, fontSize: true, color: true, fontWeight: true},
7 | img: {margin: true, width: true, height: true, borderRadius: true, border: true, position: true, display: true},
8 | button: {fontSize: true, color: true, fontWeight: true, background: true, padding: true, margin: true, position: true, border: true, borderRadius: true},
9 | flexbox: {padding: true, margin: true, position: true},
10 | grid: {padding: true, margin: true, position: true},
11 | tabbar: {border: true, background: true},
12 | tag: {fontSize: true, color: true, fontWeight: true, background: true, padding: true, margin: true, position: true, borderRadius: true, border: true},
13 | icontext: {color: true, margin: true, position: true},
14 | navbar: {color: true, background: true}
15 | }
16 |
--------------------------------------------------------------------------------
/src/utils/config.js:
--------------------------------------------------------------------------------
1 | const config = {
2 | // URL: 'http://localhost:8360'
3 | URL: '/api'
4 | }
5 |
6 | export default config
7 |
--------------------------------------------------------------------------------
/src/utils/help.js:
--------------------------------------------------------------------------------
1 | function guid () {
2 | function S4 () {
3 | return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
4 | }
5 | return (`e-${S4() + S4()}`)
6 | }
7 |
8 | function getInit (type) {
9 | let attr
10 | switch (type) {
11 | case 'div':
12 | attr = {
13 | style: 'height:100px;border:1px solid #ccc;',
14 | config: [
15 | { name: 'p', label: '父元素', type: 'bool', data: false },
16 | { name: 'dir', label: '主轴方向', type: 'select', options: ['top', 'right', 'bottom', 'left'], data: 'left', show: 1 },
17 | { name: 'main', label: '主轴对齐方式', type: 'select', options: ['right', 'left', 'justify', 'center'], data: 'left', show: 1 },
18 | { name: 'cross', label: '交叉轴对齐方式', type: 'select', options: ['top', 'bottom', 'baseline', 'center', 'stretch'], data: 'top', show: 1 },
19 | { name: 'box', label: '子元素设置', type: 'select', options: ['', 'mean', 'first', 'last', 'justify'], data: '', show: 1 },
20 | { name: 'c', label: '子元素', type: 'bool', data: false },
21 | { name: 'flex-box', label: '子元素', type: 'number', data: 0, show: 6 }
22 | ]
23 | }
24 | break
25 | case 'span':
26 | attr = {
27 | style: 'color:#000;',
28 | config: [
29 | { name: 'text', label: '文字', type: 'input', data: '文字' }
30 | ]
31 | }
32 | break
33 | case 'h1':
34 | attr = {
35 | style: 'color:#555;fontSize:16px;',
36 | config: [
37 | { name: 'text', label: '文字', type: 'input', data: '标题' }
38 | ]
39 | }
40 | break
41 | case 'p':
42 | attr = {
43 | style: 'color:#888;fontSize:14px;',
44 | config: [
45 | { name: 'text', label: '文字', type: 'input', data: '这是一段描述文字' }
46 | ]
47 | }
48 | break
49 | case 'img':
50 | attr = {
51 | style: 'width:100px;height:80px;',
52 | config: [
53 | { name: 'url', label: 'url', type: 'input', data: '' }
54 | ]
55 | }
56 | break
57 | case 'icon':
58 | attr = {
59 | style: 'color:#000;',
60 | config: [
61 | { name: 'name', label: '图标名', type: 'input', data: 'icon-info' }
62 | ]
63 | }
64 | break
65 | default:
66 | attr = {}
67 | }
68 | return attr
69 | }
70 |
71 | const mobiles = [
72 | {
73 | label: 'iPhone7',
74 | width: 375,
75 | height: 667
76 | }, {
77 | label: 'iPhone7Plus',
78 | width: 414,
79 | height: 736
80 | }, {
81 | label: 'iPhone5s',
82 | width: 320,
83 | height: 568
84 | }, {
85 | label: 'iPhoneX',
86 | width: 375,
87 | height: 812
88 | }
89 | ]
90 |
91 | function px2rem (value) {
92 | if (value) {
93 | value = value / 75
94 | value = parseFloat(value).toFixed(6)
95 | return (value + 'rem')
96 | }
97 | return null
98 | }
99 |
100 | function createModule ({elements, pid, developer, name}) {
101 | let mod = {
102 | id: `m/${guid()}`,
103 | name,
104 | elements,
105 | pid,
106 | developer,
107 | classId: {},
108 | components: {}
109 | }
110 | return mod
111 | }
112 |
113 | function createTempl ({elements, name}) {
114 | let templ = {
115 | id: `t/${guid()}`,
116 | name,
117 | elements
118 | }
119 | return templ
120 | }
121 |
122 | export { guid, getInit, mobiles, px2rem, createModule, createTempl }
123 |
--------------------------------------------------------------------------------
/src/utils/modules.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "m-1",
4 | "name": "模块1",
5 | "elements": ["e2", "e3"],
6 | "developer": "开发者1",
7 | "classId": {},
8 | "components": {
9 | "id/comp1": {
10 | "name": "demo-comp1",
11 | "label": "组件1",
12 | "elements": ["e2"]
13 | },
14 | "id/comp2": {
15 | "name": "demo-comp2",
16 | "label": "组件2",
17 | "elements": ["e3"]
18 | }
19 | }
20 | },
21 | {
22 | "id": "m-2",
23 | "name": "模块2",
24 | "classId": {},
25 | "elements": ["e4"],
26 | "developer": "开发者2",
27 | "components": {
28 | "id/comp1": {
29 | "name": "demo-comp1",
30 | "label": "组件1",
31 | "elements": ["e5"]
32 | }
33 | }
34 | },
35 | {
36 | "id": "m-3",
37 | "name": "模块3",
38 | "classId": {},
39 | "elements": ["e3", "e5"],
40 | "developer": "开发者2",
41 | "components": {
42 | "id/comp1": {
43 | "name": "demo-comp1",
44 | "label": "组件1",
45 | "elements": ["e5"]
46 | }
47 | }
48 | }
49 | ]
--------------------------------------------------------------------------------
/src/utils/page.js:
--------------------------------------------------------------------------------
1 | import { toList } from '@/utils/transformTree'
2 |
3 | const DATA = [{
4 | id: 'e1',
5 | label: '容器-e1',
6 | type: 'div',
7 | style: 'width:100px;height:100px;background:#F56C6C;',
8 | pid: 'root',
9 | children: [{
10 | id: 'e2',
11 | label: '文字-e2',
12 | type: 'span',
13 | config: [
14 | { name: 'text', lable: '文字', type: 'input', data: '监控设备' }
15 | ],
16 | style: 'width:50px;height:50px;color:pink;',
17 | pid: 'e1',
18 | children: []
19 | }]
20 | }, {
21 | id: 'e4',
22 | label: '容器-e4',
23 | type: 'div',
24 | style: 'width:100px;height:50px;background:orange;',
25 | pid: 'root',
26 | children: [{
27 | id: 'e5',
28 | label: '文字-e5',
29 | type: 'span',
30 | config: [
31 | { name: 'text', label: '文字', type: 'input', data: 'sajfg' }
32 | ],
33 | style: 'color: #000;',
34 | pid: 'e4',
35 | children: []
36 | }]
37 | }, {
38 | id: 'e7',
39 | label: '容器-e7',
40 | type: 'div',
41 | style: 'width:100%;height:100px;background:#409EFF;',
42 | children: [],
43 | pid: 'root'
44 | }, {
45 | id: 'e6',
46 | label: '文字-e6',
47 | type: 'span',
48 | config: [
49 | { name: 'text', label: '文字', type: 'input', data: '数据库表' }
50 | ],
51 | style: 'width:50px;height:50px;color: #555;',
52 | pid: 'root',
53 | children: []
54 | }]
55 |
56 | const LIST = toList(DATA)
57 |
58 | export { LIST, DATA }
59 |
60 | // export default DATA
61 |
--------------------------------------------------------------------------------
/src/utils/page.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "id": "Page1",
4 | "name": "测试页面",
5 | "background": "#fff",
6 | "projectId": 5
7 | },
8 | "elements": [
9 | {
10 | "id": "e1",
11 | "type": "div",
12 | "className": "",
13 | "style": "width:150px;height:150px;border:1px solid #ccc;",
14 | "label": "容器-e1",
15 | "children": [{
16 | "id": "e2",
17 | "className": "",
18 | "label": "容器-e2",
19 | "type": "div",
20 | "style": "width:50px;height:50px;background:#409EFF;",
21 | "pid": "e1",
22 | "children": []
23 | },{
24 | "id": "e3",
25 | "className": "",
26 | "label": "容器-e3",
27 | "type": "div",
28 | "style": "width:50px;height:50px;background:#555;",
29 | "pid": "e1",
30 | "children": []
31 | }],
32 | "pid": "root"
33 | },
34 | {
35 | "id": "e4",
36 | "label": "容器-e4",
37 | "type": "div",
38 | "className": "",
39 | "style": "width:100px;height:50px;background:#FED96E;",
40 | "pid": "root",
41 | "children": [{
42 | "id": "e5",
43 | "label": "文字-e5",
44 | "type": "span",
45 | "className": "",
46 | "config": [
47 | { "name": "text", "label": "文字", "type": "input", "data": "sajfg" }
48 | ],
49 | "style": "color: #000;",
50 | "pid": "e4",
51 | "children": []
52 | }]
53 | }
54 | ]
55 | }
--------------------------------------------------------------------------------
/src/utils/templs.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "t1",
4 | "name": "模版1",
5 | "image": "http://imgs.xueui.cn/wp-content/uploads/2018/01/fm110.jpg",
6 | "content": {
7 | "id": "t1",
8 | "type": "div",
9 | "style": "",
10 | "label": "模版1容器",
11 | "children": [
12 | {
13 | "id": "e1",
14 | "type": "div",
15 | "style": "width:150px;height:150px;background:#4ED7EC;",
16 | "label": "容器-e1",
17 | "children": [{
18 | "id": "e2",
19 | "label": "容器-e2",
20 | "type": "div",
21 | "style": "width:50px;height:50px;background:#409EFF;",
22 | "pid": "e1",
23 | "children": []
24 | },{
25 | "id": "e3",
26 | "label": "容器-e3",
27 | "type": "div",
28 | "style": "width:50px;height:50px;background:#555;",
29 | "pid": "e1",
30 | "children": []
31 | }],
32 | "pid": "t1"
33 | }
34 | ]
35 | }
36 | },
37 | {
38 | "id": "t2",
39 | "name": "模版2",
40 | "image": "http://imgs.xueui.cn/wp-content/uploads/2017/10/Cover%EF%BC%9AArticle-2017.10.26-1.png",
41 | "content": {
42 | "id": "t2",
43 | "type": "div",
44 | "style": "",
45 | "label": "模版1容器",
46 | "children": [
47 | {
48 | "id": "e1",
49 | "type": "div",
50 | "style": "width:150px;height:150px;background:#67c23a;borderRadius:100%",
51 | "label": "容器-e1",
52 | "children": [],
53 | "pid": "t2"
54 | }
55 | ]
56 | }
57 | },
58 | {
59 | "id": "t3",
60 | "name": "模版3",
61 | "image": "http://imgs.xueui.cn/wp-content/uploads/2017/10/Cover%EF%BC%9AArticle-2017.10.24-2.png",
62 | "content": {
63 | "id": "t3",
64 | "type": "div",
65 | "style": "",
66 | "label": "模版1容器",
67 | "children": [
68 | {
69 | "id": "e4",
70 | "label": "容器-e4",
71 | "type": "div",
72 | "style": "width:100px;height:50px;background:#fed96e;borderRadius: 4px;",
73 | "pid": "t3",
74 | "children": [{
75 | "id": "e5",
76 | "label": "文字-e5",
77 | "type": "span",
78 | "config": [
79 | { "name": "text", "label": "文字", "type": "input", "data": "文字" }
80 | ],
81 | "style": "color: #000;",
82 | "pid": "e4",
83 | "children": []
84 | }]
85 | }
86 | ]
87 | }
88 | }
89 | ]
--------------------------------------------------------------------------------
/src/utils/transformTree.js:
--------------------------------------------------------------------------------
1 | // import DATA from './page'
2 | import { guid } from '@/utils/help'
3 |
4 | function toTree (data) {
5 | let list = JSON.parse(JSON.stringify(data))
6 | let idMap = {}
7 | let tree = []
8 |
9 | list.forEach(item => {
10 | idMap[item.id] = item
11 | })
12 | list.forEach(v => {
13 | let parent = idMap[v.pid]
14 | // debugger
15 | if (parent) {
16 | !parent.children && (parent.children = [])
17 | // parent.children.push(v)
18 | parent.children[v.idx] = v
19 | idMap[v.pid] = parent
20 | } else {
21 | // tree.push(v)
22 | tree[v.idx] = v
23 | }
24 | })
25 | return tree
26 | }
27 |
28 | function handleList (tree, list, pid) {
29 | tree.forEach((item, idx) => {
30 | let newItem = { pid, idx, ...item }
31 | delete newItem.children
32 | list.push(newItem)
33 | if (item.children && item.children.length > 0) {
34 | handleList(item.children, list, item.id)
35 | }
36 | })
37 | }
38 |
39 | function toList (tree) {
40 | let list = []
41 | handleList(tree, list, 'root')
42 | return JSON.parse(JSON.stringify(list))
43 | }
44 |
45 | /**
46 | * 根据 pid 返回 children
47 | * @param {*} tree
48 | * @param {*} pid
49 | */
50 | function treeTravel (tree, pid) {
51 | if (pid === 'root') {
52 | return new Promise(resolve => resolve(tree))
53 | }
54 | let q = []
55 | tree.forEach(item => {
56 | q.push(item)
57 | })
58 | // console.dir(q)
59 | while (q.length > 0) {
60 | let node = q.shift()
61 | if (node.id === pid) {
62 | return new Promise(resolve => resolve(node.children))
63 | }
64 | if (node.children && node.children.length > 0) {
65 | node.children.forEach(item => {
66 | q.push(item)
67 | })
68 | }
69 | }
70 | }
71 |
72 | /**
73 | * 根据 pid 返回 children
74 | * @param {*} tree
75 | * @param {*} id
76 | */
77 | function treeTravelById (tree, id) {
78 | let q = []
79 | tree.forEach(item => {
80 | q.push(item)
81 | })
82 | while (q.length > 0) {
83 | let node = q.shift()
84 | if (node.id === id) {
85 | return new Promise(resolve => resolve(node))
86 | }
87 | if (node.children && node.children.length > 0) {
88 | node.children.forEach(item => {
89 | q.push(item)
90 | })
91 | }
92 | }
93 | }
94 |
95 | /**
96 | * 模块编辑转换: 将ids -> element
97 | */
98 | function moduleSelect (tree, ids) {
99 | let elements = []
100 | let q = []
101 | tree.forEach(item => {
102 | q.push(item)
103 | })
104 | while (q.length > 0) {
105 | let node = q.shift()
106 | if (ids.indexOf(node.id) > -1) {
107 | node.pid = 'root'
108 | elements.push(node)
109 | } else if (node.children && node.children.length > 0) {
110 | node.children.forEach(item => {
111 | q.push(item)
112 | })
113 | }
114 | }
115 | return new Promise(resolve => resolve(elements))
116 | }
117 |
118 | /**
119 | * 复制包含多个子元素的元素,改变所有的id
120 | */
121 | function copyElorTempl (el, pid) {
122 | const id = guid()
123 | el.id = id
124 | el.pid = pid
125 | el.label = `${el.type}/${id}`
126 | if (el.children && el.children.length > 0) {
127 | el.children.forEach(item => {
128 | copyElorTempl(item, id)
129 | })
130 | }
131 | }
132 |
133 | export { toTree, toList, treeTravel, moduleSelect, treeTravelById, copyElorTempl }
134 |
--------------------------------------------------------------------------------
/static/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyhajnal/h5-editor/55d71c1915e204b9f03653d60078e7dc5ed05991/static/.gitkeep
--------------------------------------------------------------------------------
/styles/common.scss:
--------------------------------------------------------------------------------
1 |
2 | .clearfix:before,
3 | .clearfix:after {
4 | display: table;
5 | content: "";
6 | }
7 |
8 | .clearfix:after {
9 | clear: both
10 | }
--------------------------------------------------------------------------------
/styles/element-variables.scss:
--------------------------------------------------------------------------------
1 | /* 改变主题色变量 */
2 | $--color-primary: #FD7F6B;
3 |
4 | /* 改变 icon 字体路径变量,必需 */
5 | $--font-path: '~element-ui/lib/theme-chalk/fonts';
6 |
7 | @import "~element-ui/packages/theme-chalk/src/index";
--------------------------------------------------------------------------------
/styles/normalize.min.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*# sourceMappingURL=normalize.min.css.map */
--------------------------------------------------------------------------------
/styles/var.scss:
--------------------------------------------------------------------------------
1 | $themeColor: #FD7F6B;
2 | // $themeColor: #4FC5B6;
3 | $lightBg: #f2f2f2;
--------------------------------------------------------------------------------
/test/style.spec.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai'
2 | import { toStyleString, toStyleObj } from '../src/utils/transformStyle'
3 |
4 | const egStyleObj = {
5 | width: 20,
6 | padding: [10, 10, 20, 30],
7 | border: [1, 'solid', '#ccc']
8 | }
9 |
10 | const egStyleStr = 'width:20px;padding:10px 10px 20px 30px;border:1px solid #ccc;'
11 |
12 | describe('样式转换', () => {
13 | it('string to obj', () => {
14 | expect(toStyleObj(egStyleStr)).to.be.equal(egStyleObj)
15 | })
16 |
17 | it('obj to string', () => {
18 | // console.log(toStyleString(egStyleObj))
19 | expect(toStyleString(egStyleObj))
20 | .to.be.equal(egStyleStr)
21 | })
22 | })
23 |
--------------------------------------------------------------------------------
/test/tree.spec.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai'
2 | import { toTree, toList } from '../src/utils/transformTree'
3 | import egTree from '../src/utils/page'
4 |
5 | const egList = [{
6 | id: 'e1',
7 | label: '容器',
8 | type: 'div',
9 | style: 'width:100px;height:100px;background:red;',
10 | pid: 'root',
11 | idx: 0
12 | }, {
13 | id: 'e2',
14 | label: '文字',
15 | type: 'span',
16 | text: 'hhhh',
17 | style: 'width:50px;height:50px;background:pink;',
18 | pid: 'e1',
19 | idx: 0
20 | }, {
21 | id: 'e3',
22 | label: '容器',
23 | type: 'div',
24 | style: 'width:100px;height:100px;background:blue;',
25 | idx: 1,
26 | pid: 'root'
27 | }]
28 |
29 | describe('树形结构转换', () => {
30 | it('tree to list', () => {
31 | console.log(toList(egTree))
32 | // expect(toList(egTree)).to.be.equal(egList)
33 | })
34 |
35 | it('list to tree', () => {
36 | console.log(toTree(egList))
37 | // expect(toTree(egList))
38 | // .to.be.equal(egTree)
39 | })
40 | })
41 |
--------------------------------------------------------------------------------