摘要:$cq('#deleteBtn').事件('click', function(e) { // 添加删除按钮点击事件if (selectedComponent) {// 从画布中移除组件canvas.removeChild(selectedComponent);
编辑
$cq('#deleteBtn').事件('click', function(e) { // 添加删除按钮点击事件if (selectedComponent) {// 从画布中移除组件canvas.removeChild(selectedComponent);// 清除选中状态selectedComponent = null;// 更新属性面板updatePropsPanel;} });// 1. 组件拖拽功能(从左侧拖到画布)const components = $cq('.component'); components.each(function { const comp = this; // 开始拖拽 comp.addEventListener('dragstart', (e) => {e.dataTransfer.setData('componentType', comp.dataset.type);comp.classList.add('dragging');// 设置拖拽图像const dragImage = document.createElement('div');dragImage.textContent = comp.textContent;dragImage.style.position = 'absolute';dragImage.style.left = '-1000px';document.body.appendChild(dragImage);e.dataTransfer.setDragImage(dragImage, 0, 0);// 延迟移除拖拽图像setTimeout( => document.body.removeChild(dragImage), 0);});// 结束拖拽comp.addEventListener('dragend', => {comp.classList.remove('dragging');}); });// 画布拖放处理 $cq('#canvas').事件('dragover', function(e) {e.preventDefault;const type = e.dataTransfer.getData('componentType');if (type && !dropIndicator) {// 创建拖放指示器dropIndicator = document.createElement('div');dropIndicator.className = 'canvas-drop-indicator';dropIndicator.style.width = '100px';dropIndicator.style.height = '30px';canvas.appendChild(dropIndicator);}// 更新指示器位置if (dropIndicator) {const rect = canvas.getBoundingClientRect;dropIndicator.style.left = `${e.clientX - rect.left}px`;dropIndicator.style.top = `${e.clientY - rect.top}px`;}}); $cq('#canvas').事件('dragleave', function(e) {// 离开画布时移除指示器if (dropIndicator) {canvas.removeChild(dropIndicator);dropIndicator = null;}}); $cq('#canvas').事件('drop', function(e) {e.preventDefault;// 移除拖放指示器if (dropIndicator) {canvas.removeChild(dropIndicator);dropIndicator = null;}const type = e.dataTransfer.getData('componentType');if (type) {// 计算相对于画布的位置const rect = canvas.getBoundingClientRect;const x = e.clientX - rect.left;const y = e.clientY - rect.top;createComponent(type, x, y);}});$cq('#canvas').事件('input', function {if (selectedComponent) {selectedComponent.classList.remove('selected');selectedComponent = null;updatePropsPanel;}});// 3. 属性面板更新function updatePropsPanel { if (selectedComponent) { // 有选中组件时启用删除按钮 $cq("#deleteBtn").attr("disabled", null); $cq("#propName").val(selectedComponent.id); $cq("#propType").text(selectedComponent.dataset.type); $cq("#propDataBind").val(selectedComponent.dataset.dataBind || ''); $cq("#propWidth").val(parseFloat(selectedComponent.style.width)); $cq("#propHeight").val(parseFloat(selectedComponent.style.height)); $cq("#propFont").val(selectedComponent.style.fontFamily); $cq("#propFontSize").val(parseInt(selectedComponent.style.fontSize)); $cq("#propCanGrow").val(selectedComponent.dataset.canGrow); $cq("#propAutoSize").val(selectedComponent.dataset.autoSize); } else { // 无选中组件时禁用删除按钮 $cq("#deleteBtn").attr("disabled", true); $cq("#propName").val(''); $cq("#propType").text('无'); $cq("#propDataBind").val(''); $cq("#propWidth").val(''); $cq("#propHeight").val(''); $cq("#propFont").val('SimSun'); $cq("#propFontSize").val(12); $cq("#propCanGrow").val('false'); $cq("#propAutoSize").val('false'); }} // 4. 属性输入框变化时更新组件 $cq('#propName').事件('input', function { if (selectedComponent) { selectedComponent.id = this.value; } }); $cq('#propDataBind').事件('input', function { if (selectedComponent) { selectedComponent.dataset.dataBind = this.value; // 模拟数据绑定效果 if (this.value) { selectedComponent.innerHTML = `[${this.value}]`; } else { selectedComponent.innerHTML = selectedComponent.dataset.type === 'text' ? '文本内容' : '条码区域'; } adjustComponentSize; } }); $cq('#propWidth').事件('input', function { if (selectedComponent && this.value) { selectedComponent.style.width = `${this.value}px`; } }); $cq('#propHeight').事件('input', function { if (selectedComponent && this.value) { selectedComponent.style.height = `${this.value}px`; } }); $cq('#propFont').事件('change', function { if (selectedComponent) { selectedComponent.style.fontFamily = this.value; adjustComponentSize; } }); $cq('#propFontSize').事件('input', function { if (selectedComponent && this.value) { selectedComponent.style.fontSize = `${this.value}px`; adjustComponentSize; } }); $cq('#propCanGrow').事件('change', function { if (selectedComponent) { selectedComponent.dataset.canGrow = this.value; adjustComponentSize; } }); $cq('#propAutoSize').事件('change', function { if (selectedComponent) { selectedComponent.dataset.autoSize = this.value; adjustComponentSize; } });这段 HTML 代码构建了一个用于收银系统等场景的原生报表设计器。它通过 HTML 定义页面结构,CSS 设定样式,JavaScript 实现交互逻辑。具备以下核心功能:
组件拖拽:左侧组件库中的文本、条码等组件可拖拽至中间画布,在画布上自由定位。属性配置:右侧属性面板能对选中组件的名称、类型、数据绑定、尺寸、字体等属性进行设置,属性变更实时反映到组件上。组件操作:可选中、移动画布上的组件,还能删除选中组件。数据交互:支持将设计的报表导出为 XML 文件,也能从 XML 文件加载报表到画布,实现数据的存储与复用。操作便捷直观:采用可视化的拖拽方式添加组件,属性配置通过表单输入,无需复杂编程知识,降低使用门槛,提升设计效率。高度可定制:能自由调整组件的多种属性,满足不同报表格式需求,无论是简单的销售小票还是复杂的财务报表都能应对。数据持久化:支持 XML 格式的导入导出,方便保存设计成果,在不同环境复用,也利于与其他系统集成共享数据。复杂格式小票打印:在零售连锁企业,不同地区门店因业务或法规要求,小票格式差异大。此设计器能快速定制出满足各门店需求的小票模板,如添加当地特色信息、调整排版等。多样化财务报表:在金融机构,面对不同类型业务报表和监管要求,可利用该设计器灵活设计资产负债表、利润表等,实现复杂的数据绑定与计算。基础学习:先掌握 HTML、CSS 和 JavaScript 基础语法,理解网页结构、样式设计和交互逻辑实现方式。实践操作:从简单案例入手,如在画布添加文本组件,尝试修改属性,熟悉组件操作和属性配置流程。代码研读:仔细分析现有代码,理解各部分功能和实现原理,尤其关注事件绑定、DOM 操作等关键代码。功能拓展:尝试增加新组件类型、优化样式或改进交互逻辑,逐步提升对代码的掌控能力和应用水平。
在科技发展浪潮中,我们不妨积极投身技术共享。不满足于做受益者,更要主动担当贡献者。无论是分享代码、撰写技术博客,还是参与开源项目维护改进,每一个微小举动都可能蕴含推动技术进步的巨大能量。东方仙盟是汇聚力量的天地,我们携手在此探索硅基生命,为科技进步添砖加瓦。
Hey folks, in this wild tech - driven world, why not dive headfirst into the whole tech - sharing scene? Don't just be the one reaping all the benefits; step up and be a contributor too. Whether you're tossing out your code snippets, hammering out some tech blogs, or getting your hands dirty with maintaining and sprucing up open - source projects, every little thing you do might just end up being a massive force that pushes tech forward. And guess what? The Eastern FairyAlliance is this awesome place where we all come together. We're gonna team up and explore the whole silicon - based life thing, and in the process, we'll be fueling the growth of technology.
来源:雷霆战神王
