我在使用echarts时没有使用按需引入的方式,而是全部引入并且挂载到了Vue全局组件中,在main.js中
// 引入Echarts import ECharts from 'vue-echarts' import "echarts"; Vue.component("v-chart", ECharts); 然后直接在页面上使用
<div class="echartsLeft-list"> <div class="chart1-title">14 日销售折线图(单位:件)</div> <v-chart class="chart1" :option="option1" ref="chart1" /> </div> 我们在使用echarts的时候往往要考虑适配问题,在阅读echarts的官方文档时,可以看到,有一个方法叫做resize
那我们如何去使用这个方法呢
首先在methods中定义一个方法,通过ref获取页面上的echarts实例,直接调用方法
getresize(){ this.$refs.chart1.resize() }, 那么什么时候去调用呢,就是当窗口大小发生改变时,在mounted生命周期添加监听页面窗口大小的方法
mounted() { window.addEventListener("resize",this.getresize); }, 这样就可以实现适配了,但是有一个问题会出现,那就是你跳转到其他页面时,监听事件并没有被销毁,但echarts实例已经被销毁了,导致找不到resize的报错,所以这个时候就需在beforeDestroy生命周期清楚监听事件
beforeDestroy() { // 页面销毁时销毁监听事件 window.removeEventListener('resize',this.getresize) }, 整体代码:
<template> <div class="echartsLeft-list"> <div class="chart1-title">14 日销售折线图(单位:件)</div> <v-chart class="chart1" :option="option1" ref="chart1" /> </div> </template> <script> export default { data() { return { // echarts图表折线图 option1: { xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, yAxis: { type: 'value', axisLine: { lineStyle: { type: 'dashed' } } }, series: [ { data: [150, 230, 224, 218, 135, 147, 260], type: 'line' } ] }, } }, mounted() { window.
UE5 Shader基础学习笔记——13-20 DetailNormal/Smoothstep/Length/CeilFloorRound/DDXDDY/SinCos/Power Lec13 Detail Normal MappingLec14 Advanced Detail Mapping (etc.灰度mask)Lec15 Smoothstep (etc.溶解/高度混合)Lec16 Length & Distance (etc.摇摆/内部假光)Lec17 Ceil Floor Round (etc.色阶)Lec18 DDX DDY (etc.面片法线,纹理mip计算)Lec19 Sin Cos (etc.涟漪)Lec20 Power 本系列学习资料来源,Ben Cloward的油管空间,本笔记主要对其中UE的部分进行记录
Lec13 Detail Normal Mapping 使用Quixel的一个岩石资产(PkeeM)作为演示,拉太近之后纹理会比较模糊
可以使用Detail Normal增加细节,所谓Detail Normal就是再拿一张法线纹理,平铺很多次,进行法线混合覆盖在上面
Ben在视频中使用的DetailNormal如下,RG是法线,B是粗糙度,A是用于颜色Overlay的mask
由于有很多信息,所以在导入UE时使用BC7格式压缩,并且取消SRGB
使用如下
此时放大近看可以看到细节
不过这样是一直在计算DetailNormal,实际使用时为了让其不一直计算,可以在较低的Lod中舍弃这个,或者创建一个基于距离的mask,靠近时再计算
Lec14 Advanced Detail Mapping (etc.灰度mask) 在这节使用一张纹理mask将多个Detail进行映射
整个实现如下图,也就是RGBA四个通道各画一个Mask分别用不同的图
这样是消耗比较高的,于是可以用UE的TextureArray来改善,创建TextureArray后插入要用的图
采样TextureArray需要UVW三个参数,UV正常采样,W用于选择贴图
为了分出用什么贴图,可以在mask上使用不同灰度值,这样实现更加节省性能,W用灰度值映射
从评论中节选出一些问题
TextureArray会只加载一个mip,无法利用Streaming的优势,但对于detail来说没问题,毕竟detail只在特写中需要。Ben关于这个的建议是使用低分辨率的TextureArray,然后应用所有角色,一直在内存中也没事。
关于如何在mask中单独设置每个纹理的UV平铺,如果使用了if节点来设置就没有意义了。
Ben的回复是之前在开发圣歌的时候尝试做过但是这种尝试并不干净,他决定使用一个全局的统一的分辨率控制缩放。Ben提议可以将纹理缩放倍数也编码为灰度颜色读取,但是会在边界上产生一些奇怪的结果,在涉及纹理压缩和低mipmap时尤为明显。
在圣歌的开发中,Ben让艺术家在一个mask上使用16种材质,texture array设置有16份贴图,分辨率为64*64
如果想要使用mask之间过渡,可以采用最开始分通道存储mask的方式
也有人提出问题,UE更适合多种材质插槽,使用多种简单的材质更好。Ben觉得使用一个材质可以减少DrawCall。
这种用灰度分mask的方法在其他游戏中也会用到,比如原神中根据不同灰度选择不同Ramp
Lec15 Smoothstep (etc.溶解/高度混合) 关于Smoothstep,可以看看
常用函数SmoothStep的实现原理
Shader实验室: smoothstep函数
1:在电脑左下角搜索框输入cmd,打开小黑框
2:输入神秘代码:git config --list(这里可以看到用户名和用户邮箱)useremail和username
ps:git如果没有初始化,可以直接设置用户名和邮箱:
git config --global user.name “输入你的用户名”
git config --global user.email “输入你的邮箱”
3:如果有则通过神秘代码进行替换:
git config --global --replace-all user.email “输入你的邮箱”
git config --global --replace-all user.name “输入你的用户名”
最后通过 git config --list 查看是否替换成功
介绍 这个是为我自己写得,因为我觉得如果需要获取网页上的某个颜色总是需要打开“开发者中心”的话太麻烦了;简单易用、易懂,仅使用JavaScript语言编写。
它长这样: 使用 仅调用:一行代码即可搞定
ColorPicker("#000000"); 调用后执行其他程序
ColorPicker("#000000").then(function(){}); 取得颜色rgb值
ColorPicker("#008CD6").then(function(ColorData){console.log(ColorData)}); 随时直接设置、更改颜色:一行代码即可搞定
ColorPicker.setColor("#000000"); 以上代码均与它无关 关键代码
if ('EyeDropper' in window) { // 判断是否支持这个api let eyeDropper = new EyeDropper(); // 创建对象 ColorPicker.prototype.Ele.getColor.addEventListener('click', async () => { try { const ColorResult = await eyeDropper.open();// 取得吸取结果 ColorPicker.setColor(ColorResult.sRGBHex);// 取得颜色并设置颜色 } catch (e) { console.warn('你取消了取色操作') } }); } 源码在这里 目录结构:
popup.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ColorTool拾色器</title> <link rel="stylesheet" href="./icomoon/style.css"> <link rel="stylesheet" href="./css/index.css"> <script src="./javascript/ColorTool.js"></script> </head> <body> <div class="
随时更新
随时更新
问题背景 AOSP工程代码拿过来时是压缩包,因此需要解压代码,创建git仓库进行上传。但实际上传的文件个别有些遗落,导致上传的代码拉取下来后无法编译通过。
问题分析 git add .进行添加所有文件时,会忽略.gitignore里面列明的文件,要是必要的文件也被添加到文件中,git add时就没能add上对应文件。
问题解决 处理步骤如下:
1. 将原始解压后的文件覆盖掉git仓库中的文件;
2. 找到所有.gitignore文件;
find ./ -name "*.gitignore"
3. 删除所有.gitignore文件
find ./ -name "*.gitignore" | xargs rm
4. 查看遗漏的文件有哪些
git status
5. 判别哪些文件是需要的,哪些不需要。
1)都需要。则是最简单的,git add . 添加删除掉gitignore及所需要的文件即可;
2)个别需要。则恢复对应的.gitignore文件,然后把需要的文件或目录,将其从.gitignore中删除或注释掉(#注释)
恢复删除的.gitignore文件:git reset HEAD .gitignore
6. 个别没在.gitignore目录中,但却还是被遗漏的(也有可能被*.xxx匹配忽略了),可以使用!进行强制包含,不做忽略;
如:!QcomPkg/SDM670Pkg/Library/PdcTargetLib/log/
注意:这种情况下需要使用对比工具对当前git仓库文件与原始解压文件进行对比,将缺少的文件复制过去。复制过去之后git status会找不到拷贝的文件,需要先往
.gitignore中添加“忽略该文件路径”(即!文件路径)进行忽略。
7. 去掉已commit到git仓库中的无用文件(如编译后的产物文件)
1)找出编译产生的文件:进行编译,之后git status查看被自动修改的文件,其大概率为编译产生的文件
2)删除对应无用文件:rm xxx
3)将该无用文件路径添加到.gitignore
4)git add .gitignore & 删除的无用文件
Nginx简介 Nginx是一个高性能的Web服务器和反向代理的软件。 Web服务器:就是运行我们web服务的容器,提供web功能,还有tomcat也提供类似的功能。 代理是软件架构和网络设计中,非常重要的一个概念。有两种代理:正向代理和反向代理。 正向代理 用户端设置代理服务器。 所有的请求都由代理服务器发出,无法判断代理了多少用户端,叫正向代理。 反向代理 和正向代理相反:在服务端设置代理,所有请求,由服务端接受,然后再由代理服务器发到 后方的 服务器。这么一来,所有请求,都由一个服务器接收,无法判断代理了多少服务端。这就是反向代 理。 利用反向代理,就可以将请求分发到系统内部的多个节点上,从而减少每个节点的并发数。而这些节 点在外界看来,就是一个系统,表现出唯一的ip,也就是代理服务器的IP。 nginx最初是由一个俄罗斯人(Igor Sysoev:伊戈尔 塞索耶夫)开发的。Nginx的第一个版本发布于 2004年,因其系统资源消耗低、运行稳定,且具有高性能的并发处理能力等特性,Nginx在互联
企业中得到广泛应用。Nginx是互联网上最受欢迎的开源Web服务器之一,Netcraft公司2019年7月 的统计数据表明,Nginx为全球最繁忙网站中的25.42%提供了服务或代理。得益于近几年云计算和 微服务的快速发展,Nginx因在其中发挥了自身优势而得到广泛应用,且有望在未来占有更多的市场 份额。 2019年3月,著名硬件负载均衡厂商F5宣布收购Nginx,Nginx成为F5的一部分。 正向代理和反向代理的区别 1、代理对象不同。正向代理代理的是客户端,反向代理代理的是服务器。正向代理帮助客户访问其无法访问的服务器资源,反向代理帮助服务器做负载均衡,另外,由于客户端跟真实服务器不直接接触,能起到一定安全防护的作用。 2、架设主体不同。正向代理一般是客户端架设的,比如在自己的机器上装一个代理软件,反向代理一般是服务器架设的,通常是在机器集群中部署个反向代理服务器。 3、保护对象不同。正向代理保护对象是客户端,反向代理保护对象是原始资源服务器。 4、作用目的不同。正向代理主要目的是解决访问限制问题,而反向代理一方面是作为负载均衡,再就是起到安全防护的作用。
// Injection of resource dependencies failed; nested exception is org.springframework.beans. 今天项目启动报错,最终发现两个类,用@resource注入,变量名一样导致了冲突,改了变量名就好了
//错误的情况 @Resource private User user; @Resource private MyUser user; //修改后 @Resourceprivate User user; @Resourceprivate MyUser myUser;
1:要求实现父子进程对话
1.父进程先发送一句话给子进程,子进程接收后打印
2.子进程再回复一句话给父进程,父进程接收后打印
3.重复1.2步骤,当收到quit后,要结束父子进程
程序:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> int main(int argc, const char *argv[]) { //创建无名管道 int pfd[2]={0}; if(pipe(pfd)<0) { perror("pipe"); return -1; } int pfd1[2]={0}; if(pipe(pfd1)<0) { perror("pipe"); return -1; } char buf[]="quit"; char buf1[128]=""; ssize_t res=0; //创建子进程 pid_t pid=fork(); if(pid>0) //父进程为真,子进程为假 { while(1) { //从终端获取数据 bzero(buf1,sizeof(buf1)); waitpid(pid,NULL,WNOHANG); fgets(buf1,sizeof(buf1),stdin); buf1[strlen(buf1)-1]='\0'; if(strcmp(buf1,buf)==0) { printf("退出\n"); exit(0); } //发送给子进程 if((res=write(pfd[1],buf1,sizeof(buf1)))<0) { perror("
最近碰到一个题目,使用三种方式遍历一个list集合
键盘任意输入的五个int类型变量
使用三种不同的方法遍历集合,遍历输出时不换行,数字之间用空格隔开
import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); List<Integer> list = new ArrayList<>(); int num1 = scanner.nextInt(); int num2 = scanner.nextInt(); int num3 = scanner.nextInt(); int num4 = scanner.nextInt(); int num5 = scanner.nextInt(); scanner.close(); list.add(num1); list.add(num2); list.add(num3); list.add(num4); list.add(num5); System.out.print("普通for循环遍历:"); for(int i=0;i<list.size();i++){ //泛型容器类的获取其长度用size //数组,字符串获取其长度用length //泛型容器类获取其值可以用get方法,数组则是用[]加下标的方法 System.out.print(list.get(i)+" "); } System.out.println(); System.out.print("增强for循环遍历:"); for(int i:list){ System.
环境:Win10 x64,VS2019
官方链接:
FreeCAD 0.20: https://github.com/FreeCAD/FreeCAD
LibPack-0.20: https://github.com/FreeCAD/FreeCAD-LibPack/releases/tag/2.6
编译说明:Compile on Windows - FreeCAD Documentation
说明:请仔细阅读官方的编译说明,很多环境细节都考虑到,包括VS,Cmake,python等。第一次Cmake由于没注意python,导致代码无法编译,即使修改后能够编译也无法运行。用的笨办法,将电脑python全部删除,就可以正常运行。
Cmake配置:
更改下面两个位置编译后就可以直接运行
运行效果:
五、模块 5.1 基本概念 构成
模块的开始与结束: 模块在语言形式上是以关键词module开始、以关键词endmodule结束的一段程序,其中模块开始语句必须以分号结束。模块的开始部分包括模块名和端口列表,模块名是模块唯一的标识符,端口列表相当于引脚。
模块端口的定义: 定义端口列表中哪些是输入、输出、位宽
模块数据类型的声明 包括:wire、reg、memory、parameter等数据类型。
一般来说,module的input缺省定义为wire类型,output信号可以是wire类型,也可以是reg类型,inout一般为tri(三线型)类型,表示多个驱动源。
模块逻辑功能描述 产生各种逻辑(主要是组合逻辑和时序逻辑),包括initial语句,always语句、其他例化语句、连续赋值语句、函数和任务。
模块设计采用多种建模方式,行为描述方式、结构描述方式、混合描述方式
D触发器举例:
5.2 端口
定义
缺省状态下,默认端口类型是wire类型,在某一端口类型的声明中,类型的声明长度必须与端口声明的长度一致。
三种端口的声明方式:
输入端口: Input [信号位宽-1:0] 端口名 1;
输出端口 output [信号位宽-1:0] 端口名 1;
输入、输出端口 Inout [信号位宽-1:0] 端口名 1;
模块引用时端口的对应方式
在引用时,严格按照模块定义的端口顺序来连接,不用标明源模块定义时规定的端口名。在引用“.”标明源模块定义时规定的端口名
四、Verilog语法 1、空白符 2、注释符: 1、单行注释: //
2、多行注释: /* */
3、标识符和转义字符 标识符用来命名信号、模块、参数等,可以是任何字母、数字、$符号以及下划线的组合,标识符区分大小写,并且第一个字符必须是英文字母或下划线
4、关键字 5、数据类型 1、数值
Verilog的数值状态有四种,在逻辑数值中,x和z都不区分大小写。
状态
含义
0
低电平、逻辑0、假
1
高电平、逻辑1、真
X
不确定状态或者未知逻辑
Z
高阻态
在数值中,下划线符号“_”除了不能放在数值的首位外,可以随意在整型数与实例数中,他们对数值的大小没有改变,只是为了提高可读性。
整数的表示形式:+/-<size>’<base_format><number>其中,“+,-”是正负数的表示,size表示换算后的二进制宽度,“ ’ ”为基础格式表示的固有字符,不能缺省,base_format表示基数的符号;number是可以使用数字字符集。 注意:
在较长的数之间可以使用下划线来划分,目的是提高可读性当数字没有说明位宽时,默认是32X或者z在二进制代表1位x或z;在八进制代表3位;16进制代表4位若没有定义一个整数的位宽,其宽度应为相应值中定义的位数若定义的位宽比实际数的位数大,则在左边用0补齐,若最左边为0或者x则用0或者x补齐。如果定义的位宽比实际数的位宽小,则最左边的位被截断整数可以带正负号,并且正负号应写在最左边,负数用二进制的补码表示如果位宽与进制都缺省,则代表十进制数,数字中不能有空格,但在表示进制的字母两侧可以有空格。“ ?”表示高阻态数字中不能有空格,表示进制的字母两侧可以有空格 实数的表示方法 十进制表示:小数点两侧必须有数值科学计数法 2、字符串及其表示
双引号括起来的字符序列
1、数据类型
物理数据类型
最主要的物理数据类型是连线型、寄存器型和存储器型,并使用四种逻辑电平和八种信号强度对实际的硬件电路建模。信号强度表示数字电路中不同强度的驱动源,用来解决不同驱动强度下的赋值冲突。
标识符
名称
类型
强弱程度
Supply
电源级驱动
驱动
强
Strong
强驱动
驱动
Pull
上拉级驱动
驱动
Large
大容性
存储
Weak
弱驱动
驱动
Medium
中性驱动
存储
Small
小容性
存储
Highz
高容性
高阻
连线型
连线型数据类型
前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~
今天,我就来给大家分享一下python制作的几种圣诞树吧~
一:唯美圣诞 代码展示 导入模块
完整源码点击领取即可
import turtle as t from turtle import * import random as r import time n = 100.0 speed("fastest") screensize(bg='black') left(90) forward(3*n) color("orange", "yellow") begin_fill() left(126) for i in range(5): forward(n/5) right(144) forward(n/5) left(72) end_fill() color("dark green") backward(n*4.8) def tree(d, s): if d <= 0: return forward(s) tree(d-1, s*.8) right(120) tree(d-3, s*.5) drawlight()#同时画小彩灯 right(120) tree(d-3, s*.5) right(120) backward(s) tree(15, n) backward(n/2) for i in range(200): a = 200 - 400 * r.
/*
*@更多基础不会的加autojs交流群553908361喽;
一键加群:点击加群
这是一款
中间界面跳转 的源码,作为多功能跳转
"ui"; ui.layout( <vertical gravity="center" bg="file://1.jpg"> <button id="dyyh" textColor="#00F5FF" textSize="30sp"style="Widget.AppCompat.Button.Borderless"text="养号助手"/> <button id="dysh" textColor="#00F5FF" textSize="30sp"style="Widget.AppCompat.Button.Borderless"text="抖音上号"/> <button id="dyyx" textColor="#00F5FF"textSize="30sp" style="Widget.AppCompat.Button.Borderless"text="营销助手"/> <button id="ptrj" textColor="#00F5FF" textSize="30sp"style="Widget.AppCompat.Button.Borderless"text="配套软件"/> </vertical> ); ui.ptrj.click(function() { toastLog("请打开前往网址下载配套软件") //把双斜杠去掉,然后把双引号的网址,修改为你的就行了 app.openUrl("https://wwa.lanzous.com/b0aqufvcf") }); ui.dyyh.click(function() { //抖音养号助手 var ss="./dyyh.js"; engines.execScriptFile(ss) }); ui.dyyx.click(function() { //抖音引流 toastLog("等待开发") return var ss="./css.js"; engines.execScriptFile(ss) }); ui.dysh.click(function() { //抖音上号 toastLog("加载") var ss="./dysh.js"; engines.execScriptFile(ss) }); 其实可以看出,大部分代码都是重复的.你猜的没错.直接复制粘贴了
<button id="dyyh" textColor="#00F5FF" textSize="30sp"style="Widget.AppCompat.Button.Borderless"text="养号助手"/> //定义一个按钮文字,大小,颜色 ui.dyyh.click(function() { //抖音养号助手 var ss="
在开发过程中经常会发现当页面不应该出现的元素或内容会闪现一下然后消失 先看bug效果 我的收藏列表是有东西的,但是刚进入页面时看到了去添加,这是不应该被看到的,
下面是我的bug代码: <template> <div class="wai"> <tou-san :iconif="true" :fanhui="fanhui" name="我的收藏" :nameif="true" icon="icon-zuojiantou"></tou-san> <div v-if="shanglist.length == 0" class="kong"> <img style="width:2.2rem" src="${wu}" alt=""> <p style="Height:.3rem">你还没有收藏商家</p> <button style="${this.yangshi}">去逛逛</button> </div> <!-- <ul v-else> <li @click="xiangq(item.mtWmPoiId)" v-for="(item,index) in shanglist" :key="index"> <div> <img :src="item.picUrl" alt=""> </div> <div class="you"> <h3>{{item.name}}</h3> <div class="yi"> <p><span class="xing"> <span class="iconfont icon-xingxing"></span><span>{{item.wmPoiScore/10}}</span> </span> <span class="yuan">{{item.monthSalesTip}}</span> </p> <span>商家配送</span> </div> <div class="er"> <p> <span>{{item.minPriceTip}}</span> <span>{{item.shippingFeeTip}}</span> </p> <p> <span>{{item.deliveryTimeTip}}</span> <span>{{item.distance}}</span> </p> </div> <div class="
前言: ajax的简单应用,简单好懂。本次运用的软件为ideal,使用的是tomcat服务器,无框架编程。
AJAX是什么 Asynchronous JavaScript And XML
是一种通过JavaScript和后台进行通信的技术,能够实现页面的局部刷新,提高用户的体验
常规页面刷新会更新整个页面。
ajax技术通过浏览器局部发送请求给后台,后台通过resp.getWriter.print("");响应给前台页面
代码实现: 服务器代码: 一个类写入多个servlet: package com.dmdd.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class BaseServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String m = req.getParameter("m"); try { Method method=this.getClass().getDeclaredMethod(m,HttpServletRequest.class,HttpServletResponse.class); method.setAccessible(true); method.invoke(this,req,resp); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.
登录状态保持 导入三方模块 jsonwebtoken ,这个模块用来创建加密的身份令牌 token token可以设置过期时间,并不是token字符串消失了,只是不能用了,所以有效期到了,必须在服务器重新生成一个新的token。重新登录本地存储。在token身份令牌有效期间,客户端可以通过这个令牌对服务器进行一些请求操作,这个token字符串就相当于你的账号密码
在登录接口中传给前端,
//借助第三方包 jsonwebtoken 生成token字符串 //jwt.sign( 加密的数据 , 密钥 , { 算法, 过期时间 } ) var token = jwt.sign( { phone }, "1234", { algorithm:'HS256',expiresIn: 60 } ) //登陆成功时, 可以一并返回 登陆成功的用户信息,登陆令牌 res.send( {code:200, msg:'登陆成功!',userinfo: arr[i], token } ); 前端登录成功后立即将从后端拿到的token存入到本地存储 //将token存储到了localStorage中 localStorage.setItem('token',res.data.token); 前端在需要token令牌才能操作的页面全局设置axios拦截器 // 设置全局axios拦截 axios.interceptors.request.use( // 在ajax请求前把你给拦住,给你的请求头中加个参数 (config)=>{// 每次请求到服务器 前 都会执行 // 设置请求头参数 config.headers['Authorization'] = 'Bearer' + ' ' + localStorage.getItem('token'); return config }, (error)=>{ return Promise.
图片上传 input文件框 <input type="file"> 选中图片 上传服务器 input.onchange=function(e){ // 上传文件到服务器 // 上传文件时必须发送post类型的请求 // 上传文件时必须指定一个确定的字段(属性)作用是标识这是哪个用户的头像 // 上传文件时,先实例化一个FormData对象,将文件放入到FormData对象中,将FormData对象作为请求参数发送到服务器 var fd=new FormData() fd.append('touxiang',e.target.files[0]); fd.append('phone',JSON.parse( localStorage.getItem('userinfo')).phone) // 唯一的标识 axios.post('/user/touxiang',fd).then((res)=>{ // c头像存储到本地存储 localStorage.setItem('userinfo',JSON.stringify(res.data.userinfo)) document.querySelector('#touxiang').src=res.data.userinfo.touxiang } } 3、后端接收文件的特殊处理(index.js)
const multer=require('multer') // 配置磁盘存储引擎 var storage=multer.diskStorage({ // 文件存储的目的地 destination:(req,file,cb)=>{ // cb第一个参数时错误对象,没有就写null,第二个是存放路径 cb(null,'static/uploads') }, // 负责管理文件名 filename:(req,file,cb)=>{ // cb第一个参数时错误对象,没有就写null,第二个是文件名(不能写死,会覆盖) // cb(null,'a.png') // file.originalname // 原始文件名 cb(null,new Date().getTime()+path.extname(file.originalname)) } }) // 应用磁盘存储引擎(让上一步配置的磁盘存储引擎生效) var uploads=multer({storage}) // 注册文件上传中间件 // fd.append('touxiang',e.target.files[0]); // 里面那个名字必须和 前端那个名字一样 app.