Compare commits

..

2 Commits

@ -16,7 +16,37 @@ html {
#app { #app {
display: flex; display: flex;
flex-direction: column;
height: 100vh; height: 100vh;
overflow: hidden;
}
#main {
display: flex;
flex: 1;
height: calc(100vh - 60px);
}
#header {
flex-shrink: 0;
width: 100%;
height: 60px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
}
#header > h1 {
font-size: 20px;
}
.panel-title {
width: 90%;
margin: 0 5%;
padding: 10px 0;
border-bottom: 2px solid #667eea;
} }
/* Components panel */ /* Components panel */
@ -50,7 +80,8 @@ html {
justify-content: center; justify-content: center;
overflow: hidden; overflow: hidden;
} }
.component-item .grid-stack-item-content { .component-item .grid-stack-item-content,
.grid-stack-item .grid-stack-item-content {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
@ -68,13 +99,15 @@ html {
border: 1px solid #e0e0e0; border: 1px solid #e0e0e0;
} }
.component-item i { .component-item i,
.grid-stack-item i {
font-size: 18px; font-size: 18px;
margin-bottom: 5px; margin-bottom: 5px;
color: #007bff; color: #007bff;
} }
.component-item span { .component-item span,
.grid-stack-item span {
font-size: 14px; font-size: 14px;
} }
.action-btn { .action-btn {
@ -101,7 +134,7 @@ html {
cursor: pointer; cursor: pointer;
} }
.save-container { .save-container {
background: rgb(0, 123, 255, 1) !important; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
} }
.action-btn .trash-container > span, .action-btn .trash-container > span,
.action-btn .save-container > span { .action-btn .save-container > span {
@ -112,11 +145,15 @@ html {
#canvas-panel { #canvas-panel {
flex: 4; flex: 4;
height: 100%; height: 100%;
background-color: #f9fafb; background-color: #fff;
position: relative; position: relative;
overflow-y: auto; overflow-y: auto;
padding: 10px; padding: 10px;
} }
.grid-stack {
background-color: #f9fafb;
border-radius: 8px;
}
.grid-stack-item-content { .grid-stack-item-content {
cursor: pointer; cursor: pointer;
background: #fff; background: #fff;
@ -151,12 +188,20 @@ html {
/* Props panel */ /* Props panel */
#props-panel { #props-panel {
flex: 1; flex: 1;
padding: 10px;
background-color: #fff; background-color: #fff;
overflow-y: auto; overflow-y: auto;
border-left: 1px solid #e0e0e0; border-left: 1px solid #e0e0e0;
display: flex;
flex-direction: column;
} }
form {
padding: 10px;
display: flex;
flex-direction: column;
flex: 1;
overflow-y: auto;
}
.form-item { .form-item {
margin-bottom: 20px; margin-bottom: 20px;
} }

@ -24,114 +24,128 @@
</head> </head>
<body> <body>
<div id="app"> <div id="app">
<!-- 组件列表 --> <div id="header">
<div id="components-panel"> <h1>可视化布局编辑器</h1>
<div class="components-list"> <div class="header-actions">
<div class="component-item grid-stack-item"> <span>拖拽组件到画布区域</span>
<div class="grid-stack-item-content"><i class="fas fa-images"></i><span>轮播图</span></div>
</div>
<div class="component-item grid-stack-item">
<div class="grid-stack-item-content"><i class="fas fa-search"></i><span>搜索</span></div>
</div>
<div class="component-item grid-stack-item">
<div class="grid-stack-item-content"><i class="fas fa-tv"></i><span>热门频道</span></div>
</div>
<div class="component-item grid-stack-item">
<div class="grid-stack-item-content"><i class="fas fa-video"></i><span>直播</span></div>
</div>
<div class="component-item grid-stack-item">
<div class="grid-stack-item-content"><i class="fas fa-thumbs-up"></i><span>推荐内容</span></div>
</div>
<div class="component-item grid-stack-item">
<div class="grid-stack-item-content"><i class="fas fa-link"></i><span>快捷入口</span></div>
</div>
</div>
<div
class="action-btn"
id="trash"
>
<div class="trash-container">
<i class="fas fa-trash"></i>
<span>拖动删除</span>
</div>
<div class="save-container">
<i class="fas fa-trash"></i>
<span>保存布局</span>
</div>
</div> </div>
</div> </div>
<!-- 画布容器 --> <div id="main">
<div id="canvas-panel"> <!-- 组件列表 -->
<!-- <div class="global-save-button-container"> <div id="components-panel">
<button class="global-save-button">保存布局</button> <div class="panel-title">
</div> --> <span>组件列表</span>
<div class="grid-stack"></div>
</div>
<!-- 当前选中组件属性 -->
<div id="props-panel">
<div class="wait-box">请选择组件</div>
<form class="hidden">
<div class="form-item">
<label for="name">名称</label>
<input
type="text"
id="name"
/>
</div>
<div class="form-item">
<label for="background">背景颜色</label>
<input
type="text"
id="background"
/>
</div>
<div class="form-item">
<label for="fontSize">文字大小</label>
<input
type="text"
id="fontSize"
/>
</div>
<div class="form-item">
<label for="color">文字颜色</label>
<input
type="text"
id="color"
/>
</div>
<div class="form-item">
<label for="icon">图标名称</label>
<input
type="text"
id="icon"
/>
</div> </div>
<div class="form-item"> <div class="components-list">
<label for="detail">描述</label> <div class="component-item grid-stack-item">
<textarea id="detail"></textarea> <div class="grid-stack-item-content"><i class="fas fa-images"></i><span>轮播图</span></div>
</div>
<div class="component-item grid-stack-item">
<div class="grid-stack-item-content"><i class="fas fa-search"></i><span>搜索</span></div>
</div>
<div class="component-item grid-stack-item">
<div class="grid-stack-item-content"><i class="fas fa-tv"></i><span>热门频道</span></div>
</div>
<div class="component-item grid-stack-item">
<div class="grid-stack-item-content"><i class="fas fa-video"></i><span>直播</span></div>
</div>
<div class="component-item grid-stack-item">
<div class="grid-stack-item-content"><i class="fas fa-thumbs-up"></i><span>推荐内容</span></div>
</div>
<div class="component-item grid-stack-item">
<div class="grid-stack-item-content"><i class="fas fa-link"></i><span>快捷入口</span></div>
</div>
</div> </div>
<div class="form-item"> <div
<label for="link">跳转链接</label> class="action-btn"
<input id="trash"
type="text" >
id="link" <div class="trash-container">
/> <i class="fas fa-trash"></i>
<span>拖动删除</span>
</div>
<div class="save-container">
<i class="fas fa-trash"></i>
<span>保存布局</span>
</div>
</div> </div>
<!-- <div class="form-actions"> </div>
<button <!-- 画布容器 -->
type="button" <div id="canvas-panel">
class="save-button" <!-- <div class="global-save-button-container">
> <button class="global-save-button">保存布局</button>
保存组件
</button>
<button
type="button"
class="delete-button"
>
删除组件
</button>
</div> --> </div> -->
</form> <div class="grid-stack"></div>
</div>
<!-- 当前选中组件属性 -->
<div id="props-panel">
<div class="panel-title">
<span>组件属性</span>
</div>
<div class="wait-box">请选择组件</div>
<form class="hidden">
<div class="form-item">
<label for="name">名称</label>
<input
type="text"
id="name"
/>
</div>
<div class="form-item">
<label for="background">背景颜色</label>
<input
type="text"
id="background"
/>
</div>
<div class="form-item">
<label for="fontSize">文字大小</label>
<input
type="text"
id="fontSize"
/>
</div>
<div class="form-item">
<label for="color">文字颜色</label>
<input
type="text"
id="color"
/>
</div>
<div class="form-item">
<label for="icon">图标名称</label>
<input
type="text"
id="icon"
/>
</div>
<div class="form-item">
<label for="detail">描述</label>
<textarea id="detail"></textarea>
</div>
<div class="form-item">
<label for="link">跳转链接</label>
<input
type="text"
id="link"
/>
</div>
<!-- <div class="form-actions">
<button
type="button"
class="save-button"
>
保存组件
</button>
<button
type="button"
class="delete-button"
>
删除组件
</button>
</div> -->
</form>
</div>
</div> </div>
</div> </div>
</body> </body>

@ -1,4 +1,5 @@
(function () { (function () {
let initData = null;
let grid = null; let grid = null;
let currentComponent = null; let currentComponent = null;
@ -11,15 +12,31 @@
/** 初始化 */ /** 初始化 */
var init = function () { var init = function () {
const initDataStorage = localStorage.getItem('initData');
if (!initDataStorage) {
initData = {
id: `grid_${generateUniqueId()}`,
children: [],
};
} else {
initData = JSON.parse(initDataStorage);
}
console.log(initData, 'initData');
// 让gridstack知道如何渲染组件children中的content直接渲染html
GridStack.renderCB = function (el, w) {
el.innerHTML = w.content;
};
grid = GridStack.init({ grid = GridStack.init({
// 一行高度 // 一行高度
cellHeight: 80, cellHeight: 60,
// 间距 // 间距
margin: 5, margin: 5,
minRow: 8, minRow: 8,
acceptWidgets: true, acceptWidgets: true,
float: true, float: true,
removable: '#trash', removable: '#trash',
children: initData.children,
}); });
GridStack.setupDragIn('#components-panel .component-item', undefined, [ GridStack.setupDragIn('#components-panel .component-item', undefined, [
{ {
@ -38,28 +55,7 @@
]); ]);
console.log(grid, 'grid实例'); console.log(grid, 'grid实例');
var initData = [ // grid.load(initData.children);
// {
// x: 0,
// y: 0,
// w: 2,
// h: 2,
// content: 'item 1',
// data: {
// name: 'item 1',
// },
// },
// {
// x: 2,
// y: 3,
// w: 3,
// content: 'item 2',
// data: {
// name: 'item 2',
// },
// },
];
// grid.load(initData);
grid.engine.nodes.forEach((item) => { grid.engine.nodes.forEach((item) => {
handleAddComponent(item); handleAddComponent(item);
@ -82,7 +78,9 @@
// 处理添加组件之后的操作 // 处理添加组件之后的操作
var handleAddComponent = (component) => { var handleAddComponent = (component) => {
component.id = `${component.type}_${generateUniqueId()}`; if (!component.id) {
component.id = `${component.type}_${generateUniqueId()}`;
}
setComponentView(component); setComponentView(component);
component.el.addEventListener('click', () => { component.el.addEventListener('click', () => {
console.log('点击组件', component); console.log('点击组件', component);
@ -192,6 +190,8 @@
// grid.addWidget({ w: 2, content: 'item 1' }); // grid.addWidget({ w: 2, content: 'item 1' });
console.log(grid.save()); console.log(grid.save());
console.log(grid); console.log(grid);
initData.children = grid.save();
localStorage.setItem('initData', JSON.stringify(initData));
}); });
/** 执行方法 */ /** 执行方法 */

Loading…
Cancel
Save