deepseek v3 0324实现低代码前端编辑器 HTML
下面是一个简单的低代码前端编辑器的 HTML 实现,包含了基本的拖拽组件、属性编辑和预览功能。功能说明这个低代码前端编辑器包含以下功能:左侧组件面板:中间画布区域:右侧属性面板:基本交互功能:要使这个编辑器更实用,你可以考虑添加以下功能:这个实现是一个基础版本,你可以根据需要进行扩展和定制。
·
下面是一个简单的低代码前端编辑器的 HTML 实现,包含了基本的拖拽组件、属性编辑和预览功能。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>低代码前端编辑器</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
display: flex;
height: 100vh;
overflow: hidden;
}
/* 左侧组件面板 */
.components-panel {
width: 200px;
background-color: #f0f0f0;
padding: 10px;
border-right: 1px solid #ccc;
overflow-y: auto;
}
.component-item {
padding: 8px;
margin-bottom: 8px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 4px;
cursor: grab;
user-select: none;
}
.component-item:hover {
background-color: #e9e9e9;
}
/* 中间画布 */
.canvas {
flex: 1;
padding: 20px;
background-color: #f9f9f9;
overflow: auto;
position: relative;
}
.canvas-container {
min-height: 100%;
background-color: white;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
position: relative;
}
/* 右侧属性面板 */
.properties-panel {
width: 250px;
background-color: #f0f0f0;
padding: 10px;
border-left: 1px solid #ccc;
overflow-y: auto;
}
.property-group {
margin-bottom: 15px;
}
.property-group h3 {
margin-bottom: 8px;
font-size: 14px;
color: #555;
}
.property-item {
margin-bottom: 8px;
}
.property-item label {
display: block;
margin-bottom: 4px;
font-size: 12px;
color: #666;
}
.property-item input, .property-item select, .property-item textarea {
width: 100%;
padding: 6px;
border: 1px solid #ddd;
border-radius: 4px;
}
/* 顶部工具栏 */
.toolbar {
background-color: #333;
color: white;
padding: 10px;
display: flex;
justify-content: space-between;
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 100;
}
.toolbar button {
background-color: #555;
color: white;
border: none;
padding: 6px 12px;
margin-right: 5px;
border-radius: 4px;
cursor: pointer;
}
.toolbar button:hover {
background-color: #666;
}
/* 画布上的组件 */
.canvas-component {
position: absolute;
border: 1px dashed #ccc;
padding: 10px;
background-color: white;
cursor: move;
}
.canvas-component.selected {
border: 1px solid #4a90e2;
background-color: #f0f7ff;
}
.resize-handle {
width: 10px;
height: 10px;
background-color: #4a90e2;
position: absolute;
right: 0;
bottom: 0;
cursor: nwse-resize;
}
</style>
</head>
<body>
<!-- 左侧组件面板 -->
<div class="components-panel">
<h2>组件</h2>
<div class="component-item" draggable="true" data-type="button">按钮</div>
<div class="component-item" draggable="true" data-type="text">文本</div>
<div class="component-item" draggable="true" data-type="input">输入框</div>
<div class="component-item" draggable="true" data-type="image">图片</div>
<div class="component-item" draggable="true" data-type="container">容器</div>
</div>
<!-- 中间画布 -->
<div class="canvas">
<div class="toolbar">
<div>
<button id="preview-btn">预览</button>
<button id="save-btn">保存</button>
<button id="clear-btn">清空</button>
</div>
<div>
<button id="undo-btn">撤销</button>
<button id="redo-btn">重做</button>
</div>
</div>
<div class="canvas-container" id="canvas-container">
<!-- 组件将在这里被添加 -->
</div>
</div>
<!-- 右侧属性面板 -->
<div class="properties-panel">
<h2>属性</h2>
<div id="properties-content">
<p>选择一个组件来编辑其属性</p>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const canvasContainer = document.getElementById('canvas-container');
const propertiesContent = document.getElementById('properties-content');
let selectedComponent = null;
// 组件计数器
let componentCount = 0;
// 默认组件属性
const componentDefaults = {
button: {
text: '按钮',
color: '#ffffff',
bgColor: '#4a90e2',
width: '100px',
height: '40px',
fontSize: '14px'
},
text: {
content: '这是一段文本',
color: '#333333',
fontSize: '16px',
fontWeight: 'normal'
},
input: {
placeholder: '请输入内容',
width: '200px',
height: '30px'
},
image: {
src: 'https://via.placeholder.com/150',
width: '150px',
height: '150px'
},
container: {
width: '300px',
height: '200px',
bgColor: '#f0f0f0'
}
};
// 为组件面板中的项目添加拖拽功能
document.querySelectorAll('.component-item').forEach(item => {
item.addEventListener('dragstart', function(e) {
e.dataTransfer.setData('text/plain', this.getAttribute('data-type'));
});
});
// 画布接收拖拽
canvasContainer.addEventListener('dragover', function(e) {
e.preventDefault();
});
canvasContainer.addEventListener('drop', function(e) {
e.preventDefault();
const componentType = e.dataTransfer.getData('text/plain');
addComponentToCanvas(componentType, e.clientX - this.getBoundingClientRect().left, e.clientY - this.getBoundingClientRect().top);
});
// 添加组件到画布
function addComponentToCanvas(type, x, y) {
componentCount++;
const id = `component-${componentCount}`;
const component = document.createElement('div');
component.className = 'canvas-component';
component.id = id;
component.style.left = `${x}px`;
component.style.top = `${y}px`;
// 设置默认属性
const defaults = componentDefaults[type];
// 根据类型创建不同的内容
switch(type) {
case 'button':
component.innerHTML = `<button style="width:${defaults.width};height:${defaults.height};background-color:${defaults.bgColor};color:${defaults.color};font-size:${defaults.fontSize}">${defaults.text}</button>`;
component.dataset.props = JSON.stringify(defaults);
break;
case 'text':
component.innerHTML = `<div style="color:${defaults.color};font-size:${defaults.fontSize};font-weight:${defaults.fontWeight}">${defaults.content}</div>`;
component.dataset.props = JSON.stringify(defaults);
break;
case 'input':
component.innerHTML = `<input type="text" placeholder="${defaults.placeholder}" style="width:${defaults.width};height:${defaults.height}">`;
component.dataset.props = JSON.stringify(defaults);
break;
case 'image':
component.innerHTML = `<img src="${defaults.src}" style="width:${defaults.width};height:${defaults.height}" alt="图片">`;
component.dataset.props = JSON.stringify(defaults);
break;
case 'container':
component.style.width = defaults.width;
component.style.height = defaults.height;
component.style.backgroundColor = defaults.bgColor;
component.dataset.props = JSON.stringify(defaults);
break;
}
// 添加调整大小手柄
const resizeHandle = document.createElement('div');
resizeHandle.className = 'resize-handle';
component.appendChild(resizeHandle);
// 点击选择组件
component.addEventListener('mousedown', function(e) {
if (e.target === resizeHandle) return;
// 取消之前选择的组件
if (selectedComponent) {
selectedComponent.classList.remove('selected');
}
// 选择当前组件
selectedComponent = this;
this.classList.add('selected');
// 显示属性面板
showPropertiesPanel(type, JSON.parse(this.dataset.props), id);
// 阻止事件冒泡,避免触发画布的点击事件
e.stopPropagation();
});
// 调整大小
resizeHandle.addEventListener('mousedown', function(e) {
e.preventDefault();
e.stopPropagation();
const startX = e.clientX;
const startY = e.clientY;
const startWidth = parseInt(component.style.width) || parseInt(getComputedStyle(component).width);
const startHeight = parseInt(component.style.height) || parseInt(getComputedStyle(component).height);
function doResize(e) {
const newWidth = startWidth + (e.clientX - startX);
const newHeight = startHeight + (e.clientY - startY);
component.style.width = `${newWidth}px`;
component.style.height = `${newHeight}px`;
// 更新属性
const props = JSON.parse(component.dataset.props);
props.width = `${newWidth}px`;
props.height = `${newHeight}px`;
component.dataset.props = JSON.stringify(props);
}
function stopResize() {
window.removeEventListener('mousemove', doResize);
window.removeEventListener('mouseup', stopResize);
}
window.addEventListener('mousemove', doResize);
window.addEventListener('mouseup', stopResize);
});
// 拖动组件
component.addEventListener('mousedown', function(e) {
if (e.target === resizeHandle) return;
const startX = e.clientX;
const startY = e.clientY;
const startLeft = parseInt(component.style.left) || 0;
const startTop = parseInt(component.style.top) || 0;
function doDrag(e) {
const newLeft = startLeft + (e.clientX - startX);
const newTop = startTop + (e.clientY - startY);
component.style.left = `${newLeft}px`;
component.style.top = `${newTop}px`;
}
function stopDrag() {
window.removeEventListener('mousemove', doDrag);
window.removeEventListener('mouseup', stopDrag);
}
window.addEventListener('mousemove', doDrag);
window.addEventListener('mouseup', stopDrag);
});
canvasContainer.appendChild(component);
// 选择新添加的组件
component.click();
}
// 显示属性面板
function showPropertiesPanel(type, props, id) {
let html = `<div class="property-group">
<h3>${type} 属性</h3>`;
switch(type) {
case 'button':
html += `
<div class="property-item">
<label>文本</label>
<input type="text" value="${props.text}" data-prop="text">
</div>
<div class="property-item">
<label>宽度</label>
<input type="text" value="${props.width}" data-prop="width">
</div>
<div class="property-item">
<label>高度</label>
<input type="text" value="${props.height}" data-prop="height">
</div>
<div class="property-item">
<label>背景色</label>
<input type="color" value="${props.bgColor}" data-prop="bgColor">
</div>
<div class="property-item">
<label>文字颜色</label>
<input type="color" value="${props.color}" data-prop="color">
</div>
<div class="property-item">
<label>字体大小</label>
<input type="text" value="${props.fontSize}" data-prop="fontSize">
</div>
`;
break;
case 'text':
html += `
<div class="property-item">
<label>内容</label>
<textarea data-prop="content">${props.content}</textarea>
</div>
<div class="property-item">
<label>颜色</label>
<input type="color" value="${props.color}" data-prop="color">
</div>
<div class="property-item">
<label>字体大小</label>
<input type="text" value="${props.fontSize}" data-prop="fontSize">
</div>
<div class="property-item">
<label>字体粗细</label>
<select data-prop="fontWeight">
<option value="normal" ${props.fontWeight === 'normal' ? 'selected' : ''}>正常</option>
<option value="bold" ${props.fontWeight === 'bold' ? 'selected' : ''}>加粗</option>
</select>
</div>
`;
break;
case 'input':
html += `
<div class="property-item">
<label>占位文本</label>
<input type="text" value="${props.placeholder}" data-prop="placeholder">
</div>
<div class="property-item">
<label>宽度</label>
<input type="text" value="${props.width}" data-prop="width">
</div>
<div class="property-item">
<label>高度</label>
<input type="text" value="${props.height}" data-prop="height">
</div>
`;
break;
case 'image':
html += `
<div class="property-item">
<label>图片URL</label>
<input type="text" value="${props.src}" data-prop="src">
</div>
<div class="property-item">
<label>宽度</label>
<input type="text" value="${props.width}" data-prop="width">
</div>
<div class="property-item">
<label>高度</label>
<input type="text" value="${props.height}" data-prop="height">
</div>
`;
break;
case 'container':
html += `
<div class="property-item">
<label>宽度</label>
<input type="text" value="${props.width}" data-prop="width">
</div>
<div class="property-item">
<label>高度</label>
<input type="text" value="${props.height}" data-prop="height">
</div>
<div class="property-item">
<label>背景色</label>
<input type="color" value="${props.bgColor}" data-prop="bgColor">
</div>
`;
break;
}
html += `</div>
<button id="update-props" data-id="${id}">更新属性</button>`;
propertiesContent.innerHTML = html;
// 为更新按钮添加事件
document.getElementById('update-props').addEventListener('click', function() {
updateComponentProperties(this.getAttribute('data-id'), type);
});
}
// 更新组件属性
function updateComponentProperties(id, type) {
const component = document.getElementById(id);
if (!component) return;
const inputs = propertiesContent.querySelectorAll('[data-prop]');
const props = {};
inputs.forEach(input => {
const propName = input.getAttribute('data-prop');
props[propName] = input.value;
});
// 更新组件数据
component.dataset.props = JSON.stringify(props);
// 根据类型更新组件显示
switch(type) {
case 'button':
component.innerHTML = `<button style="width:${props.width};height:${props.height};background-color:${props.bgColor};color:${props.color};font-size:${props.fontSize}">${props.text}</button>`;
break;
case 'text':
component.innerHTML = `<div style="color:${props.color};font-size:${props.fontSize};font-weight:${props.fontWeight}">${props.content}</div>`;
break;
case 'input':
component.innerHTML = `<input type="text" placeholder="${props.placeholder}" style="width:${props.width};height:${props.height}">`;
break;
case 'image':
component.innerHTML = `<img src="${props.src}" style="width:${props.width};height:${props.height}" alt="图片">`;
break;
case 'container':
component.style.width = props.width;
component.style.height = props.height;
component.style.backgroundColor = props.bgColor;
break;
}
// 重新添加调整大小手柄
const resizeHandle = document.createElement('div');
resizeHandle.className = 'resize-handle';
component.appendChild(resizeHandle);
}
// 点击画布空白处取消选择
canvasContainer.addEventListener('mousedown', function(e) {
if (e.target === this && selectedComponent) {
selectedComponent.classList.remove('selected');
selectedComponent = null;
propertiesContent.innerHTML = '<p>选择一个组件来编辑其属性</p>';
}
});
// 预览按钮
document.getElementById('preview-btn').addEventListener('click', function() {
alert('预览功能将在新窗口打开当前设计的页面');
// 实际实现中可以打开一个新窗口或切换到预览模式
});
// 保存按钮
document.getElementById('save-btn').addEventListener('click', function() {
alert('设计已保存');
// 实际实现中可以保存到本地或服务器
});
// 清空按钮
document.getElementById('clear-btn').addEventListener('click', function() {
if (confirm('确定要清空画布吗?')) {
canvasContainer.innerHTML = '';
propertiesContent.innerHTML = '<p>选择一个组件来编辑其属性</p>';
selectedComponent = null;
}
});
});
</script>
</body>
</html>
功能说明
这个低代码前端编辑器包含以下功能:
-
左侧组件面板:
- 提供可拖拽的基础组件(按钮、文本、输入框、图片、容器)
-
中间画布区域:
- 接收拖放的组件
- 支持组件的选择、移动和调整大小
- 显示当前设计的布局
-
右侧属性面板:
- 显示选中组件的可编辑属性
- 支持实时更新组件样式和内容
-
基本交互功能:
- 拖拽添加组件
- 组件选择和属性编辑
- 组件移动和调整大小
- 预览、保存和清空功能
扩展建议
要使这个编辑器更实用,你可以考虑添加以下功能:
- 撤销/重做功能
- 组件层级管理(置顶、置底)
- 组件复制/粘贴
- 响应式布局设置
- 导出为HTML/CSS代码
- 保存到本地存储或服务器
- 更多组件类型(表格、列表、导航栏等)
- 组件对齐辅助线
- 网格布局支持
这个实现是一个基础版本,你可以根据需要进行扩展和定制。
更多推荐
所有评论(0)