layui文件上传(头像上传)

头像上传

头像上传大概流程就是选择电脑上的文件图片然后上传到服务器服务器存起来然后上传到浏览器中,服务器需要用到磁盘存储模块(multer),需要下载安装

multer是Nodejs中用于处理文件上传 multipart/form-data数据的中间件,用于处理任何表单提交数据(包含非multipart/form-data类型的表单);

multer 在request对象中加入了body和file或files属性,body属性包含了form中的文本内容,file或files包含了form 中的附件数据

后端代码设置:

1,multer:文件上传中间件

1.1引入multer模块

var multer = require("multer")

1.2对将要上传的文件配置文件存储位置和文件名

引入multer模块之后对上传文件进行配置,multer.diskStorage({destination:function(req,file,callback){callback(错误信息,存放目录)}})主要设置存储位置和文件名

var myStorage = multer.diskStorage({
  // 设置文件存储位置
  destination: function(req, file, callback){
    // 通过调用callback设置文件存储目录, 参数1是错误信息, 参数2是目录
    callback(null,"./public/HeadImg")
  },
  // 设置文件名
  filename: function(req, file, callback){
    // file.originalname 指文件的原始名
    // callback(null, file.originalname)
    // 把用户头像名设置为用户名, 保证每个用户头像唯一不重复
    // console.log(1, req.body) // 在磁盘存储时,body-parser模块尚未解析出body数据,所以这里body为空
    // callback(null, req.body.username + ".jpg")  // 结论: 这种方案不可行
    
    // cookie会随ajax请求,被携带在请求头中, 但请求头不支持汉字,会乱码, 所以在本地cookie中存数据时, 汉字要进行url编码, 
    // 使用cookie-parser模块可以直接解析请求头中的cookie字符串, 自动解码并生成对象存入req.cookies字段中
    console.log(1, req.headers.cookie, req.cookies)
    callback(null, req.cookies.username + ".jpg")
  }
  // 以上两个函数都有三个参数:
  // req: 请求对象, 对应接口回调中的req参数
  // file: 上传的文件信息
  // callback: 设置信息的回调, 通过向callback传参设置文件名和位置
})
  • destination:主要设置文件存储位置,是一个函数,函数有三个参数。req:请求对象,对应接口回调中的req参数;file:上传的文件信息;callback:设置信息的回调,通过向callback传参设置文件名和位置。destination中的callback传参的是文件存储位置

  • filename:主要设置文件名,也是一个函数,也有三个参数。req和file通过destination作用一样,但是callback传参的第二个参数是文件名。callback参数1是错误信息,参数2是文件名或者位置。

  • file.originalname:指文件的原始名,文件原始名不能包含一些特殊字符

  • callback参数1为空说明没有错误,所以置为null

  • req对应接口中的req

1.3 创建硬盘存储对象

var save = multer({
  storage: myStorage
})
  • 这的myStorage指的就是文件配置

2,头像上传接口

接口用post方式才可以,不过post请求方式第二个参数就是创建的硬盘存储对象,打点调用single()单文件上传或者array()多文件上传设置文件上传方式。头像上传接口的回调执行时,文件就已经存储到磁盘了,直接相应即可。

app.post("/uploadHead", save.single("headImg"), function(req, res) {
    console.log(2, req.body)
        // 文件上传的回调执行时, 文件就已经存储到磁盘了, 直接响应即可
    res.json({ code: 1, msg: "头像已上传" })
})

前端代码设置:

独自创建一个html命名为HeadImg.html。

1.文件上传的三种方式:

1.1 form表单上传,简单方便

设置form标签的action属性值为后端接口的url路径地址,method的属性值为post方式。form表单包括一个输入框和一个按钮,输入框的类型为file类型。输入框只能选择一个文件。form表单文件上传时,需要通过enctype属性来设置文件上传的类型。上传文件类型设置input的accept属性值,属性值为image/*,表示上传所有格式的图片

 <!-- enctype设置表单提交的数据类型,  multipart/form-data指文件类型-->
    <form action="/uploadHead" method="POST" enctype="multipart/form-data" class="layui-form">
        <!-- accept="image/*" 指规定文件只能选择图片类型的文件 -->
        <input type="file" name="headImg" accept="image/*" >
        <button>上传头像</button>
    </form>

form表单上传文件,输入框必须设置name值,因为发送给服务器的是name属性值+传递的数据,name的属性值对应接口的save.single()的参数。不对应的话文件存不进去

form表单文件上传后端代码:

var multer = require("multer")
    // 对上传文件进行配置
var myStorage = multer.diskStorage({
    // 配置文件存储位置
    destination: function(req, file, callback) {
        callback(null, "./public/HeadImg")
    },
    // 配置文件名
    filename: function(req, file, callback) {
        callback(null, file.originalname)
    }
})
var save = multer({
    storage: myStorage
})
​
app.post("/uploadHead", save.single("headimg"), function(req, res) {
    res.json({ msg: "长传成功", code: 1 })
})

现在实现的不过是上传头像,并没有实现根据用户名上传头像并更改用户的头像。

1.2 ajax文件上传,异步上传,局部刷新

表单中只有一个button可以不加lay-filter属性。

使用ajax请求上传文件,首先要通过input标签的files属性获取上传文件信息,然后把获取到的文件信息添加到formData对象中。因为ajax上传的文件其实就是一个formData对象。formData对象是一个内置对象,用自身的append方法去添加到该对象中。append(name,file)有两个参数,参数1对应input框的name值和后端存储的name值对应,第二个参数就是获取到的文件信息。

 form.on("submit", function(){
         console.log($("input")[0].files)
          // 找到input选中的头像文件
          var file = $("input")[0].files[0]
          // 把需要上传的文件加入formData对象中(因为ajax上传的是formData对象)
           var formData = new FormData()
          // 注意: 第一个参数是input的name值,和后端存储参数对应
          formData.append("headImg", file);
          // formData.append("username", sessionStorage.getItem("name"))
          // 发起ajax请求, 上传头像
           $.ajax({
                    type: "post",
                    url: "/uploadHead",
                    data: formData,
                    // contentType指上传数据类型, jQuey封装ajax时会自动把data对象转成字符串类型, false表示禁止自动转换类型, 因为文件不能转类型
                    contentType: false,
                    // processData指jQuery内部对data数据的加工处理(编码),false可防止文件被加工处理, 保持原有结构 
                    processData: false,
                    success: function(){
                        layer.msg("头像已上传",{icon: 1})
                        // location.reload(); // 刷新当前页无效
                        // console.log($("#headImg")[0]) // 找头像标签无效
​
                        // window.parent.location.reload()  // 刷新外层主页
​
     // 更新外层主页顶部导航中的头像显示 无效
  // window.parent.document.getElementById("headImg").src = "./HeadImg/张三.jpg"
 // 这一句无效的原因: img标签设置src地址时,如果src值不变的情况下, img会直接调用缓存, 不会更新 (浏览器自动缓存造成的结果)
 // 解决方案: 我们在src图片路径后使用?拼接随机数,使设置前后的src不一致, img就会重载图片 (?后的数据叫hash值,不影响路径使用)
window.parent.document.getElementById("headImg").src = "./HeadImg/"+ sessionStorage.getItem("name") +".jpg?" + Math.random()
                    }
                })
                return false;
            })
  • ajax请求中上传文件类型,必须设置上传文件类型和

  • contentType:设置上传文件类型,false指禁止转换类型,服务器只接受字符串数据,文件不能转类型

  • processData:false :指jquery内部对data数据加工处理(编码),false防止文件被加工处理,保持原有结构

1.2.1 上传头像之后,用户名头像更改

1.3 layui文件上传,需要很多配置项,前后端要对应,比较麻烦,不建议

2,点击上传头像跳转到HeadImg.html页面

2.1在上传头像的a标签中添加三个属性:class、data-url、data-title

需要把之前layui后台系统页上传头像添加三个属性值,分别是 class="navTab"、data-url="HeadImg.html"、data-title="上传头像"。

  • 添加class值是为了tab点击事件创建一个新的tab选项卡,新的选项卡内容是iframe跳转页面的标签,目的就是跳转到HeadImg.html上传头像页面。

  • 添加data-url属性值是为了增加新的选项卡内容设置iframe的src属性,src属性值必须为HeadImg.html,跳转到上传头像页面。

  • 添加data-title属性就是设置新增的tab选项卡的title

<!-- 上传头像的html应该改为: -->
<dd><a href="javascript:;" class="navTab" data-url="HeadImg.html" data-title="上传头像">上传头像</a></dd>

2.2点击上传头像tab选项卡,必须取消左侧列表的选中

$(".navTab").click(function(e) {
    if (e.target.dataset.url == "HeadImg") {
         $("dd").removeClass("layui-this")
     }
}

2.2.1 切换选项卡,更新左侧导航标题标记

需要给左侧导航标题都加上class="navTab",方便查找还原,给点击过的tab选项卡还原。

设置tab选项卡element模块的点击事件,点击tab卡的a标签的时候向点击的标签添加layui-this属性,但是会发现点击多个之后会选中多个,所以需要在添加layui-this属性之前先取消所有dd标签的layui-this属性才能做到还原。

    element.on("tab(yu_tab)", function(data) {
        // 如果点的是tab标题li标签,就执行切换
       if (data.elem.context.nodeName == "LI") {
          var id = data.elem.context.getAttribute("lay-id"); //找到点击这一项的id值,id值就是设置的该标签的data-title属性值
            $("dd").removeClass("layui-this") //取消左侧导航所有标记
            $(`[data-title=${id}]`).parent().addClass("layui-this") //添加这一项标记
         $(".layui-tab-content .layui-show iframe")[0].contentWindow.location.reload();         //刷新这一页的iframe
       }
     })
  • 模板字符串[]指的是属性值的设置

2.2.2 如何刷新这一网页的iframe

先找到iframe标签然后通过它的contentWiondw方法刷新网页。

 $(".layui-tab-content .layui-show iframe")[0].contentWindow.location.reload(); //刷新这一页的iframe

3,设置上传图片的名字为用户名

上传用户名头像并更新用户名头像,必须设置图片的文件名为formData对象中存在的username字段里边存的是会话存储的用户名信息。

3.1 把会话存储中存储的用户名添加到foramData对象中

formData.append("username", sessionStorage.getItem("username"))

3.2使用req.boy 修改接口中设置的文件名为会话存储的用户名(不可行)

因为用ajax请求,请求数据data是formData对象中的数据,把会话存储的用户名添加到formData对象中,向服务器发送请求,后台接口接受的请求req中含有会话存储的用户名。而接口中的req和设置文件信息对象filename的函数参数req相同,所以直接在filename中通过回调函数的第二个参数设置文件名为req.username

  formData.append("username", sessionStorage.getItem("name"))
  filename: function(req, file, callback) {
        // callback(null, file.originalname)
        callback(null, req.body.username + ".jpg")
    }

通过req.body.username设置文件名不行,因为是异步执行的,在磁盘存储时,body-parser模块尚未解析出body数据,所以这里body为空。所以需要用到cookie存储用户名

3.3 使用cookie存储用户名修改接口中设置的文件名

在登陆页面登陆成功之后把用户名存到会话存储中,不会随着ajax请求发给服务器,所以把用户名存入本地cookie中

document.cookie = "username=" + formdata.field.username

cookie在请求头发送时不支持中文,所以需要url编码才行

document.cookie = "username=" + encodeURI(formdata.field.username)

在后端服务器中需要用到cookie-parser解析器,解析cookie中的数据才可以。使用cookie-parser模块可以直接解析请求头中的cookie字符串,自动解码并生成对象存入req.cookies字段中

var cookieParser = require("cookie-parser")
app.use(cookieParser())

然后利用cookie中的用户名设置文件名

callback(null, req.cookies.username + ".jpg")

4,刷新页面才能把上传的用户名头像才能更新

已经上传图片,并把图片重命名为用户名。而用户名头像是根据图片的用户名来查找并显示的,所以只需要在上传头像成功的同时并刷新页面就可以显示自己上传后的头像。

设置外层主页顶部导航中的头像显示:

window.parent.document.getElementById("headImg").src = `./HeadImg/${sessionStorage.getItem("name")}.jpg`;
  • window.parent.location.reload() :刷新外层主页,效果不太好

  • window:当前页HeadImg.html

  • window.parent:外层主页 index.html

  • window.parent.document.getElementById("headImg").src = "./HeadImg/" + sessionStorage.getItem("name") + ".jpg";这一句无效

这一句无效的原因:img标签设置src地址时,如果src值不变的情况下,img会直接调用缓存,不会更新(浏览器自动缓存造成的结果)。解决方案:我们在src图片路径后使用问号拼接一个随机数,使设置前后的src不一致,img就会重载图片(?后的数据叫哈希值,不影响路径使用)。

 window.parent.document.getElementById("headImg").src = `./HeadImg/${sessionStorage.getItem("name")}.jpg?` + Math.random();
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值