thinkphp8+layui多图上传,带删除\排序功能
环境:thinkphp8.1\php8.3\layui2.10; layui的版本必须是2.8.8版本以上;
layui.define(['jquery', 'upload', 'layer'], function (exports) {const $ = layui.jquery;const upload = layui.upload;const layer = layui.layer;const multiUpload = {/*** 初始化上传组件* @param {Object} options*/init: function (options) {const opts = $.extend({elemSelect: '#uploadBtn',elemPreview: '#upload-preview',elemStart: '#startUpload',elemHidden: '#imagePaths',uploadUrl: '/api/index/upload'}, options);let fileMap = new Map();let imgIndex = 0;// 选择图片 + 本地预览upload.render({elem: opts.elemSelect,auto: false,multiple: true,choose: function (obj) {const previewContainer = $(opts.elemPreview);obj.preview(function (index, file, result) {imgIndex++;const id = 'img-' + imgIndex;fileMap.set(id, file);const card = $(`<div class="img-card" id="${id}"><img src="${result}" alt="${file.name}"><button type="button" class="delete-btn" title="删除图片">×</button></div>`);card.find('.delete-btn').on('click', function () {fileMap.delete(id);card.remove();updateImageList();});previewContainer.append(card);});}});// 拖拽排序$(opts.elemPreview).sortable({items: '.img-card',cursor: 'move',opacity: 0.7,tolerance: 'pointer',update: function () {updateImageList();}});// 更新隐藏字段function updateImageList() {const ids = $(opts.elemPreview + ' .img-card').map(function () {return this.id;}).get();$(opts.elemHidden).val(ids.join('|'));}// 更新URL(仅相对路径)function updateImageListUrls() {const urls = [];$(opts.elemPreview + ' .img-card').each(function () {let url = $(this).attr('data-url');if (url) {url = url.replace(/^https?:\/\/[^/]+\/storage\//, '');urls.push(url);}});$(opts.elemHidden).val(urls.join('|'));console.log('当前图片相对路径顺序:', urls.join('|'));}// 点击上传$(opts.elemStart).on('click', function () {const orderedIds = $(opts.elemPreview + ' .img-card').map(function () {return this.id;}).get();if (orderedIds.length === 0) {layer.msg('请先选择图片', { icon: 0 });return;}const formData = new FormData();for (const id of orderedIds) {const file = fileMap.get(id);if (file) formData.append('file[]', file);}layer.msg('上传中...', { icon: 16, shade: 0.3, time: 0 });$.ajax({url: opts.uploadUrl,type: 'POST',data: formData,processData: false,contentType: false,dataType: 'json'}).done(function (res) {layer.closeAll('loading');if (res.code === 0) {const baseUrl = window.location.origin + '/storage/';const urls = res.data.urls.map(p => baseUrl + p);$(opts.elemPreview + ' .img-card').each(function (i) {const img = $(this).find('img');if (urls[i]) img.attr('src', urls[i]);$(this).attr('data-url', urls[i]);});updateImageListUrls();layer.msg('上传成功,共 ' + urls.length + ' 张', { icon: 1 });} else {layer.msg('上传失败:' + res.msg, { icon: 2 });}}).fail(function (xhr, status, error) {layer.closeAll('loading');console.error('AJAX 错误:', status, error);layer.msg('上传接口异常', { icon: 2 });}).always(function () {console.log('上传请求结束');});});// 暴露可用方法return {reload: updateImageListUrls,clear: function () {$(opts.elemPreview).empty();$(opts.elemHidden).val('');fileMap.clear();}};}};// 输出模块exports('multiUpload', multiUpload);
});
定义多图上传模块,放到 layui\modules\multiUpload.js;
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>多图上传,预览,删除,排序(顺序同步)</title><link href="__ADMIN__/layui/css/layui.css" rel="stylesheet"><link href="__INDEX__/jquery-ui/themes/base/jquery-ui.css" rel="stylesheet"><script src="__INDEX__/jquery/jquery.js"></script><script src="__INDEX__/jquery-ui/jquery-ui.min.js"></script><script src="__ADMIN__/layui/layui.js"></script><link href="__INDEX__/upload/upload.css" rel="stylesheet">
</head>
<body>
<div class="layui-container"><div class="layui-upload"><div class="layui-btn-container"><button type="button" class="layui-btn layui-btn-normal" id="uploadBtn"><i class="layui-icon layui-icon-upload"></i> 选择多图</button><button type="button" class="layui-btn layui-btn-danger" id="startUpload"><i class="layui-icon layui-icon-release"></i> 开始上传</button></div><blockquote class="layui-elem-quote layui-quote-nm">预览图(可拖拽排序):<div id="upload-preview" class="layui-upload-list"></div></blockquote><input type="hidden" id="imagePaths" name="images" value=""></div>
</div><script>layui.config({base: '__ADMIN__/' // 模块目录路径}).use(['index', 'multiUpload'], function () {const multiUpload = layui.multiUpload;// 初始化multiUpload.init({elemSelect: '#uploadBtn',elemPreview: '#upload-preview',elemStart: '#startUpload',elemHidden: '#imagePaths',uploadUrl: '/api/index/upload'});});
</script>
</body>
</html>
排序:这里我用到jquery-ui组件的排序功能,版本:1.14;jQuery3.7;
/*** 多图上传接口* 路径:/api/index/upload*/public function upload(): Json{// 获取前端统一上传字段 file[]$files = Request::file('file');if (empty($files)) {return json(['code' => 1, 'msg' => '未选择文件']);}$paths = [];try {foreach ($files as $file) {// 存入 storage/topic/YYYYMMDD/$savePath = Filesystem::putFile("", $file);// 统一路径格式为 /$paths[] = str_replace('\\', '/', $savePath);}} catch (\Throwable $e) {return json(['code' => 2,'msg' => '上传失败:' . $e->getMessage(),]);}// 生成可访问 URL$urls = array_map(fn($p) => $p, $paths);return json(['code' => 0,'msg' => '上传成功','data' => ['paths' => implode('|', $paths),'urls' => $urls,'count' => count($paths),],]);}
这是后端的代码,欢迎大家指正!