兴山县铁路建设协调指挥部网站,珠海网站建设平台,苏州网络推广电话,那个网站做外贸好用户反馈组件实现#xff08;Vue3ElementPlus#xff09;含图片拖拽上传 1. 页面效果1.1 正常展示1.2 鼠标悬浮1.3 表单 2. 代码部分1.2 html、ts1.2 less部分 3. 编码过程遇到的问题 1. 页面效果
1.1 正常展示 1.2 鼠标悬浮 1.3 表单 2. 代码部分
1.2 html、ts
templ… 用户反馈组件实现Vue3ElementPlus含图片拖拽上传 1. 页面效果1.1 正常展示1.2 鼠标悬浮1.3 表单 2. 代码部分1.2 html、ts1.2 less部分 3. 编码过程遇到的问题 1. 页面效果
1.1 正常展示 1.2 鼠标悬浮 1.3 表单 2. 代码部分
1.2 html、ts
templateTeleportdivclassfeedbackmouseenter() (showText true)mouseleave() (showText false)el-popover :visiblevisible triggermanual placementleft :width510div classfeedback-content dragoverhandleDragOver drophandleDropheader classflexstrong反馈中心/strongel-link typeprimary clicktoJiraPage strong我的反馈/strong /el-link/headerhr stylemargin: 10px 0 0 -13px; border-top: 1px solid #dbdbdb /sectionp stylemargin-top: 10px; letter-spacing: 1pxstrong尊敬的用户/strong/pp styleletter-spacing: 1px; text-indent: 4ch感谢您提供诚挚的建议我们将尽快帮您处理解决。/pel-formrefrefForm:modelfromData:rulesfromRuleslabel-positiontopsizelargestylemargin-top: 20pxclassfrom-contentel-form-itemlabel问题类型propissueType:rules{ required: true, message: 请选择问题类型, trigger: [blur, change] }div classcard-listdivv-fort in feedbackType:keyt.name:class[card-item, { active: fromData.issueType t.id }]clickfromData.issueType t.id{{ t.name }}/div/div/el-form-itemel-form-item label概述 propsummaryel-input v-modelfromData.summary/el-input/el-form-itemel-form-item label问题描述 propdescriptionel-input v-modelfromData.description typetextarea :rows4/el-input/el-form-itemel-uploadactionnonelist-typepicture-card:auto-uploadfalse:before-uploadbeforeAvatarUpload:on-exceedhandleExceed:file-listfromData.imgs:on-previewhandlePictureCardPreviewel-iconPlus //el-icontemplate #file{ file }divimg classel-upload-list__item-thumbnail :srcfile.url alt /span classel-upload-list__item-actionsspanclassel-upload-list__item-previewclickhandlePictureCardPreview(file)el-iconzoom-in //el-icon/spanspanv-if!disabledclassel-upload-list__item-deleteclickhandleRemove(file)el-iconDelete //el-icon/span/span/div/template/el-uploaddiv classbtn-rowel-button classbtn-row-left typedefault sizesmall round clickclose取 消/el-buttonel-buttonclassbtn-row-rightsizesmalltypeprimaryround:disabledloadingclickhandleSubmit(refForm)提 交/el-button/div/el-form/sectiondiv classdot/div/divtemplate #referencediv v-ifvisible classline/divdiv v-else classslot-content clickvisible trueChatLineSquare classfeedback-icon /div v-ifshowText classfeedback-text意见反馈 /div/div/template/el-popover/divel-dialog v-modeldialogVisibleimg w-full :srcdialogImageUrl altPreview Image //el-dialog/Teleport
/templatescript setup langtsimport { ElMessage } from element-plus;import type { UploadFile, ElForm, UploadProps } from element-plus;import { ChatLineSquare, Delete, Plus, ZoomIn } from element-plus/icons-vue;import { submitFeedback } from /api/config-center;(() {// 初始化数据准备。。。})();const handleDragOver (event) {event.preventDefault();};const allowedFormats [image/jpeg,image/png,image/gif,image/bmp,image/tiff,image/x-icon,image/svgxml,] as const;const handleDrop (event) {event.preventDefault();const file event.dataTransfer.files[0];if (!allowedFormats.includes(file.type)) {ElMessage.warning(只能上传 JPEG、PNG、GIF、BMP、TIFF、ICO 或 SVG 格式的图片);return;}if (fromData.value.imgs?.length 5) {ElMessage.warning(抱歉最多只能上传5张图片);return;}if (file.size 2 * 1024 * 1024) {ElMessage.warning(图片大小不能超过 2MB);return;}const reader new FileReader();reader.onload () {const image {name: file.name,url: reader.result, // 用于页面回显raw: file, // 将图片的原始文件对象存储到 raw 属性中};fromData.value.imgs.push(image);};reader.readAsDataURL(file);};const showText ref(false);const visible ref(false);type FormInstance InstanceTypetypeof ElForm;const refForm refFormInstance();const feedbackType ref([]);const toJiraPage () {};const loading ref(false);const handleSubmit (formEl: FormInstance | undefined): void {if (!formEl) return;formEl.validate((valid: any) {if (valid) {loading.value true;let fd new FormData();fd.append(issueType, fromData.value.issueType);fd.append(summary, fromData.value.summary);fd.append(description, fromData.value.description);fromData.value.imgs.forEach((v) fd.append(files, v.raw));submitFeedback(fd).then((res: any) {if (res.code 200) {ElMessage.success(反馈成功感谢您的关注);visible.value false;fromData.value {issueType: 0,summary: ,description: ,imgs: [],};} else {ElMessage.error(反馈失败: res.message);}}).catch((e) ElMessage.error(反馈失败: e)).finally(() (loading.value false));} else {return false;}});};const fromData ref({issueType: , // 问题类型summary: , // 概要description: , // 描述imgs: [], // 图片});const close () {visible.value false;showText.value false;refForm.value?.resetFields();fromData.value {issueType: ,summary: ,description: ,imgs: [],};};const dialogImageUrl ref();const dialogVisible ref(false);const disabled ref(false);const handlePictureCardPreview (file: UploadFile) {dialogImageUrl.value file.url!;dialogVisible.value true;};const handleRemove (file: UploadFile) {const index fromData.value.imgs.findIndex((f: any) f.uid file.uid);fromData.value.imgs.splice(index, 1);};const fromRules reactive({// issueType: [{ required: true, message: 请选择问题类型, trigger: blur }],summary: [{ required: true, message: 请输入概要, trigger: blur }],description: [{ required: true, message: 请输入描述, trigger: blur }],});
/script由于我这边项目的需求反馈组件我是和菜单组件放在一起
1.2 less部分
style langless scoped::v-deep(.el-upload-list--picture-card .el-upload-list__item-actions span span) {margin-left: 0.6rem !important;}::v-deep(.el-upload.el-upload--picture-card),::v-deep(li.el-upload-list__item) {width: 70px !important;height: 70px !important;}::v-deep .el-upload-dragger {width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;}.feedback-content {height: 561px;position: relative;header {display: flex;justify-content: space-between;margin: 0 10px;}section {.from-content {height: 454px;// overflow-y: scroll;}.card-list {display: flex;gap: 20px;.card-item {padding: 0 20px;border-radius: 5px;background-color: #f2f3f5;border: 1px solid #dfdfdf;cursor: pointer;width: 100%;height: 35px;line-height: 35px;font-size: 12px;.active {color: #fff;background-color: #4c7cee;}}}.upload {width: 60px;height: 60px;cursor: pointer;border: 1px dashed var(--el-border-color-darker);background-color: #fafafa;:hover {border-color: var(--el-color-primary);color: var(--el-color-primary);}}}.dot {position: absolute;left: -12px;top: 0;width: 4px;height: 21px;border-radius: 5px;background-color: #4c7cee;}}.feedback {position: fixed;top: 50%;right: 0;color: #fff;cursor: pointer;border-radius: 6px;transform: translateY(-50%);background-color: #4c7cea;z-index: 999999999999;.line {width: 7px;height: 100px;border-radius: 6px;background-color: #4c7cea;}.feedback-text {letter-spacing: 0.3em;writing-mode: vertical-lr;text-orientation: upright;}media only screen and (min-width: 1280px) {.slot-content {margin: 6px;.feedback-icon {width: 24px;height: 24px;margin-bottom: 5px;}.feedback-text {font-size: 16px;}}}media only screen and (max-width: 1280px) {.slot-content {margin: 3px;.feedback-icon {width: 19px;height: 19px;margin-bottom: 3px;}.feedback-text {font-size: 13px;}}}}.btn-row {margin: 16px 8px 0;text-align: end;-left {border-color: #4c7cee;color: #4c7cee;}}
/style3. 编码过程遇到的问题
Teleport 是 Vue3 的一个内置组件详细使用请查阅 Vue3官网关于图片拖拽 最初的时候是采用 el-upload 的 drag 属性来实现但是后面有用户提出拖拽上传目标的框太小建议可以把图片拖拽进整个表单最开始时候的想法是在最外层的div加一个拖拽事件但是实现起来有一个问题 el-upload 拖拽事件添加 .stop会造成下方区域无法实现拖拽上传其他区域OK后采取的解决方式是 el-upload 去除拖拽属性全部采用最外层的原生拖拽事件上传 图片的上传 图片需要和文字一起上传最初的时候实在没有想到实现方式后面查了好些文章发现是通过 FormData 实现