Vue3 + Element-Plus + vue-draggable-plus 实现图片拖拽排序和图片上传到阿里云 OSS 父组件实现真正上传(最新保姆级)

Vue3 + Element-Plus + vue-draggable-plus 实现图片拖拽排序和图片上传到阿里云 OSS(最新保姆级)父组件实现真正上传

  • 1、效果展示
  • 2、UploadImage.vue 组件封装
  • 3、相关请求封装
  • 4、SwiperConfig.vue 调用组件
  • 5、后端接口

1、效果展示


在这里插入图片描述

如果没有安装插件,请先安装 vue-draggable-plus 插件:

cnpm install vue-draggable-plus

2、UploadImage.vue 组件封装


<template><div class="draggable_image_upload"><VueDraggable class="box-uploader" ref="draggableRef" v-model="curList" :animation="600" easing="ease-out"ghostClass="ghost" draggable="ul" @start="onStart" @update="onUpdate"><!-- 使用element-ui el-upload自带样式 --><ul v-for="(item, index) in curList" :key="index" class="el-upload-list el-upload-list--picture-card"><li class="el-upload-list__item is-success animated":style="{ 'height': props.height + ' !important', 'width': props.width + ' !important', 'margin-right': props.space + ' !important' }"><el-image class="originalImg" :src="item.url" :preview-src-list="[item.url]":style="{ 'height': props.height + ' !important', 'width': props.width + ' !important' }" /><label class="el-upload-list__item-status-label"><el-icon class="el-icon--upload-success el-icon--check"><Check /></el-icon></label><span class="el-upload-list__item-actions"><!-- 预览    --><span class="el-upload-list__item-preview" @click="handleImgPreview('originalImg', index)"><el-icon><ZoomIn /></el-icon></span><!-- 删除    --><span class="el-upload-list__item-delete" @click="onImageRemove(item.url)"><el-icon><Delete /></el-icon></span></span></li></ul><!-- 上传组件 --><el-upload v-model:file-list="curList" :action="UPLOAD_IMG_URL" :multiple="multiple"list-type="picture-card" :accept="accept" :show-file-list="false" :before-upload="beforeImgUpload":on-success="handleImgSuccess" ref="uploadRef" :auto-upload="autoUpload" drag><el-icon :style="{ 'height': props.height + ' !important', 'width': props.width + ' !important' }"><Plus /></el-icon></el-upload></VueDraggable></div>
</template><script name="DraggableImageUpload" setup>
import { UPLOAD_IMG_URL, uploadImageApi } from "@/api/upload/index"; //请求url
import { Check, Delete, Download, Plus, ZoomIn } from '@element-plus/icons-vue';
import { ElMessage } from "element-plus";
import { getCurrentInstance, onMounted, reactive, ref, toRefs, computed } from 'vue';
import { VueDraggable } from 'vue-draggable-plus';const draggableRef = ref(null);const { proxy } = getCurrentInstance();const props = defineProps({accept: {type: String,default: ".jpg,.jpeg,.png"},limit: {type: Number,default: 9999},multiple: {type: Boolean,default: true},autoUpload: {type: Boolean,default: false},height: {type: String,default: "100px"},width: {type: String,default: "100px"},space: {type: String,default: "20px"},modelValue: {type: Array,default: () => []}
});
const {modelValue
} = toRefs(props);const data = reactive({maxImgsLen: 0,imgList: []
});const { maxImgsLen, imgList } = toRefs(data);const emit = defineEmits(["update:modelValue", "upload-failure", "upload-success"]);
const curList = computed({get() {return props.modelValue;},set(newValue) {emit("update:modelValue", newValue);}
});const onStart = () => {console.log('start');
};const onUpdate = () => {console.log(curList.value, 'update++++++++++++++');
};const handleImgPreview = (domClass, index) => {const dom = document.getElementsByClassName(domClass);dom[index].firstElementChild.click(); //调用 el-image 的预览方法
};const onImageRemove = (url) => {const list = [...curList.value];list.forEach((item, index) => {if (url === item.url) {list.splice(index, 1);}});curList.value = list;
};const beforeImgUpload = (rawFile) => {const types = ["image/jpeg", "image/jpg", "image/png"];const size = rawFile.size;const isImage = types.includes(rawFile.type);const isLt5M = size / 1024 / 1024 < 5;if (!isImage) {ElMessage("请上传jpeg、jpg、png类型的图片", {type: "error"});return false;} else if (!isLt5M) {ElMessage("上传图片大小不能超过5MB", {type: "error"});return false;}return true;
};const uploadImage = async (file) => {let res = await uploadImageApi(file);return res.data;
}/*** 提供给外部的上传触发方法*/
const triggerUpload = async () => {for (let i = 0; i < modelValue.value.length; i++) {const file = modelValue.value[i];if (file.status === 'ready') {modelValue.value[i] = {...file,status: 'uploading',message: '上传中',};const formData = new FormData();formData.append('file', file.raw);  // 将 File 对象添加到 FormDataconst uploadedUrl = await uploadImage(formData);modelValue.value[i] = {name: file.name,size: file.size,uid: file.uid,status: 'success',url: uploadedUrl,};}emit('upload-success');}
};/*** 提供给外部的函数*/
defineExpose({triggerUpload,
});function handleImgSuccess() {ElMessage.success("图片上传成功");// This can be extended based on the response structure from the server// For example, you might want to add the uploaded image to your imgListconst uploadedFile = {url: response.url, // Assume the response contains the image URLname: file.name,size: file.size};curList.value.push(uploadedFile); // Add the uploaded image to curList
}
</script><style lang="scss" scoped>
::v-deep(.el-upload-dragger) {padding: 0;display: flex;justify-content: center;align-items: center;
}.draggable_image_upload {.box-uploader {display: flex;flex-wrap: wrap;vertical-align: middle;:deep(.el-upload) {border-radius: 4px;.circle-plus {width: 24px;height: 24px;}&.el-upload-list {&.el-upload__item {width: 100px;height: 100px;margin: 0 17px 17px 0;border-color: #e7e7e7;padding: 3px;}}&.el-upload--picture-card {border-style: dashed;margin-right: 17px;}}.el-upload-list__item {margin: 0 17px 17px 0;border-color: #e7e7e7;padding: 3px;.originalImg {:deep(.el-image__preview) {-o-object-fit: contain;object-fit: contain;}}}ul:nth-child(6n+6) {li {margin-right: 0;}}}
}
</style>

3、相关请求封装

http/index.ts

/** @Date: 2024-08-17 14:18:14* @LastEditors: zhong* @LastEditTime: 2024-09-17 19:22:36* @FilePath: \rentHouseAdmin\src\api\upload\index.ts*/
import axios from 'axios'
import type {AxiosInstance,AxiosError,AxiosRequestConfig,AxiosResponse,
} from 'axios'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/store/modules/user'
import { ResultEnum } from '@/enums/httpEnums'
import { ResultData } from './type'
import { LOGIN_URL } from '@/config/config'
import { RESEETSTORE } from '../reset'
import router from '@/router'export const service: AxiosInstance = axios.create({// 判断环境设置不同的baseURLbaseURL: import.meta.env.PROD ? import.meta.env.VITE_APP_BASE_URL : '/',timeout: ResultEnum.TIMEOUT as number,
})
/*** @description: 请求拦截器* @returns {*}*/
service.interceptors.request.use((config) => {const userStore = useUserStore()const token = userStore.tokenif (token) {config.headers['access-token'] = token}return config},(error: AxiosError) => {ElMessage.error(error.message)return Promise.reject(error)},
)
/*** @description: 响应拦截器* @returns {*}*/
service.interceptors.response.use((response: AxiosResponse) => {const { data } = response// * 登陆失效if (ResultEnum.EXPIRE.includes(data.code)) {RESEETSTORE()ElMessage.error(data.message || ResultEnum.ERRMESSAGE)router.replace(LOGIN_URL)return Promise.reject(data)}if (data.code && data.code !== ResultEnum.SUCCESS) {ElMessage.error(data.message || ResultEnum.ERRMESSAGE)return Promise.reject(data)}return data},(error: AxiosError) => {// 处理 HTTP 网络错误let message = ''// HTTP 状态码const status = error.response?.statusswitch (status) {case 401:message = 'token 失效,请重新登录'breakcase 403:message = '拒绝访问'breakcase 404:message = '请求地址错误'breakcase 500:message = '服务器故障'breakdefault:message = '网络连接故障'}ElMessage.error(message)return Promise.reject(error)},
)/*** @description: 导出封装的请求方法* @returns {*}*/
const http = {get<T>(url: string,params?: object,config?: AxiosRequestConfig,): Promise<ResultData<T>> {return service.get(url, { params, ...config })},post<T>(url: string,data?: object,config?: AxiosRequestConfig,): Promise<ResultData<T>> {return service.post(url, data, config)},put<T>(url: string,data?: object,config?: AxiosRequestConfig,): Promise<ResultData<T>> {return service.put(url, data, config)},delete<T>(url: string,data?: object,config?: AxiosRequestConfig,): Promise<ResultData<T>> {return service.delete(url, { data, ...config })},
}export default http

http/type.ts

// * 请求响应参数(不包含data)
export interface Result {code: numbermessage: stringsuccess?: boolean
}// * 请求响应参数(包含data)
export interface ResultData<T = any> extends Result {data: T
}

index.ts

/** @Date: 2024-08-17 14:18:14* @LastEditors: zhong* @LastEditTime: 2024-09-17 19:22:36* @FilePath: \rentHouseAdmin\src\api\upload\index.ts*/
// 上传基础路径
export const BASE_URL = import.meta.env.PROD? import.meta.env.VITE_APP_BASE_URL: ''
// 图片上传地址
export const UPLOAD_IMG_URL = `/admin/file/upload`
import http from '@/utils/http'/*** @description 上传图片接口* @param params*/
export function uploadImageApi(file: FormData) {return http.post<any[]>(UPLOAD_IMG_URL,file)
}

4、SwiperConfig.vue 调用组件


<!--* @Date: 2024-12-14 15:08:55* @LastEditors: zhong* @LastEditTime: 2024-12-15 20:51:31* @FilePath: \admin\src\views\small\smallSetting\components\SwiperConfig.vue
-->
<template><div class="card main"><div class="left"><div style="text-align: center;margin-bottom: 20px;"><text style="font-size: 20px;">云尚社区</text></div><div class="mt-4"><el-input style="border-radius: 10px;" size="small" placeholder="请输入关键字" :prefix-icon="Search" /></div><div style="margin-top: 10px;"><el-carousel :interval="4000" type="card" class="card" height="100px" indicator-position="none"style="padding: 6px 0;border-radius: 10px;"><el-carousel-item v-for="(item, index) in data" :key="index"><el-image :src="item.settingValue" style="height: 100px;border-radius: 6px;" /></el-carousel-item></el-carousel></div><div class="card menu"><div v-for="(item, index) in menuList" :key="index" class="menu-item"><div style="display: flex; flex-direction: column;"><el-image :src="item.url" style="height: 60px;width: 70px;;border-radius: 6px;" /><el-text style="margin-top: 8px;">{{ item.name }}</el-text></div></div></div></div><el-divider direction="vertical" style="height: 620px;margin-left: 50px;border-width: 2px;">可选配置</el-divider><div class="right"><el-tag type="" size="large" effect="dark">轮播图配置</el-tag><div style="display: flex;margin-top: 20px;"><div v-for="(item, index) in data" :key="index" style="padding-right: 20px;"><el-image :src="item.settingValue" style="height: 80px;width: 160px;;border-radius: 6px;" /></div></div><div style="margin-top: 20px;"><DraggableImageUpload @upload-success="onUploadSuccess" v-model="uploadImageArray" ref="imageUploadRef"height="80px" width="160px" space="20px" /><el-button type="" @click="handleImageUpload" style="margin-top: 20px;">替换</el-button></div></div></div>
</template><script setup>
import DraggableImageUpload from '@/components/UploadImage/UploadImage.vue'
import { getSystemSettingsConfigApi } from '@/api/system';
import { onMounted, ref } from 'vue';
import { Search } from '@element-plus/icons-vue';
const data = ref([]);
const uploadImageArray = ref([]);
const getSystemSettingsConfig = async () => {let res = await getSystemSettingsConfigApi();data.value = res.data.settingMap.one;console.log(data.value);
}onMounted(() => {getSystemSettingsConfig();
})// 菜单信息
const menuList = ref([]);const imageUploadRef = ref(null); // 创建 ref 引用
const handleImageUpload = () => {imageUploadRef.value.triggerUpload();
}// 上传成功回调
const onUploadSuccess = () => {console.log(uploadImageArray.value);
};
</script><style lang="scss" scoped>
::v-deep(li.el-upload-list__item.is-success) {margin-right: 20px;height: 80px;width: 160px;
}::v-deep(.el-upload.el-upload--picture-card) {height: 80px;width: 160px;
}.main {display: flex;justify-content: space-between;padding: 20px;
}.menu {display: flex;align-items: center;justify-content: center;flex-wrap: wrap;/* 自动换行 */gap: 20px;row-gap: 15px;/* 元素间距 */max-height: calc(40px * 2 + 20px * 2 + 50px);/* 限制两排的总高度 */overflow: hidden;/* 超出隐藏 */margin-top: 10px;border-radius: 10px;
}.item {width: calc(25% - 10px);/* 每排最多显示 4 个 */box-sizing: border-box;
}.content {display: flex;flex-direction: column;align-items: center;
}::v-deep(.el-input__wrapper) {height: 26px;border-radius: 20px;
}.left {padding: 10px;height: 600px;background-color: #f8f8f8;width: 400px;
}.right {margin-left: 50px;flex: 1;height: 600px;
}
</style>

5、后端接口


FileUploadController.java

package com.zhong.controller.apartment;import com.zhong.result.Result;
import com.zhong.utils.AliOssUtil;
import io.minio.errors.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;@Tag(name = "文件管理")
@RequestMapping("/admin/file")
@RestController
public class FileUploadController {@Autowiredprivate AliOssUtil ossUtil;@Operation(summary = "上传文件")@PostMapping("/upload")public Result<String> upload(@RequestParam MultipartFile file) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {// 获取文件原名String originalFilename = file.getOriginalFilename();// 防止重复上传文件名重复String fileName = null;if (originalFilename != null) {fileName = UUID.randomUUID() + originalFilename.substring(originalFilename.indexOf("."));}// 把文件储存到本地磁盘
//        file.transferTo(new File("E:\\SpringBootBase\\ProjectOne\\big-event\\src\\main\\resources\\flies\\" + fileName));String url = ossUtil.uploadFile(fileName, file.getInputStream());System.out.println();return Result.ok(url);}
}

AliOssUtil.class

package com.zhong.utils;import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.zhong.result.Result;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;/*** @ClassName : AliOssUtil* @Description : 阿里云上传服务* @Author : zhx* @Date: 2024-03-1 20:29*/
@Component
@Service
public class AliOssUtil {@Value("${alioss.endpoint}")private String ENDPOINT;@Value("${alioss.bucketName}")private String BUCKETNAME;@Value("${alioss.access_key}")private String ACCESS_KEY;@Value("${alioss.access_key_secret}")private String ACCESS_KEY_SECRET;public String uploadFile(String objectName, InputStream inputStream) {String url = "";// 创建OSSClient实例。System.out.println(ACCESS_KEY);OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY, ACCESS_KEY_SECRET);try {// 创建PutObjectRequest对象。// 生成日期文件夹路径,例如:2022/04/18SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd");String dateStr = dateFormat.format(new Date());PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKETNAME, dateStr + "/" + objectName, inputStream);// 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。// ObjectMetadata metadata = new ObjectMetadata();// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());// metadata.setObjectAcl(CannedAccessControlList.Private);// putObjectRequest.setMetadata(metadata);// 上传文件。PutObjectResult result = ossClient.putObject(putObjectRequest);url = "https://" + BUCKETNAME + "." + ENDPOINT.substring(ENDPOINT.lastIndexOf("/") + 1) + "/" + dateStr + "/" + objectName;} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}return url;}public  Result deleteFile(String objectName) {System.out.println(objectName);// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY, ACCESS_KEY_SECRET);try {// 删除文件。System.out.println(objectName);System.out.println(objectName.replace(",", "/"));ossClient.deleteObject(BUCKETNAME, objectName.replace(",", "/"));return Result.ok("删除成功!");} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}return Result.fail(555,"上传失败!");}
}

application.yml

alioss: # 阿里云配置endpoint: "https://cn-chengdu.oss.aliyuncs.com"    # Endpoint以西南(成都)为例,其它Region请按实际情况填写。bucketName: ""  # 填写Bucket名称,例如examplebucket。access_key: ""  # 点击头像->Accesskey管理查看 秘钥access_key_secret: "" # 密码

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

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

相关文章

将 Ubuntu 22.04 LTS 升级到 24.04 LTS

Ubuntu 24.04 LTS 将支持 Ubuntu 桌面、Ubuntu 服务器和 Ubuntu Core 5 年&#xff0c;直到 2029 年 4 月。 本文将介绍如何将当前 Ubuntu 22.04 系统升级到最新 Ubuntu 24.04 LTS版本。 备份个人数据 以防万一&#xff0c;把系统中的重要数据自己备份一下~ 安装配置SSH访问…

宝塔SSL证书申请失败,报错:申请SSL证书错误 module ‘OpenSSL.crypto‘ has no attribute ‘sign‘(已解决)

刚安装宝塔申请SSL就报错&#xff1a;申请SSL证书错误 module OpenSSL.crypto has no attribute sign 面板、插件版本&#xff1a;9.2.0 系统版本&#xff1a;Alibaba Cloud Linux 3.2104 LTS 问题&#xff1a;申请SSL证书错误 module OpenSSL.crypto has no attribute sign…

<mutex>注释 12:重新思考与猜测、补充锁的睡眠与唤醒机制,结合 linux0.11 操作系统代码的辅助(下)

&#xff08;60&#xff09;继续分析&#xff0c;为什么 timed_mutex 可以拥有准时的等待时间&#xff1a; 逐步测试&#xff1a; 以及&#xff1a; 以及&#xff1a; 以及&#xff1a; 上面的例子里之所以这么编写。无论 timed_mutex 里的定时等待函数&#xff0c;还是 条件…

【MySQL】InnoDB引擎中的Compact行格式

目录 1、背景2、数据示例3、Compact解释【1】组成【2】头部信息【3】隐藏列【4】数据列 4、总结 1、背景 mysql中数据存储是存储引擎干的事&#xff0c;InnoDB存储引擎以页为单位存储数据&#xff0c;每个页的大小为16KB&#xff0c;平时我们操作数据库都是以行为单位进行增删…

Kylin麒麟操作系统 | 网络链路聚合配置(team和bond)

目录 一、理论储备1. 链路聚合 二、任务实施1. team模式2. bond模式 一、理论储备 1. 链路聚合 链路聚合是指将多个物理端口捆绑在一起&#xff0c;形成一个逻辑端口&#xff0c;以实现出/入流量在各成员端口中的负载分担。链路聚合在增加链路带宽、实现链路传输弹性和冗余等…

Linux中用户和用户管理详解

文章目录 Linux中用户和用户管理详解一、引言二、用户和用户组的基本概念1、用户账户文件2、用户组管理 三、用户管理操作1、添加用户2、设置用户密码3、删除用户 四、用户组操作1、创建用户组2、将用户添加到用户组 五、总结 Linux中用户和用户管理详解 一、引言 在Linux系统…

多进程并发跑程序:pytest-xdist记录

多进程并发跑程序&#xff1a;pytest-xdist记录 pytest -s E:\testXdist\test_dandu.py pytest -s testXdist\test_dandu.py pytest -s &#xff1a;是按用例顺序依次跑用例 pytest -vs -n auto E:\testXdist\test_dandu.py pytest -vs -n auto&#xff0c;auto表示以全部进程…

笔记--(Shell脚本04)、循环语句与函数

循环语句 1、for语句的结构 for 变量名 in 取值列表 do 命令序列 done for 收件人 in 邮件地址列表 do 发送邮件 done for i in {1..10} doecho $i done[rootlocalhost shell]# ./ce7.sh 1 2 ...... 9 101 #!/bin/bash2 3 for i in seq 1 104 do5 echo $i6 done[rootlocal…

用.Net Core框架创建一个Web API接口服务器

我们选择一个Web Api类型的项目创建一个解决方案为解决方案取一个名称我们这里选择的是。Net 8.0框架 注意&#xff0c;需要勾选的项。 我们找到appsetting.json配置文件 appsettings.json配置文件内容如下 {"Logging": {"LogLevel": {"Default&quo…

go引用包生成不了vendor的问题

比如我要引入github.com/jinzhu/gorm这个包. 1. 首先获取包 go get github.com/jinzhu/gorm 这时go.mod文件中也有这个包依赖信息了. 2. 然后构建vendor go mod vendor 结果发现vendor目录下没有生成对应的包, 而且modules.txt也注释掉这个包了. 原因是没有其进行引用, go…

36. Three.js案例-创建带光照和阴影的球体与平面

36. Three.js案例-创建带光照和阴影的球体与平面 实现效果 知识点 Three.js基础 WebGLRenderer WebGLRenderer 是Three.js中最常用的渲染器&#xff0c;用于将场景渲染到网页上。 构造器 new THREE.WebGLRenderer(parameters)参数类型描述parametersobject可选参数&#…

el-table表格嵌套子表格:展开所有内容;对当前展开行内容修改,当前行默认展开;

原文1 原文2 原文3 一、如果全部展开 default-expand-all"true" 二、设置有数据的行打开下拉 1、父table需要绑定两个属性expand-row-key和row-key <el-table:data"tableData":expand-row-keys"expends" //expends是数组&#xff0c;设置…

零基础微信小程序开发——小程序的宿主环境(保姆级教程+超详细)

&#x1f3a5; 作者简介&#xff1a; CSDN\阿里云\腾讯云\华为云开发社区优质创作者&#xff0c;专注分享大数据、Python、数据库、人工智能等领域的优质内容 &#x1f338;个人主页&#xff1a; 长风清留杨的博客 &#x1f343;形式准则&#xff1a; 无论成就大小&#xff0c;…

NOTEBOOK_11 汽车电子设备分享(工作经验)

汽车电子设备分享 摘要 本文主要列出汽车电子应用的一些实验设备和生产设备&#xff0c;部分会给予一定推荐。目录 摘要一、通用工具&#xff1a;二、测量与测试仪器2.1测量仪器2.2无线通讯测量仪器2.3元器件测试仪2.4安规测试仪2.5电源供应器2.6电磁兼容测试设备2.7可靠性环境…

linux centos 7 安装 mongodb7

MongoDB 是一个基于文档的 NoSQL 数据库。 MongoDB 是一个文档型数据库&#xff0c;数据以类似 JSON 的文档形式存储。 MongoDB 的设计理念是为了应对大数据量、高性能和灵活性需求。 MongoDB使用集合&#xff08;Collections&#xff09;来组织文档&#xff08;Documents&a…

opengl 着色器 (四)最终章收尾

颜色属性 在前面的教程中&#xff0c;我们了解了如何填充VBO、配置顶点属性指针以及如何把它们都储存到一个VAO里。这次&#xff0c;我们同样打算把颜色数据加进顶点数据中。我们将把颜色数据添加3个float值到vertices数组。我们将把三角形的三个角分别指定为红色、绿色和蓝色…

矩阵在资产收益(Asset Returns)中的应用:以资产回报矩阵为例(中英双语)

本文中的例子来源于&#xff1a; 这本书&#xff0c;网址为&#xff1a;https://web.stanford.edu/~boyd/vmls/ 矩阵在资产收益(Asset Returns)中的应用&#xff1a;以资产回报矩阵为例 在量化金融中&#xff0c;矩阵作为一种重要的数学工具&#xff0c;被广泛用于描述和分析…

arXiv-2024 | NavAgent:基于多尺度城市街道视图融合的无人机视觉语言导航

作者&#xff1a;Youzhi Liu, Fanglong Yao*, Yuanchang Yue, Guangluan Xu, Xian Sun, Kun Fu 单位&#xff1a;中国科学院大学电子电气与通信工程学院&#xff0c;中国科学院空天信息创新研究院网络信息系统技术重点实验室 原文链接&#xff1a;NavAgent: Multi-scale Urba…

校园点餐订餐外卖跑腿Java源码

简介&#xff1a; 一个非常实用的校园外卖系统&#xff0c;基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化&#xff0c;提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合&am…

[计算机网络]ARP协议的故事:小明找小红的奇妙旅程

1.ARP小故事 在一个繁忙的网络世界中&#xff0c;每个设备都有自己的身份标识——MAC地址&#xff0c;就像每个人的身份证号码一样。在这个故事里&#xff0c;我们的主角小明&#xff08;主机&#xff09;需要找到小红&#xff08;目标主机&#xff09;的MAC地址&#xff0c;才…