0


基于vue element-ui 封装上传图片组件 功能:上传,删除,预览,上传图片水印,拖拽排序,上传进度条等

学习目标:

我们在开发后台时肯定避免不了上传图片的功能

例如:

  • 上传图片回显
  • 上传完成 : 预览查看 , 删除等
  • 如果是图片列表,还可能让你拖动图片排序
  • 有的后台项目可能要给图片添加水印,添加标记
  • 有的后台可能要炫酷一点 添加进度条功能

学习内容:

现在我们要完成上面的一系列功能,这里我用到了vue element ui的弹窗组件,预览图片组件,还有axios,axios是二次封装的,你们可以自行根据你们的项目来封装

效果演示:

基于vue element-ui 封装上传图片组件


上传图片组件代码

  1. <!--
  2. * @Author: 等风来 3064436257@qq.com
  3. * @Date: 2022-11-10 08:42:34
  4. * @LastEditTime: 2023-02-17 11:07:40
  5. -->
  6. <template>
  7. <div class="UploadImg_list">
  8. <transition-group name="tag" class="UploadImg_list">
  9. <div
  10. v-for="(item, index) in imgList"
  11. :key="item.id"
  12. :draggable="true"
  13. class="UploadImg_item"
  14. @dragstart="dragstart(index)"
  15. @dragenter="dragenter($event, index)"
  16. @dragover="dragover($event, index)"
  17. >
  18. <div class="item_cont">
  19. <img :src="item.url" alt="" />
  20. <div class="img_mask">
  21. <i
  22. class="el-icon-zoom-in"
  23. style="margin-right: 10px"
  24. @click="lookImg(item)"
  25. ></i>
  26. <i class="el-icon-delete" @click="delImg(item)"></i>
  27. </div>
  28. </div>
  29. </div>
  30. <div
  31. v-if="imgList.length < form.total"
  32. :key="-999999999"
  33. class="UploadImg_input"
  34. @click="showUploadImg"
  35. >
  36. <i class="el-icon-plus"></i>
  37. </div>
  38. </transition-group>
  39. <el-image
  40. ref="preview"
  41. class="nones"
  42. :src="url"
  43. :preview-src-list="srcList"
  44. ></el-image>
  45. <div v-show="is_Ball" class="my_mask">
  46. <Ball :percent="ballNum" :run-num="runNum"></Ball>
  47. </div>
  48. <!-- 对话框 -->
  49. <div class="UploadImg">
  50. <el-dialog
  51. title="上传图片配置"
  52. :close-on-click-modal="false"
  53. :visible.sync="isUploadImg"
  54. width="500px"
  55. :append-to-body="true"
  56. >
  57. <div>
  58. <el-form ref="form" :model="form" label-width="70px">
  59. <el-form-item v-if="form.total" label="图片总数">
  60. <el-input-number
  61. v-model="form.total"
  62. :min="1"
  63. :max="maxNum"
  64. :disabled="maxNumHide"
  65. label="图片总数"
  66. style="width: 100%"
  67. ></el-input-number>
  68. </el-form-item>
  69. <el-form-item label="图片尺寸">
  70. <el-switch v-model="form.size"></el-switch>
  71. </el-form-item>
  72. <el-form-item v-if="form.size" label="图片宽度">
  73. <el-input-number
  74. v-model="form.width"
  75. :min="50"
  76. label="图片宽度"
  77. style="width: 100%"
  78. ></el-input-number>
  79. </el-form-item>
  80. <el-form-item v-if="form.size" label="图片高度">
  81. <el-input-number
  82. v-model="form.height"
  83. :min="50"
  84. label="图片高度"
  85. style="width: 100%"
  86. ></el-input-number>
  87. </el-form-item>
  88. <el-form-item label="图片类型">
  89. <el-checkbox-group v-model="form.imgTypes">
  90. <el-checkbox v-for="item in imgType" :key="item" :label="item">
  91. {{ item }}
  92. </el-checkbox>
  93. </el-checkbox-group>
  94. </el-form-item>
  95. <el-form-item label="是否水印">
  96. <el-switch v-model="form.Watermark"></el-switch>
  97. </el-form-item>
  98. <el-form-item v-if="form.Watermark" label="水印文字">
  99. <el-input
  100. v-model="form.title"
  101. maxlength="6"
  102. show-word-limit
  103. ></el-input>
  104. </el-form-item>
  105. <el-form-item label="是否多选">
  106. <div>
  107. <el-switch v-model="form.Multiple"></el-switch>
  108. <span v-if="!form.Multiple" style="margin-left: 10px">
  109. 当前进度条功能开启
  110. </span>
  111. <span v-else style="margin-left: 10px">当前进度条功能关闭</span>
  112. </div>
  113. <p class="MultipleTitle">
  114. 单选时开启进度条功能,多选则关闭进度条功能
  115. </p>
  116. </el-form-item>
  117. </el-form>
  118. </div>
  119. <span slot="footer" class="dialog-footer UploadImg_btn">
  120. <el-button @click="isUploadImg = false">取 消</el-button>
  121. <el-button type="primary">
  122. 选择图片
  123. <input
  124. v-if="form.Multiple"
  125. type="file"
  126. accept="image/*"
  127. multiple="multiple"
  128. @change="addImgs"
  129. />
  130. <input v-else type="file" accept="image/*" @change="addImgs" />
  131. </el-button>
  132. </span>
  133. </el-dialog>
  134. </div>
  135. </div>
  136. </template>
  137. <script>
  138. import Ball from '../../components/Ball/index.vue'
  139. export default {
  140. name: 'UploadImg',
  141. components: { Ball: Ball },
  142. props: {
  143. //图片数据
  144. lists: {
  145. type: Array,
  146. default() {
  147. return []
  148. },
  149. },
  150. //图片限制个数
  151. maxNum: {
  152. type: Number,
  153. default() {
  154. return 5
  155. },
  156. },
  157. //图片限制是否能调整
  158. maxNumHide: {
  159. type: Boolean,
  160. default() {
  161. return false
  162. },
  163. },
  164. //图片类型限制
  165. imgType: {
  166. type: Array,
  167. default() {
  168. // return ['image/jpeg', 'image/png']
  169. return ['image/jpeg']
  170. },
  171. },
  172. //是否限制图片尺寸
  173. isSize: {
  174. type: Boolean,
  175. default() {
  176. return false
  177. },
  178. },
  179. //限制图片尺寸大小
  180. imgSize: {
  181. type: Array,
  182. default() {
  183. return [400, 400]
  184. },
  185. },
  186. //是否水印
  187. isWatermark: {
  188. type: Boolean,
  189. default() {
  190. return false
  191. },
  192. },
  193. //水印文字
  194. watermarkTitle: {
  195. type: String,
  196. default() {
  197. return '默认水印'
  198. },
  199. },
  200. // 1 选择图片是否多选
  201. // 2 false 时开启进度条功能
  202. isMultiple: {
  203. type: Boolean,
  204. default() {
  205. return true
  206. },
  207. },
  208. },
  209. data() {
  210. return {
  211. imgList: this.lists,
  212. url: '',
  213. srcList: [],
  214. // 源对象的下标
  215. dragIndex: '',
  216. // 目标对象的下标
  217. enterIndex: '',
  218. timeout: null,
  219. isUploadImg: false,
  220. form: {
  221. total: this.maxNum,
  222. size: this.isSize,
  223. width: this.imgSize[0],
  224. height: this.imgSize[1],
  225. title: this.watermarkTitle,
  226. Watermark: this.isWatermark,
  227. Multiple: this.isMultiple,
  228. imgTypes: [...this.imgType],
  229. },
  230. ballNum: 0,
  231. is_Ball: false,
  232. runNum: 0,
  233. }
  234. },
  235. watch: {
  236. maxNum: {
  237. handler: function (a, b) {
  238. this.form.total = a
  239. },
  240. // deep: true,
  241. },
  242. },
  243. methods: {
  244. // 显示上传图片对话框
  245. showUploadImg() {
  246. this.isUploadImg = true
  247. },
  248. // 上传图片前置验证
  249. addImgBefore(fileArr) {
  250. return new Promise((resolve, reject) => {
  251. let isOk = true
  252. // 上传图片数量限制
  253. if (this.imgList.length + fileArr.length > this.form.total) {
  254. if (this.imgList.length > this.form.total) {
  255. const del_nums = this.imgList.length - this.form.total
  256. this.imgList.splice(this.form.total, del_nums)
  257. }
  258. this.$message.error(`最多上传 ${this.form.total} 张图片!`)
  259. return resolve(false)
  260. }
  261. // 上传图片类型限制
  262. if (this.form.imgTypes.length > 0) {
  263. fileArr.forEach((item) => {
  264. if (this.form.imgTypes.indexOf(item.type) < 0) {
  265. isOk = false
  266. }
  267. })
  268. if (!isOk) {
  269. this.$message.error(
  270. `上传图片中类型不符合 ${this.form.imgTypes.toString()} 类型 !`
  271. )
  272. return resolve(false)
  273. }
  274. }
  275. //上传图片判断尺寸
  276. if (this.form.size) {
  277. fileArr.forEach((fileItem) => {
  278. this.limitFileWH(
  279. this.form.width,
  280. this.form.height,
  281. fileItem
  282. ).then((res) => {
  283. if (res) {
  284. return resolve(true)
  285. } else {
  286. return resolve(false)
  287. }
  288. })
  289. })
  290. } else {
  291. resolve(true)
  292. }
  293. })
  294. },
  295. // 上传图片
  296. async addImgs(e) {
  297. let file = [...e.target.files]
  298. let isOk = await this.addImgBefore(file)
  299. // 前置验证
  300. if (!isOk) {
  301. return
  302. }
  303. if (file.length > 1) {
  304. this.runNum = 0.5
  305. } else {
  306. this.runNum = 3
  307. }
  308. // 是否开启进度条
  309. if (!this.form.Multiple && file.length > 0) {
  310. this.is_Ball = true
  311. }
  312. this.ballNum = 0
  313. if (this.form.Watermark) {
  314. // 有水印的
  315. file.forEach(async (item) => {
  316. this.getBase64(item).then((res) => {
  317. this.imgToCanvas(res).then((data) => {
  318. this.imgList.push({
  319. id: new Date().valueOf(),
  320. url: data,
  321. })
  322. this.ballNum = 0
  323. this.is_Ball = false
  324. })
  325. })
  326. })
  327. } else {
  328. // 不加水印的
  329. file.forEach(async (item) => {
  330. const res = await this.$http.post(
  331. 'admin/api/upload',
  332. {
  333. file: item,
  334. disk: 'public',
  335. folder: 'richText',
  336. },
  337. {
  338. headers: {
  339. 'Content-Type': 'multipart/form-data',
  340. },
  341. onUploadProgress: (progressEvent) => {
  342. let persent =
  343. ((progressEvent.loaded / progressEvent.total) * 100) | 0 //上传进度百分比
  344. this.ballNum = persent
  345. },
  346. }
  347. )
  348. if (res.code == 200000) {
  349. this.imgList.push({
  350. id: new Date().valueOf(),
  351. url: res.data.url,
  352. })
  353. this.ballNum = 0
  354. this.is_Ball = false
  355. this.$message.success(res.message)
  356. } else {
  357. this.$message.error(res.message)
  358. this.is_Ball = false
  359. return
  360. }
  361. })
  362. }
  363. this.isUploadImg = false
  364. },
  365. // 判断图片是否正方形
  366. limitFileWH(E_width, E_height, file) {
  367. const _this = this
  368. let imgWidth = ''
  369. let imgHight = ''
  370. const isSize = new Promise(function (resolve, reject) {
  371. const width = E_width
  372. const height = E_height
  373. const _URL = window.URL || window.webkitURL
  374. const img = new Image()
  375. img.onload = function () {
  376. imgWidth = img.width
  377. imgHight = img.height
  378. const valid = img.width === width && img.height === height
  379. valid ? resolve() : reject()
  380. }
  381. img.src = _URL.createObjectURL(file)
  382. }).then(
  383. () => {
  384. return true
  385. },
  386. () => {
  387. _this.$message.warning({
  388. message:
  389. '上传图片的尺寸应为' +
  390. E_width +
  391. '*' +
  392. E_height +
  393. ',当前上传图片的尺寸为:' +
  394. imgWidth +
  395. '*' +
  396. imgHight,
  397. btn: false,
  398. })
  399. return false
  400. }
  401. )
  402. return isSize
  403. },
  404. // 转64
  405. getBase64(file) {
  406. return new Promise(function (resolve, reject) {
  407. const reader = new FileReader()
  408. let imgResult = ''
  409. reader.readAsDataURL(file)
  410. reader.onload = function () {
  411. imgResult = reader.result
  412. }
  413. reader.onerror = function (error) {
  414. reject(error)
  415. }
  416. reader.onloadend = function () {
  417. resolve(imgResult)
  418. }
  419. })
  420. },
  421. // 64转文件
  422. dataURLtoFile(dataurl, filename) {
  423. var arr = dataurl.split(',')
  424. var mime1 = arr[0].split(';')
  425. var mime2 = mime1[0].split(':')[1]
  426. var bstr = atob(arr[1])
  427. var n = bstr.length
  428. var u8arr = new Uint8Array(n)
  429. while (n--) {
  430. u8arr[n] = bstr.charCodeAt(n)
  431. }
  432. return new File([u8arr], 'names', { type: mime2 })
  433. },
  434. // 画水印 并上传
  435. imgToCanvas(imgSrc) {
  436. return new Promise((resolve, reject) => {
  437. const _this = this
  438. var image = document.createElement('img')
  439. image.setAttribute('src', imgSrc)
  440. const img_Src = ''
  441. // 创造画布
  442. image.onload = async () => {
  443. var canvas = document.createElement('canvas')
  444. canvas.width = image.width
  445. canvas.height = image.height
  446. var cxt = canvas.getContext('2d')
  447. // 将图片绘制上去
  448. cxt.drawImage(image, 0, 0) // 第一个参数是图片(不能是src 否则会报错,是src的话需要先new Image(),具体看上个getImgWay方法) 第二、三是图片在画布位置 第四、五是将图片绘制成多大宽高(不写四五就是原图宽高)
  449. // 给画布上添加水印文字
  450. cxt.font = '24px Georgia'
  451. cxt.textAlign = 'left'
  452. cxt.textBaseline = 'top'
  453. cxt.fillStyle = '#fff'
  454. // cxt.rotate(-10 * Math.PI / 180)
  455. cxt.rotate((Math.PI / 180) * 5)
  456. if (image.height > image.width) {
  457. for (let i = 0; i < image.height / 200; i++) {
  458. for (let j = 0; j < image.width / 50; j++) {
  459. cxt.fillText(this.form.title, i * 300, j * 100, image.width)
  460. }
  461. }
  462. } else {
  463. for (let i = 0; i < image.width / 200; i++) {
  464. for (let j = 0; j < image.height; j++) {
  465. cxt.fillText(this.form.title, i * 300, j * 100, image.width)
  466. }
  467. }
  468. }
  469. var dataurl = canvas.toDataURL('image/png')
  470. // 转好的文件 可根据你们的后端接口自行上传
  471. const file = this.dataURLtoFile(dataurl)
  472. // const formdata = new FormData()
  473. // formdata.append('file', file)
  474. const res = await this.$http.post(
  475. 'admin/api/upload',
  476. {
  477. file: file,
  478. disk: 'public',
  479. folder: 'richText',
  480. },
  481. {
  482. headers: {
  483. 'Content-Type': 'multipart/form-data',
  484. },
  485. onUploadProgress: (progressEvent) => {
  486. let persent =
  487. ((progressEvent.loaded / progressEvent.total) * 100) | 0 //上传进度百分比
  488. this.ballNum = persent
  489. },
  490. }
  491. )
  492. // const { data: res } = await $http.post('api/upload', formdata)
  493. if (res.code != 200000) {
  494. this.$message.error(res.message)
  495. this.is_Ball = false
  496. resolve(false)
  497. return
  498. }
  499. resolve(res.data.url)
  500. this.$message.success(res.message)
  501. }
  502. })
  503. },
  504. // 删除图片
  505. delImg(item) {
  506. this.$confirm('确定删除该张图片吗?', '提示', {
  507. confirmButtonText: '确定',
  508. cancelButtonText: '取消',
  509. type: 'warning',
  510. })
  511. .then(() => {
  512. let num = -1
  513. this.imgList.forEach((i, index) => {
  514. if (item.url == i.url) {
  515. num = index
  516. }
  517. })
  518. this.imgList.splice(num, 1)
  519. this.$message({
  520. type: 'success',
  521. message: '删除成功!',
  522. })
  523. })
  524. .catch(() => {})
  525. },
  526. // 查看图片
  527. lookImg(item) {
  528. this.srcList = []
  529. this.imgList.forEach((i, index) => {
  530. this.srcList.push(i.url)
  531. })
  532. this.url = item.url
  533. this.$refs.preview.clickHandler()
  534. },
  535. // 拖动排序
  536. dragstart(index) {
  537. this.dragIndex = index
  538. },
  539. // dragenter 和 dragover 事件的默认行为是拒绝接受任何被拖放的元素。
  540. // 因此,我们要在这两个拖放事件中使用`preventDefault`来阻止浏览器的默认行为
  541. dragenter(e, index) {
  542. let indexs = -1
  543. e.preventDefault()
  544. this.enterIndex = index
  545. if (this.timeout !== null) {
  546. clearTimeout(this.timeout)
  547. }
  548. // 拖拽事件的防抖
  549. this.timeout = setTimeout(() => {
  550. if (this.dragIndex !== index) {
  551. const source = this.imgList[this.dragIndex]
  552. this.imgList.splice(this.dragIndex, 1)
  553. this.imgList.splice(index, 0, source)
  554. // 排序变化后目标对象的索引变成源对象的索引
  555. this.dragIndex = index
  556. }
  557. }, 250)
  558. },
  559. dragover(e, index) {
  560. e.preventDefault()
  561. },
  562. },
  563. }
  564. </script>
  565. <style lang="scss" scoped>
  566. .UploadImg_list {
  567. display: flex;
  568. flex-wrap: wrap;
  569. align-items: center;
  570. .UploadImg_item {
  571. transition: transform 0.3s;
  572. box-sizing: border-box;
  573. width: 90px;
  574. height: 90px;
  575. border: 1px solid #c0ccda;
  576. border-radius: 4px;
  577. margin-right: 5px;
  578. padding: 3px;
  579. cursor: move;
  580. margin: 5px 0;
  581. margin-right: 5px;
  582. margin-bottom: 0;
  583. i {
  584. cursor: pointer !important;
  585. }
  586. .item_cont {
  587. position: relative;
  588. box-sizing: border-box;
  589. width: 100%;
  590. height: 100%;
  591. // background-color: red;
  592. border-radius: 2px;
  593. overflow: hidden;
  594. border: 1px solid #c0ccda;
  595. transition: all 0.3s;
  596. img {
  597. transition: all 0.3s;
  598. width: 100%;
  599. height: auto;
  600. }
  601. }
  602. .img_mask {
  603. position: absolute;
  604. left: 0;
  605. top: 0;
  606. width: 100%;
  607. height: 100%;
  608. background-color: rgba(0, 0, 0, 0.4);
  609. display: flex;
  610. align-items: center;
  611. justify-content: center;
  612. color: #fff;
  613. font-size: 20px;
  614. opacity: 0;
  615. }
  616. }
  617. .UploadImg_input {
  618. float: left;
  619. position: relative;
  620. width: 90px;
  621. height: 90px;
  622. border: 1px dashed #c0ccda;
  623. box-sizing: border-box;
  624. border-radius: 4px;
  625. display: flex;
  626. align-items: center;
  627. justify-content: center;
  628. font-size: 20px;
  629. color: #c0ccda;
  630. margin: 5px 0;
  631. margin-bottom: 0;
  632. cursor: pointer !important;
  633. background-color: #fbfdff;
  634. }
  635. .UploadImg_input:hover {
  636. border: 1px dashed #0187fb;
  637. color: #0187fb;
  638. }
  639. .UploadImg_item:hover {
  640. box-shadow: 0 2px 12px 0 rgb(1 133 249 / 60%);
  641. border: 1px solid hsl(208, 99%, 49%);
  642. }
  643. .UploadImg_item:hover img {
  644. transform: scale(1.4);
  645. }
  646. .UploadImg_item:hover .img_mask {
  647. opacity: 1;
  648. }
  649. }
  650. .nones {
  651. display: none;
  652. }
  653. .tag-enter-active {
  654. animation: tagFrames 0.3s linear;
  655. }
  656. .tag-leave-active {
  657. animation: tagFrames 0.3s linear reverse;
  658. }
  659. @keyframes tagFrames {
  660. from {
  661. transform: translateY(-30px);
  662. opacity: 0;
  663. }
  664. to {
  665. opacity: 1;
  666. transform: translateY(0px);
  667. }
  668. }
  669. ::v-deep .UploadImg .el-dialog__title {
  670. font-weight: 700;
  671. }
  672. ::v-deep .UploadImg .el-form-item__label {
  673. font-weight: 700;
  674. }
  675. ::v-deep .UploadImg .el-dialog__body {
  676. border: none;
  677. }
  678. ::v-deep .UploadImg .el-dialog__footer {
  679. border: none;
  680. }
  681. ::v-deep .UploadImg_btn .el-button span {
  682. cursor: pointer !important;
  683. }
  684. .UploadImg_btn .el-button {
  685. width: 90px;
  686. height: 36px;
  687. font-size: 15px;
  688. // line-height: 36px;
  689. position: relative;
  690. cursor: pointer;
  691. input {
  692. position: absolute;
  693. left: 0;
  694. top: 0;
  695. opacity: 0;
  696. width: 100%;
  697. height: 100%;
  698. cursor: pointer !important;
  699. }
  700. }
  701. .my_mask {
  702. position: fixed;
  703. left: 0;
  704. top: 0;
  705. width: 100vw;
  706. height: 100vh;
  707. z-index: 99999999999;
  708. background-color: rgba(0, 0, 0, 0.6);
  709. display: flex;
  710. align-items: center;
  711. justify-content: center;
  712. }
  713. .MultipleTitle {
  714. margin: 0;
  715. color: #f56c6c;
  716. font-size: 14px;
  717. }
  718. </style>

进度条小球组件代码

  1. <template>
  2. <div class="pie-wrap">
  3. <div
  4. :style="{ animationDelay: delay }"
  5. :class="['pie', { 'pie-all': num == 100 }]"
  6. >
  7. <div class="pie-inner">
  8. <p class="percent">{{ num }}%</p>
  9. <p class="txt">上传中...</p>
  10. </div>
  11. </div>
  12. </div>
  13. </template>
  14. <script>
  15. export default {
  16. name: 'Pie',
  17. props: {
  18. percent: {
  19. type: Number,
  20. default: 0,
  21. },
  22. runNum: {
  23. type: Number,
  24. default: 3,
  25. },
  26. },
  27. data() {
  28. return {
  29. num: 0,
  30. }
  31. },
  32. computed: {
  33. delay() {
  34. // 转化为延迟多少秒
  35. return `-${this.num}s`
  36. },
  37. },
  38. watch: {
  39. percent() {
  40. this.startAnimate(this.runNum, this.percent, 5)
  41. },
  42. },
  43. mounted() {
  44. this.startAnimate(this.runNum, this.percent, 5)
  45. },
  46. methods: {
  47. // 匀动动画
  48. startAnimate(step, limit, speed) {
  49. setTimeout(() => {
  50. if (this.num < limit) {
  51. this.num += step
  52. this.startAnimate(step, limit, speed)
  53. } else {
  54. this.num = limit
  55. }
  56. }, speed)
  57. },
  58. },
  59. }
  60. </script>
  61. <style lang="scss" scoped>
  62. .pie-wrap {
  63. width: 100%;
  64. height: 200px;
  65. text-align: center;
  66. .pie {
  67. display: inline-block;
  68. position: relative;
  69. width: 160px;
  70. height: 160px;
  71. margin-top: 40px;
  72. border-radius: 50%;
  73. background: #ccc;
  74. background-image: linear-gradient(to right, transparent 50%, #4479fd 0);
  75. color: transparent;
  76. text-align: center;
  77. }
  78. .pie::before {
  79. content: '';
  80. position: absolute;
  81. top: 0;
  82. left: 50%;
  83. width: 50%;
  84. height: 100%;
  85. border-radius: 0 100% 100% 0 / 50%;
  86. background-color: inherit;
  87. transform-origin: left;
  88. animation: spin 50s linear infinite, bg 100s step-end infinite;
  89. animation-play-state: paused;
  90. animation-delay: inherit;
  91. }
  92. .pie-all {
  93. background: #4479fd;
  94. background-image: none;
  95. }
  96. .pie-all::before {
  97. background-color: #4479fd;
  98. }
  99. @keyframes spin {
  100. to {
  101. transform: rotate(0.5turn);
  102. }
  103. }
  104. @keyframes bg {
  105. 50% {
  106. background: #4479fd;
  107. }
  108. }
  109. .pie-inner {
  110. content: '';
  111. position: absolute;
  112. top: 50%;
  113. left: 50%;
  114. width: 90%;
  115. height: 90%;
  116. border-radius: 50%;
  117. background: #fff;
  118. transform: translate(-50%, -50%);
  119. .percent {
  120. margin-top: 38px;
  121. margin-bottom: 10px;
  122. font-size: 30px;
  123. color: #000;
  124. }
  125. .txt {
  126. font-size: 15px;
  127. color: #666;
  128. margin: 0;
  129. }
  130. }
  131. }
  132. </style>

使用

  1. <template>
  2. <div style="padding: 50px">
  3. <h1>上传图片(查看,删除,预览,拖动排序,水印,单个上传开启进度条)</h1>
  4. <upload-img
  5. :lists="imgList"
  6. :max-num="5"
  7. :img-type="['image/png']"
  8. :is-size="true"
  9. :img-size="[400, 400]"
  10. :is-watermark="true"
  11. :watermark-title="'默认水印'"
  12. :is-multiple="false"
  13. ></upload-img>
  14. <ul>
  15. <li v-for="item in imgList" :key="item.id">
  16. {{ item.id }} -- {{ item.url }}
  17. </li>
  18. </ul>
  19. </div>
  20. </template>
  21. <script>
  22. import uploadImg from '../../components/uploadImg/index.vue'
  23. export default {
  24. components: { 'upload-img': uploadImg },
  25. data() {
  26. return {
  27. imgList: [
  28. {
  29. id: 12,
  30. url: '*****',
  31. },
  32. ],
  33. }
  34. },
  35. }
  36. </script>
  37. <style></style>

注意:

  1. imgList格式一定要注意 id为唯一值 你们可以取当前时间戳 或者 后端返回的图片id

使用

  1. lists是图片数组数据 格式一定要对
  2. max-num-hide 对话框 是否可以修改图片个数
  3. max-num 是最多图片个数 不是选中图片个数
  4. **img-type **是图片类型 是数组 这里我没做处理 直接用的['image/jpeg', 'image/png']这种格式,你们想要修改,请自行修改
  5. is-size 是上传图片前是否判断图片尺寸 根据 img-size 来判断 如果**is-size 为false 那img-size **配置不生效
  6. img-size 是限制图片尺寸 为数组 第一项为图片宽度 第二项为图片高度
  7. is-watermark 是 是否开启水印功能
  8. watermark-title 是水印的文字 如果 i**s-watermark **为fasle啧该配置也无效
  9. is-multiple 是选择图片是否为多选 true 为多选 ,false 为单选 单选是则开启上传进度条功能

这个组件并没有封装上传地址什么的 自行去源码修改 可根据你们后端的接口方式自行上传 很简单 你们肯定会


学习总结:

功能也算挺完善的一个上传图片组件,已知的就差裁剪功能了,如果有bug请联系我,谢谢,随便写着玩的


本文转载自: https://blog.csdn.net/ZL3064436257/article/details/129064651
版权归原作者 等风来吖~ 所有, 如有侵权,请联系我们删除。

“基于vue element-ui 封装上传图片组件 功能:上传,删除,预览,上传图片水印,拖拽排序,上传进度条等”的评论:

还没有评论