Laravel-admin 中 $form->table 图片上传时的 bug 问题

文章描述了在使用laravel-admin的JSON组件时,前端表格中的图片上传功能在编辑后提交时会丢失。作者分析了问题,发现新增时存在图片对象,但在不做改动直接编辑并提交时,图片数据丢失。

使用的是 laravel-admin 的 JSON 组件
问题代码存在与下面的 $form->table 中

protected function form()
{

$form = new Form(new Good());
……
form−>table(′size′,function(form->table('size', function (form>table(size,function(table) {
$table->text(‘sizes’, __(‘规格大小’));
$table->text(‘colors’, __(‘颜色分类’));
$table->text(‘sales’, __(‘价格’));
$table->text(‘sizecostprice’, __(‘成本价格’));
$table->text(‘sizestock’, __(‘库存’));
$table->image(‘sizeimg’, __(‘图片’));
});
……
}
前端展示界面如下:
在这里插入图片描述

加上上面代码后,前台界面显示、上传图片操作、确认提交等操作都正常;
添加完成后,再次编辑该数据,也可以正常显示;

问题在于,在编辑页面,不做任何改动直接提交后,$table->image(‘sizeimg’, __(‘图片’)); 的数据丢失了!
尝试查找原因
分别在新增和编辑时,打印 $form 数据,结果显示
新增时:
在这里插入图片描述

编辑后提交(不做任何改动,如果编辑时重新上传图片,还是可以正常存储到数据库的):
在这里插入图片描述

可以看到,新增时,sizeimg 是存在的,是一个文件对象;编辑提交后,sizeimg 丢失了

发现编辑时 sizeimg 不存在的问题后,考虑到是不是编辑时没有加载该参数 input 元素,所以又到前台编辑页面去查找,结果发现是有的,如下图:
在这里插入图片描述

可以看到,sizeimg 跟其他的 $table->text() 的字段都是同样存在的,但是不明白为什么在提交后会丢失

最后贴一下关于这个方法官方文档的使用说明:
解决方法
public function setSizeAttribute(KaTeX parse error: Expected '}', got 'EOF' at end of input: … if (isset(this->attributes[‘size’])){
oldcontent=jsondecode(old_content = json_decode(oldcontent=jsondecode(this->attributes[‘size’],true);
foreach ($extra as KaTeX parse error: Expected 'EOF', got '&' at position 8: key => &̲val) {
// 如果旧数据未删除,且当前不存在图片,则将旧图片路径添加进去
if (isset(oldcontent[old_content[oldcontent[key]) && !isset($val[‘img’])) {
$val[‘img’] = oldcontent[old_content[oldcontent[key][‘img’] ?? ‘’;
}
}
}
this−>attributes[′attr′]=jsonencode(arrayvalues(this->attributes['attr'] = json_encode(array_values(this>attributes[attr]=jsonencode(arrayvalues(extra));
}

<style type="text/css"> #tNewsInfo-demo { overflow-y: scroll; } .layui-layer-content { overflow: scroll; } </style> <div class="layui-card"> <div class="layui-card-header"> <h2 class="header-title">健康资讯表</h2> <span class="layui-breadcrumb pull-right"> <a href="#!console">首页</a> <a><cite>健康资讯表</cite></a> </span> </div> <div class="layui-card-body"> <div class="layui-row"> <form class="layui-form layui-col-md12 x-so" id="complain_search"> 标题: <div class="layui-input-inline"> <input type="text" name="headline" id="headline" placeholder="请输入标题" autocomplete="off" class="layui-input"> </div> 新闻类型: <div class="layui-input-inline"> <select name="newsName" id="newsName" lay-filter="newsName"> <option value="">---请选择---</option> </select> </div> 发布状态: <div class="layui-input-inline"> <select name="postauditState" id="postauditState"> <option value="" selected>---请选择---</option> <option value="1">未提交</option> <option value="2">正在审核(冻结)</option> <option value="3">审核通过(发布)</option> <option value="4">审核未通过</option> <option value="5">审核通过(发布后冻结)</option> </select> </div> <button id="search" class="layui-btn" lay-submit lay-filter="provinceSearch"> <i class="layui-icon"></i>搜索 </button> <button id="tNewsInfo-btn-add" class="layui-btn icon-btn"><i class="layui-icon"></i>添加</button> </form> </div> <!-- 数据表格 --> <table class="layui-table" id="tNewsInfo-table" lay-filter="tNewsInfo-table"></table> </div> </div> <script type="text/javascript" charset="utf-8" src="module/neditor/neditor.config.js"></script> <script type="text/javascript" charset="utf-8" src="module/neditor/neditor.all.js"></script> <script type="text/javascript" charset="utf-8" src="module/neditor/neditor.service.js"></script> <script type="text/javascript" charset="utf-8" src="module/neditor/i18n/zh-cn/zh-cn.js"></script> <script type="text/javascript" src="module/neditor/third-party/browser-md5-file.min.js"></script> <!-- 表单弹窗 --> <script type="text/html" id="tNewsInfo-model"> <form id="tNewsInfo-form" lay-filter="tNewsInfo-form" class="layui-form model-form"> <input type="hidden" name="id" /> <div class="layui-form-item"> <label class="layui-form-label">新闻类型</label> <div class="layui-input-block"> <select name="newsType" id="newsType" lay-filter="newsType"> <option value="">-请选择新闻类型-</option> </select> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">标题</label> <div class="layui-input-block"> <input name="headline" placeholder="请输入标题" type="text" class="layui-input" maxlength="20" lay-verify="required" required /> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">发布间</label> <div class="layui-input-block"> <input name="pubdate" id="pubdate" placeholder="请输入发布间" type="text" class="layui-input" maxlength="20" lay-verify="required" required /> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">文本类型</label> <div class="layui-input-block"> <input type="radio" name="ctype" value="1" title="富文本" checked /> <input type="radio" name="ctype" value="2" title="超链接" /> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">封面图片:</label> <div class="layui-upload layui-input-block"> <input type="hidden" name="thumbnail" /> <button type="button" class="layui-btn layui-btn-primary" id="fileBtn"> <i class="layui-icon"></i>选择文件 </button> </div> <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;"> 预览图: <div class="layui-upload-list" id="demo2"></div> </blockquote> </div> <div class="layui-form-item"> <label class="layui-form-label">资讯内容</label> <div class="layui-input-block"> <textarea name="contents" id="contents"></textarea> </div> </div> <div class="layui-form-item model-form-footer"> <button class="layui-btn layui-btn-primary" ew-event="closeDialog" type="button">取消</button> <button class="layui-btn" lay-filter="tNewsInfo-form-submit" lay-submit>保存</button> </div> </form> </script> <!-- 新闻状态列 --> <script type="text/html" id="newsinfo-table-state"> <input type="checkbox" lay-filter="newsinfo-table-state" value="{{d.id}}" lay-skin="switch" lay-text="发布|冻结" {{d.postauditState==3?'checked':''}} /> </script> <script type="text/html" id="newsinfo-table-stick"> <input type="checkbox" lay-filter="newsinfo-table-stick" value="{{d.id}}" lay-skin="switch" lay-text="置顶|取消" {{d.stick==0?'checked':''}} /> </script> <!-- 表格操作列 --> <script type="text/html" id="tNewsInfo-table-bar"> <a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="edit">修改</a> <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a> </script> <script> layui.use(['form', 'table', 'util', 'config', 'admin', 'formSelects', "layedit", "laydate", "upload"], function () { var form = layui.form; var table = layui.table; var config = layui.config; var layer = layui.layer; var util = layui.util; var admin = layui.admin; var formSelects = layui.formSelects; var layedit = layui.layedit; var laydate = layui.laydate; var upload = layui.upload; // 渲染表格 var renderTable = function () { table.render({ id: "provinceReload", elem: '#tNewsInfo-table', url: config.base_server + 'api-primaryJydc/newsinfo/getList', where: { access_token: config.getToken().access_token }, page: true, cols: [[ { type: 'numbers', title: '序号' }, { field: 'typeName', sort: true, title: '新闻类型' }, { field: 'headline', sort: true, title: '标题' }, { field: 'postauditState', sort: true, templet: "#newsinfo-table-state", title: '帖子状态 ' }, { field: 'pubdate', sort: true, templet: function (d) { return util.toDateString(d.pubdate); }, title: '发布间' }, { field: 'updateTime', sort: true, templet: function (d) { return util.toDateString(d.updateTime); }, title: '更新间' }, { field: 'stick', sort: true, templet: "#newsinfo-table-stick", title: '置顶' }, { align: 'center', toolbar: '#tNewsInfo-table-bar', title: '操作', width: 250 } ]] }); }; renderTable(); // 添加按钮点击事件 $('#tNewsInfo-btn-add').click(function () { showEditModel(); }); // 初始化新闻类别查询框 var getNewsType = function () { admin.req('api-primaryJydc/newsinfo/selectAllType', {}, function (datas) { $.each(datas.data, function (index, item) { var options = '<option value = "' + item.id + '">' + item.newsType + '</option>'; $('#newsName').append(options); // 往下拉菜单里添加元素 }); }, 'GET'); form.render('select'); }; getNewsType(); // 表单提交事件 form.on('submit(tNewsInfo-form-submit)', function (data) { layer.load(2); var url = ""; data.field.publishUserid = config.getUser().id; data.field.freezeUserid = config.getUser().id; if (data.field.id == '') { url = 'api-primaryJydc/newsinfo/' + 'save'; } else { url = 'api-primaryJydc/newsinfo/' + 'update'; } admin.req(url, JSON.stringify(data.field), function (data) { layer.closeAll('loading'); if (data.resp_code == 0) { layer.msg(data.resp_msg, { icon: 1, time: 500 }); table.reload('tNewsInfo-table'); layer.closeAll('page'); } else { layer.msg(data.resp_msg, { icon: 2, time: 500 }); } }, $('#tNewsInfo-form').attr('method')); return false; }); // 工具条点击事件 table.on('tool(tNewsInfo-table)', function (obj) { var data = obj.data; if (obj.event === 'edit') { // 修改 showEditModel(data); } else if (obj.event === 'del') { // 删除 doDelete(obj); } }); // 显示编辑弹窗 var showEditModel = function (data) { layer.open({ type: 1, title: data ? '修改健康资讯表' : '添加健康资讯表', area: ['1000px', '800px'], offset: '10px', maxmin: true, id: 'tNewsInfo-demo', skin: 'tNewsInfo-demo', content: $('#tNewsInfo-model').html(), resize: true, success: function () { admin.req('api-primaryJydc/newsinfo/selectAllType', {}, function (datas) { layer.closeAll('loading'); $.each(datas.data, function (index, item) { var option = '<option value = "' + item.id + '">' + item.newsType + '</option>'; $('#newsType').append(option); // 往下拉菜单里添加元素 }); }, 'GET'); $('#tNewsInfo-form')[0].reset(); $('#tNewsInfo-form').attr('method', 'POST'); if (data) { data.pubdate = util.toDateString(data.pubdate); $("input[name=ctype][value='1']").attr("checked", data.ctype == 1 ? true : false); $("input[name=ctype][value='2']").attr("checked", data.ctype == 2 ? true : false); form.val('tNewsInfo-form', data); var picture1 = data.thumbnail; if (null != picture1) { if (picture1.indexOf("http") != 0) { picture1 = "http://www.j1dc.cn/sss-web/download?filePath=" + picture1; } $('#demo2').append('<img src="' + picture1 + '" width="50px" height="50px" class="layui-upload-img">'); } form.render(); } // 初始化日期选择器 laydate.render({ elem: '#pubdate', type: 'datetime', format: 'yyyy-MM-dd HH:mm:ss' }); UE.delEditor('contents'); UE.getEditor('contents', { initialFrameHeight: 320, imageMaxSize: 1024 * 1024 * 10 // 设置上传图片的最大大小为 10MB }); loadingUpdate(); }, resizing: function (layero) { $(".layui-layer-content").css("height", $(layero).height() - 45); $("#tNewsInfo-demo").css("overflow", "scroll"); }, min: function (layero) { $(".layui-layer-content").css("height", $(layero).height() - 45); $("#tNewsInfo-demo").css("overflow", "scroll"); }, full: function (layero) { $(".layui-layer-content").css("height", $(layero).height() - 45); $("#tNewsInfo-demo").css("overflow", "scroll"); }, restore: function (layero) { $(".layui-layer-content").css("height", $(layero).height() - 45); $("#tNewsInfo-demo").css("overflow", "scroll"); } }); }; // 删除 var doDelete = function (obj) { layer.confirm('确定要删除吗?', function (i) { layer.close(i); layer.load(2); admin.req('api-primaryJydc/newsinfo/delete/' + obj.data.id, {}, function (data) { layer.closeAll('loading'); if (data.resp_code == 0) { layer.msg(data.resp_msg, { icon: 1, time: 500 }); obj.del(); } else { layer.msg(data.resp_msg, { icon: 2, time: 500 }); } }, 'DELETE'); }); }; // 修改新闻状态 form.on('switch(newsinfo-table-state)', function (obj) { layer.load(2); admin.req('api-primaryJydc/newsinfo/updateEnabled', { id: obj.elem.value, postauditState: obj.elem.checked ? 3 : 5, freezeUserid: config.getUser().id }, function (data) { layer.closeAll('loading'); if (data.resp_code == 0) { layer.msg(data.resp_msg, { icon: 1, time: 500 }); } else { layer.msg(data.resp_msg, { icon: 2, time: 500 }); $(obj.elem).prop('checked', !obj.elem.checked); form.render('checkbox'); } }, 'GET'); }); // 文件上传 var loadingUpdate = function () { upload.render({ elem: '#fileBtn', url: config.base_server + 'api-file/files-anon', accept: 'file', auto: true, before: function (obj) { layer.load(); // 上传loading this.data = { access_token: config.getToken().access_token }; // 预读本地文件示例,不支持ie8 obj.preview(function (index, file, result) { $(".layui-upload-img").remove(); $('#demo2').append('<img src="' + result + '" width="50px" height="50px" alt="' + file.name + '" class="layui-upload-img">'); }); }, done: function (data) { layer.closeAll('loading'); $("[name=thumbnail]").val(data.datas.url); // 移除了将图片插入富文本编辑器的代码 }, error: function (data) { layer.closeAll('loading'); } }); }; // 修改新闻置顶状态 form.on('switch(newsinfo-table-stick)', function (obj) { layer.load(2); admin.req('api-primaryJydc/newsinfo/updateStick', { id: obj.elem.value, stick: obj.elem.checked ? 0 : 1, freezeUserid: config.getUser().id }, function (data) { layer.closeAll('loading'); if (data.resp_code == 0) { layer.msg(data.resp_msg, { icon: 1, time: 500 }); } else { layer.msg(data.resp_msg, { icon: 2, time: 500 }); $(obj.elem).prop('checked', !obj.elem.checked); form.render('checkbox'); } }, 'GET'); }); // 搜索框查询加载方法 form.on('submit(provinceSearch)', function (data) { var formData = data.field; console.debug(formData); var newsType = formData.newsName, headline = formData.headline, postauditState = formData.postauditState; table.reload('provinceReload', { where: { access_token: config.getToken().access_token, newsType: newsType, headline: headline, postauditState: postauditState } }); return false; }); }); </script> 修改添加按钮点击的候刷新的错误,修改富文本有候会失效的错误,保持原来页面的样子
最新发布
07-18
在修复 `layui` 页面中添加按钮导致页面刷新的问题以及富文本编辑器失效的 bug ,需要从以下几个方面入手:阻止默认表单提交行为、确保编辑器正确初始化,并且避免 DOM 元素被错误销毁或重复加载。 ### 阻止按钮点击导致的页面刷新 页面刷新通常由 `<form>` 表单的默认提交行为引起。可以通过以下方式阻止: - 在事件处理函数中使用 `event.preventDefault()` 来阻止默认行为。 - 或者在 HTML 中将按钮的 `type` 属性设置为 `"button"`,而非 `"submit"`。 示例代码如下: ```html <button type="button" id="addBtn">添加</button> ``` JavaScript 代码: ```javascript document.getElementById("addBtn").addEventListener("click", function(event) { // 处理添加逻辑 console.log("添加操作执行"); }); ``` ### 解决富文本编辑器失效问题 对于 `layui` 富文本编辑器(`layedit`)失效的情况,需确保编辑器实例在 DOM 完全加载后才进行初始化。如果编辑器是在弹出层中创建的,则应在弹出层打开后的回调函数中构建编辑器[^2]。 示例代码如下: ```javascript var editIndex, layedit; layui.use('layedit', function () { layedit = layui.layedit; var openPop = layer.open({ title: '打开弹出层', area: ['800px', '700px'], type: 1, btn: ["确定", "取消"], content: $("#demo"), success: function () { // 建立编辑器 editIndex = layedit.build('eyeCycDesc', { tool: ['strong', 'italic', 'underline', 'del', '|', 'left', 'center', 'right'] }); // layedit赋值操作 layedit.setContent(editIndex, hospInfo.content, false); }, cancel: function () { }, yes: function (index, layero) { } }); }); ``` ### 保持原有样式不变 为了保持原有样式不变,应避免对现有 CSS 样式进行不必要的修改。同,在动态插入或更新 DOM 元素,应确保新元素的类名和结构与原页面一致。 例如,如果使用 JavaScript 动态添加内容到页面中,可以参考以下代码: ```javascript var newDiv = document.createElement("div"); newDiv.className = "layui-form-item"; // 保持原有类名 newDiv.innerHTML = '<label class="layui-form-label">新输入框</label><div class="layui-input-block"><input type="text" name="title" lay-verify="required" placeholder="请输入" class="layui-input"></div>'; document.getElementById("container").appendChild(newDiv); ``` ### XSS 安全防护 为防止富文本编辑器引发的 XSS 攻击,建议在输出用户提交的内容之前,使用 `js-xss` 进行过滤[^3]。以下是浏览器端使用的示例: ```html <script src="https://rawgit.com/leizongmin/js-xss/master/dist/xss.js"></script> <script> var html = filterXSS('<script>alert("xss");</script>'); document.getElementById("output").innerHTML = html; </script> <div id="output"></div> ``` 通过上述方法,可以在修复页面功能的同,确保安全性与用户体验不受影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值