[代码分享] 基于 layui 封装的后台上传功能,前端苦手的福音 [大佬慎点]
功能:查看、复制 url、替换和移除。
开发使用和用户使用都简单。
前端苦手、伸手党福音。
授人以鱼,就授人以鱼。
如果你不用 layui,也可以参考一下~
话说,社区是否考虑加一个 帖子附件 功能?可以附加小文件~
效果
里面那些文字,,,如果系统中已经引入了图标库,可自行改为图标,会好看一点,当然样式也可能要相应的调整。
紫色 可自行改为自己后台的主题色~~
使用方式
模板
<!-- head 中 -->
<link rel="stylesheet" href="{{ asset('layui/css/layui.css') }}">
<link rel="stylesheet" href="{{ asset('upload.css') }}">
<!-- body 中 -->
<form action="/user/test" method="post">
<div style="float: left; margin-right: 10px;">
<h2>初始化值</h2>
<!-- 使用 up-uploader 类标记 -->
<div class="up-uploader" data-value="/uploads/7c0d7ef03a7eb04ce795b0f60e68e7e1.txt"></div>
</div>
<div>
<h2>头像</h2>
<div class="up-uploader" data-input-name="avatar"></div>
</div>
<div>
<h2>相册</h2>
<div
class="up-uploader"
data-input-name="photos[]"
data-max="8"
data-full-url="true"
></div>
</div>
<div>
<h2><button type="submit">提交</button></h2>
</div>
</form>
<script src="{{ asset('layui/layui.js') }}"></script>
<!-- 其实可以用 layui 的自定义模块加载,这里算了,效果一样 -->
<script src="{{ asset('upload.js') }}"></script>
上传返回
可自行调整,JS 中也要稍微调整下
return response()->json([
'code' => 0, // 0 - 成功,其他 - 失败
'msg' => '上传成功',
'data' => [
'full_url' => 'http://chat.l.com'.$storage->url('uploads/'.$filename), // 全路径,并没有用到
'path' => '/uploads/'.$filename, // 相对路径
],
]);
提交后的数据
array:4 [▼
"up_file" => null // 这个选择文件的那个 input 框的值,忽略即可
"file" => "/uploads/7c0d7ef03a7eb04ce795b0f60e68e7e1.txt"
"avatar" => "/uploads/61c1b32a961b0d868a78dae00e4997f9.png"
"photos" => array:2 [▼
0 => "http://chat.l.com/uploads/53c7473b75cf9adcb8540fdf3a2022eb.png"
1 => "http://chat.l.com/uploads/61c1b32a961b0d868a78dae00e4997f9.png"
]
]
代码
JS
upload.js
layui
.define(['upload', 'laytpl', 'layer'], function (exports) {
var log = console.log // 开发测试时的简写
var upload = layui.upload
var laytpl = layui.laytpl
var layer = layui.layer
var $ = layui.jquery
var domain = location.origin // 自行修改,注意末尾的斜杠
var uploadUrl = domain + '/upload/test' // 同上
/**
* 上传完成后,渲染的 html 元素 模板
* @type {string}
*/
var itemTpl =
'<div class="up-item">' +
' {{# if (d.isImage) { }}' +
' <img src="{{ d.src }}" class="up-image">' +
' {{# } else { }}' +
' <div class="up-file">已上传文件</div>' +
' {{# } }}' +
' <div class="up-actions">' +
' <span class="up-action up-copy" title="复制:{{ d.src }}">复制</span>' +
' <a ' +
' href="{{ d.src }}" target="_blank" title="查看" ' +
' class="up-action {{# if (d.isImage) { }} up-preview {{# } }}"' +
' >查看</a>' +
' {{# if (!d.readOnly) { }}' +
' <span class="up-action up-replace" title="替换">替换</span>' +
' <span class="up-action up-remove" title="移除">移除</span>' +
' {{# } }}' +
' </div>' +
' <input name="{{ d.inputName }}" hidden value="{{ d.val }}">' +
'</div>'
/**
* 简单判断是不是图片地址
* @param {string} path
* @return {boolean}
*/
var isImage = function (path) {
var t = path.toLowerCase().split('.')
var ext = t.length <= 1
? ''
: t[t.length - 1]
var imageExts = [
'jpg', 'jpeg', 'gif', 'png', 'bmp', 'ico', 'webp', 'svg', 'tiff',
]
return imageExts.indexOf(ext) !== -1
}
/**
* 简单判断是不是全路径地址
* @param {string} url
* @return {boolean}
*/
var isFullUrl = function (url) {
url = url.toLowerCase()
return (url.indexOf('https://') === 0) ||
(url.indexOf('http://') === 0)
}
/**
* 复制文本到剪贴板
* @param {string} text
* @return {boolean}
*/
var copyText = function (text) {
var $copyInput = $('<input style="position: fixed !important; top: -9999px !important;" value="' + text + '">')
$('body').append($copyInput)
$copyInput.select()
var res = document.execCommand('copy')
$copyInput.remove()
return res
}
/**
* 手动渲染一个上传器
* @param $wrapper 一个 jQuery 元素
* @param overOptions 可选,覆盖 html 元素中设置的配置
*/
var renderUploader = function ($wrapper, overOptions) {
// 覆盖的配置
if (overOptions) {
var keys = Object.keys(overOptions)
for (var i = 0; i < keys.length; i++) {
var k = keys[i]
$wrapper.data(k, overOptions[k])
}
}
// 可选配置的默认配置
// 有的是 layui upload 的,可参考 layui 文档
var defaultOptions = {
field: 'up_file',
size: 2048,
accept: 'images',
acceptMime: 'image/*',
max: 1, // 最多上传多少张
fullUrl: false, // input 的值,是否设置为全路径
inputName: 'file', // input 的 name 属性,尽量别和前面的 field 一样,虽然没影响
readOnly: false, // 只读情况下,只有查看和复制操作
value: '', // 默认的文件 url 值,用于初始化显示,多个值用英文逗号分隔
}
var options = $.extend(defaultOptions, $wrapper.data())
/**
* layui 上传实例
*/
var uploaderIns
/**
* 获取当前文件已经上传了多少个
*
* @return {number}
*/
var getItemsCount = function () {
return $itemsWrapper.children().length
}
/**
* 判断是否达到最大上传数
* @return {boolean}
*/
var isMax = function () {
return (options.max != 0) && (getItemsCount() >= options.max)
}
/**
* 根据当前已经上传和最大上传,设置选择器的显隐
*/
var setPickerVisible = function () {
isMax() ? $picker.hide() : $picker.show()
}
/**
* 生成上传后新元素的的 html
* @param val 上传后文件的地址
* @param callback html 生成后的回调
*/
var renderItemHtml = function (val, callback) {
var src = isFullUrl(val) ? val : domain + val
laytpl(itemTpl).render({
val: options.fullUrl ? src : val,
src: src,
isImage: isImage(val),
inputName: options.inputName,
readOnly: options.readOnly,
}, function (html) {
var $item = $(html)
// 复制
$item.find('.up-copy').click(function () {
copyText(src)
layer.msg('复制成功', { icon: 1 })
})
// 替换
if (!options.readOnly) {
renderReplaceUploader($item)
}
callback && callback($item)
})
}
/**
* 添加新的已上传元素
* @param {string} val
*/
var appendItem = function (val) {
renderItemHtml(val, function ($item) {
$itemsWrapper.append($item)
setPickerVisible()
})
}
/**
* 替换图片的上传
* @param $item
*/
var renderReplaceUploader = function ($item) {
var replaceOptions = $.extend({}, options, {
elem: $item.find('.up-replace'),
multiple: false,
number: 1,
done: function (res) {
layer.closeAll('loading')
if (res.code !== 0) {
layer.msg(res.msg, { icon: 2 })
return
}
renderItemHtml(res.data.path, function ($newItem) {
$item.replaceWith($newItem)
})
},
error: function () {
layer.closeAll('loading')
},
})
upload.render(replaceOptions)
}
$wrapper.html('<div class="up-items-wrapper"></div>')
if (!options.readOnly) {
$wrapper.append('<div class="up-picker">点击上传</div>')
}
var $picker = $wrapper.find('.up-picker')
var $itemsWrapper = $wrapper.find('.up-items-wrapper')
// 固定配置
options = $.extend(options, {
elem: $picker,
url: uploadUrl,
auto: true,
method: 'post',
multiple: (options.max > 1) || (options.max == 0),
number: options.max,
before: function () {
layer.load(2)
},
done: function (res) {
layer.closeAll('loading')
if (res.code !== 0) {
layer.msg(res.msg, { icon: 2 })
return
}
// layui 的自动上传,好像不能提前终止
// 所以,如果上传数量超过设定的值,只能在这里丢弃返回的结果
if (isMax()) {
return
}
appendItem(res.data.path)
},
error: function () {
layer.closeAll('loading')
},
})
// 初始化默认值的情况
var value = options.value
if (value) {
value = value.split(',')
for (var i = 0; i < value.length; i++) {
if (isMax()) {
break
}
appendItem(value[i])
}
}
// 只读的情况下,不需要渲染上传器
if (!options.readOnly) {
uploaderIns = upload.render(options)
}
$wrapper.on('click', '.up-remove', function () {
$(this).parents('.up-item').remove()
setPickerVisible()
})
}
// 初始化页面上的上传器,使用 .up-uploader 选择器
$('.up-uploader').each(function () {
renderUploader($(this))
})
// 图片弹框预览
$(document).on('click', '.up-preview', function () {
var img = $(this).parents('.up-item').find('.up-image')[0]
var src = img.src
if (!img) {
layer.msg('没有可显示的图片', { icon: 2 })
return
}
var width = img.naturalWidth
var height = img.naturalHeight
if (!width || !height) {
layer.msg('图片尺寸错误', { icon: 2 })
return
}
var hwRatio = height / width
var maxHeight = window.innerHeight * 0.9
var maxWidth = window.innerWidth * 0.9
if (width > maxWidth) {
width = maxWidth
height = width * hwRatio
}
if (height > maxHeight) {
height = maxHeight
width = height / hwRatio
}
layer.open({
type: 1,
title: false,
area: [width + 'px', height + 'px'],
shadeClose: true,
content:
'<a href="' + src + '" target="_blank">' +
' <img src="' + src + '" style="height: 100%; width: 100%;">' +
'</a>',
})
return false
})
exports('up-uploader', {
// 导出该函数,可在其他地方,手动渲染动态加入的 html 元素
// 如何导入,可查看 layui 的自定义模块文档
renderUploader: renderUploader,
})
})
css
upload.css
/* 听说这是最强清除浮动的搞法? */
.up-uploader::after {
content: '';
display: block;
clear: both;
}
.up-picker {
float: left;
border: 1px solid #cfdadd;
width: 120px;
height: 120px;
font-size: 20px;
color: #8e999c;
text-align: center;
line-height: 120px;
cursor: pointer;
}
.up-picker:hover {
border-color: #23b7e5;
}
.up-items-wrapper {
float: left;
}
.up-item {
position: relative;
line-height: 116px;
float: left;
border: 1px solid #cfdadd;
width: 120px;
height: 120px;
text-align: center;
margin-right: 5px;
}
.up-item:hover .up-actions {
display: initial;
}
.up-image {
max-width: 100%;
max-height: 100%;
}
.up-file {
font-size: 20px;
color: #7266ba;
line-height: 120px;
}
.up-actions {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(204, 204, 204, .9);
line-height: 120px;
}
.up-actions .up-action {
font-size: 12px;
font-weight: bolder;
cursor: pointer;
color: #6254b2;
}
.up-actions .up-remove {
color: #ee3939;
}
感谢分享,在用layui,先收藏了