Element中Upload组件上传(图片和文件的默认上传以及自定义上传)

目录

  • 一、代码实现([具体配置文档](https://element.eleme.cn/#/zh-CN/component/upload))
    • 1. 默认图片上传
    • 2. 自定义图片上传
    • 3. 默认文件上传
  • 二、效果图

一、代码实现(具体配置文档)

1. 默认图片上传

  1. 适用于:文件上传接口只要求file二进制文件,无需其他参数。(或者配置data属性用于上传时附带的额外参数)。
  2. 该实现方式会在选择完图片后就根据配置好的action的接口上传地址自动上传图片。
  3. 重点就是配置好action属性,以及限制类型和大小。
<template><div class="component-box"><!-- list-type :文件列表的类型,text/picture/picture-card --><!-- name	上传的文件字段名	string	—	file --><!-- show-file-list	是否显示已上传文件列表 --><!-- this.fileList.length >= this.limit 控制加号部分,不可以再加 --><!-- disabled	是否禁用	boolean	—	false --><el-upload:action="uploadImgUrl"list-type="picture-card":on-success="handleSuccess":before-upload="handleBefore":limit="limit":on-error="handleError":on-exceed="handleExceed"name="files":on-remove="handleRemove":show-file-list="true":headers="headers":file-list="fileList":on-preview="handlePreview":class="{ hide: this.fileList.length >= this.limit }":disabled="disabled":data="uploadData"><i class="el-icon-plus" /></el-upload><!-- 上传提示 --><div v-if="showTip" slot="tip" class="el-upload__tip">请上传<template v-if="fileSize">大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b></template><template v-if="fileType">格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b></template>的文件</div><el-dialog:close-on-click-modal="false":close-on-press-escape="false":visible.sync="isVisible"title="预览"width="800"append-to-body><img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" /></el-dialog></div>
</template><script>
//获取实际项目的token
// import { getToken } from '@/utils/auth'export default {props: {// 选择的图片数据value: [String, Object, Array],// 图片数量限制 limit	最大允许上传个数limit: {type: Number,default: 10},// 大小限制(MB)fileSize: {type: Number,default: 5},// 文件类型, 例如['png', 'jpg', 'jpeg']fileType: {type: Array,default: () => ['png', 'jpg', 'jpeg']},// 是否显示提示isShowTip: {type: Boolean,default: true},// 是否禁用disabled: {type: Boolean,default: false}},data() {return {// 预览图片地址dialogImageUrl: '',// 预览弹框是否显示isVisible: false,// hideUpload: false,// 接口地址baseUrl: process.env.VUE_APP_BASE_API,// 必选参数,上传的地址uploadImgUrl: process.env.VUE_APP_BASE_API + '图片服务器地址', // 上传的图片服务器地址// headers	设置上传的请求头部headers: { //获取实际token后,取消掉注释// Authorization: 'Bearer ' + getToken()},// file-list	上传的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}]	array	—	[]fileList: [],// 上传时附带的额外参数uploadData: { toPdf: false },}},computed: {// 是否显示提示showTip() {return this.isShowTip && (this.fileType || this.fileSize)}},watch: {value: {handler(val) {// console.log(val,'chak')if (val) {// 1.将值转为数组const list = Array.isArray(val) ? val : this.value.split(',')console.log(list)// 2.然后将数组转为对象数组this.fileList = list.map(item => {if (typeof item === 'string') {if (item.indexOf(this.baseUrl) === -1) {item = {name: item,url: item}} else {item = {name: item,url: item}}}return item})} else {this.fileList = []return []}},deep: true,immediate: true}},methods: {// 删除图片// on-remove	文件列表移除文件时的钩子	function(file, fileList)handleRemove(file) {const findex = this.fileList.map(f => f.name).indexOf(file.name)this.fileList.splice(findex, 1)// 获取到由所有文件的url地址组成的逗号分割的字符串this.$emit('input', this.getString(this.fileList))// 获取到选择的所有文件的所有信息this.$emit('getInput', JSON.stringify(this.fileList))},// 上传成功回调// 文件上传成功时的钩子	function(response, file, fileList)handleSuccess(res) {if (res && res.data && res.data[0]) {const result = res.data[0]this.fileList.push({name: result.originalName,url: result.fileUrl,id: result.id})// 获取到由所有文件的url地址组成的逗号分割的字符串this.$emit('input', this.getString(this.fileList))// 获取到选择的所有文件的所有信息this.$emit('getInput', JSON.stringify(this.fileList))console.log(this.getString(this.fileList), 'res')console.log(JSON.stringify(this.fileList), 'res')}this.loading.close()},// 上传前loading加载// before-upload上传文件之前的钩子,参数为上传的文件,// 若返回 false 或者返回 Promise 且被 reject,则停止上传。	function(file)handleBefore(file) {console.log(file, 'handleBefore')let isImg = false // 判断是否是图片if (this.fileType.length) {// 判断是否限制了类型let fileExtension = ''// 从后判断是否存在.,并且获取到他的下标,然后获取的上传的文件的后缀if (file.name.lastIndexOf('.') > -1) {fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)}isImg = this.fileType.some(type => {// 如果上传文件的类型type是规定的类型fileType中的某一个,返回trueif (file.type.indexOf(type) > -1) return true// 如果上传文件的后缀是规定的类型fileType中的某一个,返回trueif (fileExtension && fileExtension.indexOf(type) > -1) return true// 后缀返回falsereturn false})} else {// 判断上传的文件的类型是否是图片isImg = file.type.indexOf('image') > -1}// 如果不是图片则提示一下,且不可以上传if (!isImg) {this.$message.error(`文件格式不正确, 请上传${this.fileType.join('/')}图片格式文件!`)return false}// 判断大小,B<KB<MB<GB,且1 kB = 1024 B ,1 MB = 1024 kB ,1 GB = 1024 MB。// file.size 的单位是B// bit就是位,也叫比特位,是计算机表示数据最小的单位 ; byte就是字节//  1byte=8bit  ; 1byte就是1Bif (this.fileSize) {const isLt = file.size / 1024 / 1024 < this.fileSizeif (!isLt) {this.$message.error(`上传头像图片大小不能超过 ${this.fileSize} MB!`)return false}}this.loading = this.$loading({lock: true,text: '上传中',background: 'rgba(0, 0, 0, 0.7)'})},// 文件个数超出// on-exceed	文件超出个数限制时的钩子	function(files, fileList)handleExceed() {this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`)},// 上传失败// on-error	文件上传失败时的钩子	function(err, file, fileList)handleError() {this.$message({type: 'error',message: '上传失败'})this.loading.close()},// 预览// on-preview	点击文件列表中已上传的文件时的钩子	function(file)handlePreview(file) {this.dialogImageUrl = file.urlthis.isVisible = true},// 对象转成指定字符串分隔 (比如获取到由所有文件的url地址组成的逗号分割的字符串)getString(list, separator) {let strs = ''separator = separator || ','for (const i in list) {strs += list[i].url + separator}return strs != '' ? strs.substr(0, strs.length - 1) : ''}}
}
</script><style  scoped>
/* .el-upload--picture-card 控制加号部分 *//deep/ .hide .el-upload--picture-card {display: none;
}/* 去掉动画效果 */
/deep/ .el-list-enter-active,
/deep/ .el-list-leave-active {transition: all 0s;
}/deep/ .el-list-enter,
.el-list-leave-active {opacity: 0;transform: translateY(0);
}
</style>

2. 自定义图片上传

  1. 不需要配置action,使用http-request 覆盖默认的上传行为,可以自定义上传的实现。适用于文件上传需要file文件和其他参数。
  2. 或者在http-request的方法中不做任何操作,在before-upload上传前的校验中,保存将要上传的文件file,然后页面根据实际需要,调用方法上传图片。(如在页面中加一个提交按钮,点击调用提交方法上传图片)。
  3. 重点简单了解FormData的使用和Content-Type的类型
// 可以根据后台接口要求来决定参数的类型onChange() {//通常文件上传是要用 FormData 格式的this.formdata = new FormData()this.formdata.append('file', this.file)this.formdata.append('name', this.name)},
// this.formdata 就是要传给后台的参数了
  1. multipart/form-data支持文件上传的格式,一般需要上传文件的表单则用该类型。
// 头像上传
// export function uploadAvatar(data) {
//     return request({
//       url: '/manager/user/uploadAvatar',
//       method: 'post',
//       data: data,
//       headers: {
//         'Content-Type': 'multipart/form-data'
//       }
//     })
//   }
<template><div class="component-box"><!-- http-request	覆盖默认的上传行为,可以自定义上传的实现 --><el-uploadaction=""list-type="picture-card":before-upload="handleBefore":limit="limit":http-request="handleFileUpload":on-error="handleError":on-exceed="handleExceed":on-remove="handleRemove":show-file-list="true":file-list="fileList":on-preview="handlePreview":class="{ hide: fileList.length >= limit }":disabled="disabled"><i class="el-icon-plus" /></el-upload><!-- 上传提示 --><div v-if="showTip" slot="tip" class="el-upload__tip">请上传<template v-if="fileSize">大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b></template><template v-if="fileType">格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b></template>的文件</div><el-dialog:close-on-click-modal="false":close-on-press-escape="false":visible.sync="dialogVisible"title="预览"width="800"append-to-body><img:src="isVisible"style="display: block; max-width: 100%; margin: 0 auto"/></el-dialog></div>
</template><script>
export default {props: {value: [String, Object, Array],// 图片数量限制limit: {type: Number,default: 10,},// 大小限制(MB)fileSize: {type: Number,default: 10,},// 文件类型, 例如['png', 'jpg', 'jpeg']fileType: {type: Array,default: () => ["png", "jpg", "jpeg"],},// 是否显示提示isShowTip: {type: Boolean,default: true,},// 是否禁用disabled: {type: Boolean,default: false,},// 详情idpeopleId: {type: String,default: () => "",},},data() {return {isVisible: "",dialogVisible: false,baseUrl: process.env.VUE_APP_BASE_API,fileList: [],// file:null,};},computed: {// 是否显示提示showTip() {return this.isShowTip && (this.fileType || this.fileSize);},},watch: {value: {handler(val) {if (val) {// 1.将值转为数组const list = Array.isArray(val) ? val : this.value.split(",");// 2.将数组转为对象数组this.fileList = list.map((item) => {if (typeof item === "string") {if (item.indexOf(this.baseUrl) === -1) {item = {name: item,url: item,};} else {item = {name: item,url: item,};}}return item;});} else {this.fileList = [];return [];}},deep: true,immediate: true,},},methods: {// 删除图片handleRemove(file) {const findex = this.fileList.map((f) => f.name).indexOf(file.name);this.fileList.splice(findex, 1);this.$emit("input", this.getString(this.fileList));this.$emit("getInput", JSON.stringify(this.fileList));},// 上传成功回调handleUploadSuccess(res) {console.log(res, "success");const result = res.data[0];this.fileList.push({name: result.originalName,url: result.fileUrl,id: result.id,});this.$emit("input", this.getString(this.fileList));this.$emit("getInput", JSON.stringify(this.fileList));console.log(this.getString(this.fileList), "res");console.log(JSON.stringify(this.fileList), "res");this.loading.close();},// 上传前loading加载handleBefore(file) {// this.file = filelet isImg = false;if (this.fileType.length) {let fileExtension = "";if (file.name.lastIndexOf(".") > -1) {fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);}isImg = this.fileType.some((type) => {if (file.type.indexOf(type) > -1) return true;if (fileExtension && fileExtension.indexOf(type) > -1) return true;return false;});} else {isImg = file.type.indexOf("image") > -1;}if (!isImg) {this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`);return false;}if (this.fileSize) {const isLt = file.size / 1024 / 1024 < this.fileSize;if (!isLt) {this.$message.error(`上传头像图片大小不能超过 ${this.fileSize} MB!`);return false;}}this.loading = this.$loading({lock: true,text: "上传中",background: "rgba(0, 0, 0, 0.7)",});},// 文件个数超出handleExceed() {this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);},// 上传失败handleError() {this.$message({type: "error",message: "上传失败",});this.loading.close();},// 预览handlePreview(file) {this.isVisible = file.url;this.dialogVisible = true;},// 对象转成指定字符串分隔getString(list, separator) {let strs = "";separator = separator || ",";for (const i in list) {strs += list[i].url + separator;}return strs != "" ? strs.substr(0, strs.length - 1) : "";},// http-request	覆盖默认的上传行为,可以自定义上传的实现	function// 上传文件的文件流是无法被序列化并传递的。所以我们就可以使用到formdata对象,就可以轻松进行文件上传了。// 创建formdata对象实例的方式 :new FormData()// 添加数据:append(key,value) 如果key不存在会新增一条数据,如果key存在,则添加到数据末尾handleFileUpload(e) {console.log(e);// let _this = thislet formdata = new FormData();formdata.append("file", e.file);console.log(formdata, "formdata");// 上传图片// uploadAvatar(formdata)// 	.then(res => {// 		console.log(res,'res')// ......// 		_this.loading.close()// 	})// 	.catch(() => {// 		_this.fileList = []// 		this.loading.close()// 	})},// 上传图片 (也可以在页面上面加一个提交的按钮,点击按钮调用这个方法进行上传,上述handleFileUpload方法中不写任何代码)uploadImg() {// let formData = new FormData();// name上传的文件字段名上传的文件字段名,默认是"file",具体根据接口来// this.files 在上传前的handleBefore方法中保存这个文件// formData.append("file", this.files);// uploadAvatar(formData).then((response) => {// ......................// });},},
};
</script><style  scoped>
/* .el-upload--picture-card 控制加号部分 *//deep/ .hide .el-upload--picture-card {display: none;
}/* 去掉动画效果 */
/deep/ .el-list-enter-active,
/deep/ .el-list-leave-active {transition: all 0s;
}/deep/ .el-list-enter,
.el-list-leave-active {opacity: 0;transform: translateY(0);
}
</style>

3. 默认文件上传

  1. 和上述图片上传是一样的原理,只不过是限制的类型不一样。
<template><div class="upload-file"><!-- drag	是否启用拖拽上传	boolean	—	false --><!-- data	上传时附带的额外参数	object --><el-upload :drag="drag" ref="upload" :action="uploadFileUrl" v-if="showDing" :before-upload="handleBefore":file-list="fileList" :limit="limit" name="files" :on-error="handleError" :on-exceed="handleExceed":on-success="handleSuccess" :show-file-list="false" :headers="headers" class="upload-file-uploader":data="uploadData"><!-- 上传按钮 --><el-button v-if="showDing" size="mini" type="primary">选取文件</el-button><!-- 上传提示 --><div v-if="showTip" slot="tip" class="el-upload__tip">请上传<template v-if="fileSize">大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b></template><template v-if="fileType">格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b></template>的文件</div></el-upload><!-- 文件列表 --><transition-group class="transition-box"  tag="ol"><li v-for="(file, index) in fileList" :key="index" class="upload-item-box"><div class="upload-item"><div><el-link><span class="el-icon-document" style="margin-left: 10px">{{ file.name }}</span></el-link></div><div><el-link :underline="false" class="look" type="primary" @click="handlePrew(file)"><span class="el-icon-view"> 查看 </span></el-link><div class="delBox" v-if="showDing"><el-link v-if="index > number - 1" class="el-icon-delete link" :underline="false" type="danger"@click="handleDelete(index)">删除</el-link></div></div></div></li></transition-group></div>
</template><script>
// import { getToken } from "@/utils/auth";
export default {name: "FileUpload",props: {// 值value: [String, Object, Array],// 数量限制limit: {type: Number,default: 5,},// 大小限制(MB)fileSize: {type: Number,default: 10,},number: {type: Number,default: -1000,},// 文件类型, 例如['png', 'jpg', 'jpeg']fileType: {type: Array,default: () => ["png", "jpg", "jpeg", "doc", "xls", "ppt", "pdf"],},imageType: {type: Array,default: () => ["png", "jpg", "jpeg"],},// 是否显示提示上传提示isShowTip: {type: Boolean,default: true,},showDing: {type: Boolean,default: true,},drag: {type: Boolean,default: false,},},data() {return {loading: {},uploadData: { toPdf: false },baseUrl: process.env.VUE_APP_BASE_API,uploadFileUrl: process.env.VUE_APP_BASE_API + "图片服务器地址", // 上传的图片服务器地址headers: {// Authorization: "Bearer " + getToken(),},fileList: [],files: [],};},computed: {// 是否显示提示showTip() {return this.isShowTip && (this.fileType || this.fileSize);},},watch: {value: {handler(val) {if (val) {this.files = val;var that = this;let temp = 1;// 1.将值转为数组// this.fileListconst list = Array.isArray(val) ? val : this.value.split(",");// 2.将数组转为对象数组this.fileList = list.map((item, index) => {if (typeof item === "string") {item = { url: item };}item.name = that.files[index].originalName;item.uid = item.uid || new Date().getTime() + temp++;return item;});} else {this.fileList = [];this.files = [];return [];}},deep: true,immediate: true,},},methods: {// 预览handlePrew(file) {window.open(file.fileUrl);},// 上传前校检格式和大小handleBefore(file) {// 校检文件类型if (this.fileType) {let fileExtension = "";if (file.name.lastIndexOf(".") > -1) {fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);}// fileExtension: jfifconst isTypeOk = this.fileType.some((type) => {// 这里注意jfif图片 类型的解析 会在第一步直接解析成image/jpegif (file.type.indexOf(type) > -1) return true;if (fileExtension && fileExtension.indexOf(type) > -1) return true;return false;});if (!isTypeOk) {this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);return false;}// 判断一下,如果类型是this.imageType中的某一个,比如这里指的是图片类型,不需要转为pdf格式// this.uploadData.toPdf 这个是额外的数据,具体看实际项目以及和后端配合有关if (this.imageType) {let toPdf = true;this.imageType.some((type) => {// 这里注意jfif图片 类型的解析 会在第一步直接解析成image/jpegif (file.type.indexOf(type) > -1) {toPdf = false;}if (fileExtension && fileExtension.indexOf(type) > -1) {toPdf = false;}});this.uploadData.toPdf = toPdf;}}// 校检文件大小if (this.fileSize) {const isLt = file.size / 1024 / 1024 < this.fileSize;if (!isLt) {this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);return false;}}this.loading = this.$loading({lock: true,text: "上传中",background: "rgba(0, 0, 0, 0.7)",});console.log(file, "file");return true;},// 文件个数超出handleExceed() {this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);},// 上传失败handleError() {console.log("handleError");this.$message.error("上传失败, 请重试");this.loading.close();},// 上传成功回调handleSuccess(res, file) {console.log("handleSuccess", res, file);if (res.data && res.data[0]) {const result = res.data[0];this.fileList.push({ id: result.id, name: result.originalName, url: result.fileUrl });this.files.push(result);this.$emit("getInput", this.fileList);this.$emit("input", this.files);// 获取由选择文件的id组成的以逗号分割的字符串this.$emit("getId", this.getString(this.fileList, ',', 'id'));this.loading.close();} else {this.$message.error(res.msg);this.loading.close();}},// 删除文件handleDelete(index) {this.fileList.splice(index, 1);this.files.splice(index, 1);this.$emit("getInput", this.fileList);this.$emit("input", this.files);this.$emit("getId", this.getString(this.fileList, ',', 'id'));},// 对象转成指定字符串分隔getString(list, separator, FieldName) {let strs = "";separator = separator || ",";for (const i in list) {strs += list[i][FieldName] + separator;}return strs != "" ? strs.substr(0, strs.length - 1) : "";},},
};
</script><style scoped>
.upload-file-uploader {margin-bottom: 5px;
}.transition-box .upload-item-box{border: 1px solid #e4e7ed;line-height: 3;margin-bottom: 10px;position: relative;
}.upload-item{width: 95%;display: flex; justify-content: space-between;
}.delBox{display: inline-block;
}.look {margin-left: 10px;margin-right: 10px;
}
</style>

二、效果图

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/415819.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【docker-compose】【nginx】内网环境https配置

目录 1、openssl生成自签名证书和私钥2、nginx.conf配置ssl3、docker-compose挂载 1、openssl生成自签名证书和私钥 在部署服务器上&#xff0c;新建cert目录&#xff0c;执行以下指令&#xff0c;然后生成.crt和.key文件 openssl req -newkey rsa:2048 -nodes -keyout rsa_pri…

图灵日记之java奇妙历险记--String类

目录 String常用方法字符串构造String对象的比较字符串查找char charAt(int index)int indexOf(int ch)int indexOf(int ch, int fromIndex)int indexOf(String str)int indexOf(String str, int fromIndex)int lastIndexOf(String str)int lastIndexOf(String str, int fromIn…

禅道(ZenTao)项目管理工具

认识禅道 禅道&#xff08;Zentao&#xff09;是一个面向敏捷开发的项目管理软件&#xff0c;它是一款开源的团队协作工具。禅道提供了项目管理、任务管理、缺陷管理、文档管理等功能&#xff0c;帮助团队高效地进行项目管理工作。禅道致力于提供简单易用、功能强大、界面美观的…

C++类相关oj题目分享(计算日期到天数转换、日期差值、打印日期、日期累加)

文章目录 1.计算日期到天数转换题目详情代码思路 2.KY111 日期差值题目详情代码思路 3.KY222 打印日期题目详情代码 4.KY258 日期累加题目详情代码思路 1.计算日期到天数转换 传送门 题目详情 代码 #include <iostream> using namespace std; int GetDay(int year,int…

Qt/C++中英输入法/嵌入式输入法/小数字面板/简繁切换/特殊字符/支持Qt456

一、前言 在嵌入式板子上由于没有系统层面的输入法支持&#xff0c;所以都绕不开一个问题&#xff0c;那就是在需要输入的UI软件中&#xff0c;必须提供一个输入法来进行输入&#xff0c;大概从Qt5.7开始官方提供了输入法的源码&#xff0c;作为插件的形式加入到Qt中&#xff…

【docker】安装 CentOS

查看可用的 CentOS版本 docker search centOS拉取 CentOS最新镜像 docker pull centos:latest 查看本地镜像 docker images运行容器 docker run -itd --name centos-demo centos查看进程 docker ps进入centos容器 docker exec -it centos-demo /bin/bash停止容器 docker …

Autosar信息安全入门系列01-SecOC基础介绍

本文框架 1. 概述2. SecOC基本概念2.1 SecOC是什么&#xff1f;2.2 新鲜度值与MAC值2.3 SecOC报文格式 3. SecOC报文发送及接收逻辑3.1 SecOC报文的发送3.2 SecOC报文的接收 1. 概述 本文为Autosar通信入门系列介绍&#xff0c;如您对AutosarMCAL配置&#xff0c;通信&#xf…

C++编写、生成、调用so库详解(二)

我们上篇中主要讲了怎么去打包so库 C编写、生成、调用so库详解(一) 这篇我们就来说一些怎么调用so库 目录 1.调用符合JNI标准的so库 2.调用不符合JNI标准的so库 上面说了两种不同类型的so库,我们分别来看一下怎么调用这两种,在调用so库之前,我们先说一下直接调用上面写的C…

解决Uniapp插件市场试用原生插件项目 没有MD5签名安卓无法自定基座打包的情况

Uniapp插件市场中&#xff0c;有些插件是原生插件&#xff0c;必须使用自定义基座才能打包。但是传统keytool命令&#xff0c;已经无法看到安卓证书的MD5签名。现采用Android Studio查询signingReport的办法获取证书的MD5签名&#xff0c;并对插件的示例项目进行打包运行。一、…

烟火检测/周界入侵/视频智能识别AI智能分析网关V4如何配置ONVIF摄像机接入

AI边缘计算智能分析网关V4性能高、功耗低、检测速度快&#xff0c;易安装、易维护&#xff0c;硬件内置了近40种AI算法模型&#xff0c;支持对接入的视频图像进行人、车、物、行为等实时检测分析&#xff0c;上报识别结果&#xff0c;并能进行语音告警播放。算法可按需组合、按…

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 例4-5 select

代码 <!doctype html> <html> <head> <meta charset"utf-8"> <title>select</title> </head><body> <!--单选下拉菜单可设置默认选中项--> 所在城市&#xff08;单选&#xff09;:<br> <select>…

广告灯的左移右移

1&#xff0e;  实验任务 做单一灯的左移右移&#xff0c;硬件电路如图4.4.1所示&#xff0c;八个发光二极管L1&#xff0d;L8分别接在单片机的P1.0&#xff0d;P1.7接口上&#xff0c;输出“0”时&#xff0c;发光二极管亮&#xff0c;开始时&#xff0c;P1.0→P1.1→P1.2→…