resources :student_photos do
member do
# 上传图片
post :uploadFile
end
end
<div class="col-sm-3" style="margin-top: 20px;">
<div class="img_border">
<div class="img_plus">+</div>
<div class="img_bt">点击上传</div>
<canvas id="canvas" style="position:absolute;" class="form-group">
</canvas>
<%= file_field 'student','image',class: "upload", id: "file_btn" %>
css 图片框的样式
.img_border{
position:relative;
height: 200px;
width:172px;
border-radius: 10px;
border:1px dashed rgba(197,208,219,1);
}
.img_plus{
position:absolute;
top:0;
bottom: 0;
margin: auto 0;
width: 100%;
text-align: center;
font-size:50px;
font-family:Microsoft YaHei;
font-weight:400;
color:rgba(197,208,219,1);
display: flex;
align-items: center;
justify-content: center;
}
.img_bt{
position:absolute ;
bottom:0;
font-size:16px;
font-family:Microsoft YaHei;
font-weight:300;
color:rgba(255,255,255,1);
background:rgba(153,153,153,1);
height:24px;
text-align: center;
line-height:30px;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
width: 170px;
height: 30px;
}
.upload{
height: 200px;
width: 170px;
font-size: 100px;
/* 设置透明度 */
opacity: 0;
filter:alpha(opacity=0);
cursor:pointer;
}
script 部分代码
<script type="text/javascript">
let file_btn = document.getElementById('file_btn');
let canvas = document.getElementById('canvas');
// 给定canvas在页面的占位,图片大于则宽高等比例缩小
canvas.width = 170;
canvas.height = 200;
// 1.监听文件上传按钮的选择文件的事件
file_btn.addEventListener("change", function () {
let data_url = file_btn.files[0];
console.log(data_url);
// 2.使用FileReader类来读取文件内容
let reader = new FileReader();
reader.readAsDataURL(data_url);
// 3.监听FileReader读取器读取完成事件(此事件后才可以获取到文件内容,进行图片渲染或上传)
reader.onload = function () {
// 3.1 异步渲染(canvas)
let cxt = canvas.getContext('2d');
let img = new Image();
img.src = this.result;
// 3.11 Image对象数据准备完成事件
img.onload = function () {
cxt.clearRect(0, 0, canvas.width, canvas.height);// 清空上一次的图片
// 绘画
let width = img.width;
let height = img.height;
let result = geometric_scaling(width, height, canvas.width, canvas.height);
if (result['scale_by'] === 'none') {
cxt.drawImage(img, (canvas.width - result['width']) / 2, (canvas.height - result['height']) / 2, result['width'], result['height'])
}
if (result['scale_by'] === 'width') {
cxt.drawImage(img, 0, (canvas.height - result['height']) / 2, result['width'], result['height'])
}
if (result['scale_by'] === 'height') {
cxt.drawImage(img, (canvas.width - result['width']) / 2, 0, result['width'], result['height'])
}
}
// 3.2.异步上传(ajax) param = {"img":this.result}(数据格式为base64)
}
});
// 封装等比缩小的方法
function geometric_scaling(image_width, image_height, canvas_width, canvas_height) {
let width = image_width;
let height = image_height;
let scale = 1;
let scale_by = 'none';
let return_data = {width, height, scale, scale_by};
if (image_height < canvas_height && image_width < canvas_width) {
return return_data
} else if (image_height > canvas_height && image_width > canvas_width) {
// 都大
let scale_height = canvas_height / image_height;
let scale_width = canvas_width / image_width;
if (scale_height < scale_width) {
scale = scale_height;
scale_by = 'height';
} else {
scale = scale_width;
scale_by = 'width';
}
}
// 不是都小也不是都大的剩下两种情况
else if (image_height > canvas_height) {
scale = canvas_height / image_height;
scale_by = 'height';
} else {
scale = canvas_width / image_width;
scale_by = 'width';
}
return_data['width'] = image_width * scale;
return_data['height'] = image_height * scale;
return_data['scale'] = scale;
return_data['scale_by'] = scale_by;
return return_data
}
</script>
class StudentPhotosController < ApplicationController
# 上传图片
def uploadFile(file, id)
if !file.original_filename.empty?
# 生成一个文件名 随机+时间+格式
# 路径:upload/student/ + 学生id + 文件名
# mime = file.content_type
# ext 为上传文件类型后缀
ext = file.original_filename.split(".")[-1] # .pop()
@filename = getFileName(id, file.original_filename, ext)
# 判断文件是否存在,不存在则创建一个以学号命名的文件夹
afile = "#{Rails.root}/public/upload/student/#{id}"
FileUtils.mkdir_p(afile) unless File.exists?(afile)
# 向目录写入文件
File.open(Rails.root.join(afile, @filename), "wb") do |f|
f.write(file.read)
end
# 返回文件名称,保存到数据库中
return @filename
end
end
def getFileName(id, filename,ext)
if !filename.nil?
# 防止新文件名重复
# 生成安全的base64字符串
key = SecureRandom.urlsafe_base64
# 'upload/student/'+ id.to_s + '/' +
name = key.to_s + 't' + Time.now.strftime("%y%m%d%I%M%S") + '.' + ext.to_s
filename.sub(/.*./, name)
end
end
def new
@student_photo = ::Student.new
end
def create
@student_photo = ::Student.new(student_photo_params)
if !params[:student]['image'].blank?
uploadFile(params[:student]['image'],@student_photo.student_code)
end
if @student_photo.save
flash[:notice] = "学生图片保存成功"
redirect_to admin_student_student_photos_path
else
flash[:error] = @student_photo.errors.full_messages.uniq.join(', ')
redirect_to new_admin_student_student_photo_path
end
end
def update
end
private
def find_student_id
@student_photo = ::Student.find(params[:id])
end
def student_photo_params
params.require(:student).permit(:student_code)
end
end
实现效果如下图片框:
resources :student_photos do
member do
# 上传图片
post :uploadFile
end
collection do
# 删除单张图片
post :delete_simple_student_photo
# 获取学生人脸图片
get :all_student_photo
end
end
<div class="pic" style="border: none;">
<div class="img_border">
<div class="img_plus">+</div>
<canvas id="canvas" style="position:absolute;" class="form-group"></canvas>
<%= file_field 'student', 'image', class: "upload", id: "file_btn" %>
script 部分代码
<script type="text/javascript">
// 获取该学生所有照片的路径,并循环插入到相册中
$.ajax({
type: "GET",
url: "/student_photos/all_student_photo?id=<%= @student_photo.student_code %>",
dataType: "json",
// 请求成功
success: function (result) {
// 取出图片地址的数组
let pic_file = result.pic_file;
for (i = 0; i < pic_file.length; i++) {
$("#pic_div").append(" + i + "\" class=\"pic\" src=\"" + pic_file[i] + "\">" +
" + pic_file[i] + "\")'>X");
<% else %>
$("#pic_div").append(" + i + "\" class=\"pic\" src=\"" + pic_file[i] + "\">" +
"");
<% end %>
console.log(pic_file[i])
}
},
// 请求失败,包含具体的错误信息
error: function (e) {
console.log(e.status);
console.log(e.responseText);
alert("照片墙加载失败,请与管理员联系");
}
});
function delImg(msg){
var m = confirm("确定删除该照片?")
if(m == true){
$.ajax({
type: "POST",
url: "/student_photos/delete_simple_student_photo",
data: {msg: msg},
dataType: "json",
// 请求成功
success: function (result) {
let del = result.pic
alert(del)
history.go(0)
},
// 请求失败,包含具体的错误信息
error: function (e) {
console.log(e.status);
console.log(e.responseText);
alert("删除图片失败,请与管理员联系");
}
});
}else{
alert("删除图片失败,请与管理员联系")
}
}
let file_btn = document.getElementById('file_btn');
let canvas = document.getElementById('canvas');
// let pic = document.getElementById('pic');
// 给定canvas在页面的占位,图片大于则宽高等比例缩小
canvas.width = 170;
canvas.height = 200;
file_btn.addEventListener("change", function () {
let data_url = file_btn.files[0];
console.log(data_url);
// 2.使用FileReader类来读取文件内容
let reader = new FileReader();
reader.readAsDataURL(data_url);
// 3.监听FileReader读取器读取完成事件(此事件后才可以获取到文件内容,进行图片渲染或上传)
reader.onload = function () {
// 3.1 异步渲染(canvas)
let cxt = canvas.getContext('2d');
let img = new Image();
img.src = this.result;
// 3.11 Image对象数据准备完成事件
img.onload = function () {
cxt.clearRect(0, 0, canvas.width, canvas.height);// 清空上一次的图片
// 绘画
let width = img.width;
let height = img.height;
let result = geometric_scaling(width, height, canvas.width, canvas.height);
if (result['scale_by'] === 'none') {
cxt.drawImage(img, (canvas.width - result['width']) / 2, (canvas.height - result['height']) / 2, result['width'], result['height'])
}
if (result['scale_by'] === 'width') {
cxt.drawImage(img, 0, (canvas.height - result['height']) / 2, result['width'], result['height'])
}
if (result['scale_by'] === 'height') {
cxt.drawImage(img, (canvas.width - result['width']) / 2, 0, result['width'], result['height'])
}
}
// 3.2.异步上传(ajax) param = {"img":this.result}(数据格式为base64)
}
});
// 封装等比缩小的方法
function geometric_scaling(image_width, image_height, canvas_width, canvas_height) {
let width = image_width;
let height = image_height;
let scale = 1;
let scale_by = 'none';
let return_data = {width, height, scale, scale_by};
if (image_height < canvas_height && image_width < canvas_width) {
return return_data
} else if (image_height > canvas_height && image_width > canvas_width) {
// 都大
let scale_height = canvas_height / image_height;
let scale_width = canvas_width / image_width;
if (scale_height < scale_width) {
scale = scale_height;
scale_by = 'height';
} else {
scale = scale_width;
scale_by = 'width';
}
}
// 不是都小也不是都大的剩下两种情况
else if (image_height > canvas_height) {
scale = canvas_height / image_height;
scale_by = 'height';
} else {
scale = canvas_width / image_width;
scale_by = 'width';
}
return_data['width'] = image_width * scale;
return_data['height'] = image_height * scale;
return_data['scale'] = scale;
return_data['scale_by'] = scale_by;
return return_data
}
</script>
css 图片显示和删除按钮样式
.pic_list{
width: 100%;
height: 100%;
padding-bottom: 0%;
position: relative;
overflow: hidden;
}
.delImg {
width: 28px;
height: 28px;
border-radius: 50%;
background: gray;
color: white;
position: absolute;
right: 12px;
top: 12px;
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
opacity: .9 ;
cursor: pointer;
}
.delImg:hover{
background: red;
color: white;
opacity: .9;
}
class StudentPhotosController < ApplicationController
# 显示学生全部图片
def all_student_photo
file_path = "/upload/student/#{params[:id]}"
pic_file = []
if File.directory?("#{Rails.root}/public#{file_path}")
Dir.foreach("#{Rails.root}/public#{file_path}") do |filename|
# ruby遍历目录下所有文件时会包含“.”和“..”,这两者都属于目录,需要进行排除
unless File.directory?(filename)
pic_file << "#{file_path}" + '/' + filename
end
end
end
render json: {pic_file: pic_file}
end
#删除单张图片
def delete_simple_student_photo
msg = params[:msg]
File.delete("#{Rails.root}/public/#{msg}")
pic = "该图片删除成功"
render json: {pic: pic}
end
# 上传图片
def uploadFile(file, id)
if !file.original_filename.empty?
# 生成一个文件名 随机+时间+格式
# 路径:upload/student/ + 学生id + 文件名
# mime = file.content_type
# ext 为上传文件类型后缀
ext = file.original_filename.split(".")[-1] # .pop()
@filename = getFileName(id, file.original_filename, ext)
# 判断文件是否存在,不存在则创建一个以学号命名的文件夹
afile = "#{Rails.root}/public/upload/student/#{id}"
FileUtils.mkdir_p(afile) unless File.exists?(afile)
# 向目录写入文件
File.open(Rails.root.join(afile, @filename), "wb") do |f|
f.write(file.read)
end
# 返回文件名称,保存到数据库中
return @filename
end
end
def getFileName(id, filename,ext)
if !filename.nil?
# 防止新文件名重复
# 生成安全的base64字符串
key = SecureRandom.urlsafe_base64
# 'upload/student/'+ id.to_s + '/' +
name = key.to_s + 't' + Time.now.strftime("%y%m%d%I%M%S") + '.' + ext.to_s
filename.sub(/.*./, name)
end
end
def new
@student_photo = ::Student.new
end
def create
@student_photo = ::Student.new(student_photo_params)
if !params[:student]['image'].blank?
uploadFile(params[:student]['image'],@student_photo.student_code)
end
if @student_photo.save
flash[:notice] = "学生图片保存成功"
redirect_to admin_student_student_photos_path
else
flash[:error] = @student_photo.errors.full_messages.uniq.join(', ')
redirect_to new_admin_student_student_photo_path
end
end
def update
@student_photo = ::Student.find(params[:id])
if !params[:student]['image'].blank?
file_name = uploadFile(params[:student]['image'],@student_photo.student_code)
end
if @student_photo.update(student_photo_params)
flash[:notice] = "学生图片修改成功"
redirect_to edit_admin_student_student_photo_path(@student_photo)
else
flash[:error] = @student_photo.errors.full_messages.uniq.join(', ')
redirect_to edit_admin_student_student_photo_path(@student_photo)
end
end
private
def find_student_id
@student_photo = ::Student.find(params[:id])
end
def student_photo_params
params.require(:student).permit(:student_code)
end
end
实现效果:
这里主要介绍图片功能的实现,其他不重要的就跳过了。