> 文章列表 > uni-app 上传图片

uni-app 上传图片

uni-app 上传图片

一、效果图

 二、components/Upload-image.vue

<template><view class="con"><template v-if="viewWidth"><movable-area class="area" :style="{ height: areaHeight }" @mouseenter="mouseenter" @mouseleave="mouseleave"><movable-view v-for="(item, index) in imageList" :key="item.id" class="view" direction="all" :y="item.y":x="item.x" :damping="40" :disabled="item.disable" @change="onChange($event, item)"@touchstart="touchstart(item)" @mousedown="touchstart(item)" @touchend="touchend(item)"@mouseup="touchend(item)" :style="{width: viewWidth + 'px', height: viewWidth + 'px', 'z-index': item.zIndex, opacity: item.opacity }"><view class="area-con" :style="{width: childWidth, height: childWidth, borderRadius: borderRadius + 'rpx',transform: 'scale(' + item.scale + ')' }"><image class="pre-image" :src="item.src" mode="aspectFill"></image><view class="del-con" @click="delImages(item, index)" @touchstart.stop="delImageMp(item, index)"@touchend.stop="nothing()" @mousedown.stop="nothing()" @mouseup.stop="nothing()"><view class="del-wrap"><image class="del-image"src="https://img0.baidu.com/it/u=2175764168,623834946&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"></image></view></view></view></movable-view><view class="add" v-if="imageList.length < number":style="{ top: add.y, left: add.x, width: viewWidth + 'px', height: viewWidth + 'px' }" @click="addImages"><view class="add-wrap" :style="{ width: childWidth, height: childWidth, borderRadius: borderRadius + 'rpx' }"><image style="width: 54rpx;height: 54rpx;"src="https://bpic.51yuansu.com/pic3/cover/01/01/66/58de765c7abf3_610.jpg"></image></view></view></movable-area></template></view>
</template><script>export default {emits: ['input', 'update:modelValue'],props: {// 排序图片value: {type: Array,default: function() {return []}},// 排序图片modelValue: {type: Array,default: function() {return []}},// 从 list 元素对象中读取的键名keyName: {type: String,default: null},// 选择图片数量限制number: {type: Number,default: 6},// 图片父容器宽度(实际显示的图片宽度为 imageWidth / 1.1 ),单位 rpx// imageWidth > 0 则 cols 无效imageWidth: {type: Number,default: 0},// 图片列数cols: {type: Number,default: 3},// 图片圆角,单位 rpxborderRadius: {type: Number,default: 0},// 图片周围空白填充,单位 rpxpadding: {type: Number,default: 10},// 拖动图片时放大倍数 [0, ∞)scale: {type: Number,default: 1.1},// 拖动图片时不透明度opacity: {type: Number,default: 0.7},// 自定义添加addImage: {type: Function,default: null},// 删除确认delImage: {type: Function,default: null}},data() {return {imageList: [],width: 0,add: {x: 0,y: 0},colsValue: 0,viewWidth: 0,tempItem: null,timer: null,changeStatus: true,preStatus: true,first: true,}},computed: {areaHeight() {let height = ''// return '355px'if (this.imageList.length < this.number) {height = (Math.ceil((this.imageList.length + 1) / this.colsValue) * this.viewWidth).toFixed() + 'px'} else {height = (Math.ceil(this.imageList.length / this.colsValue) * this.viewWidth).toFixed() + 'px'}console.log('areaHeight', height)return height},childWidth() {return this.viewWidth - this.rpx2px(this.padding) * 2 + 'px'},},watch: {value: {handler(n) {if (!this.first && this.changeStatus) {console.log('watch', n)let flag = falsefor (let i = 0; i < n.length; i++) {if (flag) {this.addProperties(this.getSrc(n[i]))continue}if (this.imageList.length === i || this.imageList[i].src !== this.getSrc(n[i])) {flag = truethis.imageList.splice(i)this.addProperties(this.getSrc(n[i]))}}}},deep: true},modelValue: {handler(n) {if (!this.first && this.changeStatus) {console.log('watch', n)let flag = falsefor (let i = 0; i < n.length; i++) {if (flag) {this.addProperties(this.getSrc(n[i]))continue}if (this.imageList.length === i || this.imageList[i].src !== this.getSrc(n[i])) {flag = truethis.imageList.splice(i)this.addProperties(this.getSrc(n[i]))}}}},deep: true},},created() {this.width = uni.getSystemInfoSync().windowWidth},mounted() {const query = uni.createSelectorQuery().in(this)query.select('.con').boundingClientRect(data => {this.colsValue = this.colsthis.viewWidth = data.width / this.colsif (this.imageWidth > 0) {this.viewWidth = this.rpx2px(this.imageWidth)this.colsValue = Math.floor(data.width / this.viewWidth)}let list = this.value// #ifdef VUE3list = this.modelValue// #endiffor (let item of list) {this.addProperties(this.getSrc(item))}this.first = false})query.exec()},methods: {getSrc(item) {if(this.keyName !== null) {return item[this.keyName]}return item},onChange(e, item) {if (!item) returnitem.oldX = e.detail.xitem.oldY = e.detail.yif (e.detail.source === 'touch') {if (item.moveEnd) {item.offset = Math.sqrt(Math.pow(item.oldX - item.absX * this.viewWidth, 2) + Math.pow(item.oldY - item.absY * this.viewWidth, 2))}let x = Math.floor((e.detail.x + this.viewWidth / 2) / this.viewWidth)if (x >= this.colsValue) returnlet y = Math.floor((e.detail.y + this.viewWidth / 2) / this.viewWidth)let index = this.colsValue * y + xif (item.index != index && index < this.imageList.length) {this.changeStatus = falsefor (let obj of this.imageList) {if (item.index > index && obj.index >= index && obj.index < item.index) {this.change(obj, 1)} else if (item.index < index && obj.index <= index && obj.index > item.index) {this.change(obj, -1)} else if (obj.id != item.id) {obj.offset = 0obj.x = obj.oldXobj.y = obj.oldYsetTimeout(() => {this.$nextTick(() => {obj.x = obj.absX * this.viewWidthobj.y = obj.absY * this.viewWidth})}, 0)}}item.index = indexitem.absX = xitem.absY = yif (!item.moveEnd) {setTimeout(() => {this.$nextTick(() => {item.x = item.absX * this.viewWidthitem.y = item.absY * this.viewWidth})}, 0)}// console.log('bbb', JSON.parse(JSON.stringify(item)));this.sortList()}}},change(obj, i) {obj.index += iobj.offset = 0obj.x = obj.oldXobj.y = obj.oldYobj.absX = obj.index % this.colsValueobj.absY = Math.floor(obj.index / this.colsValue)setTimeout(() => {this.$nextTick(() => {obj.x = obj.absX * this.viewWidthobj.y = obj.absY * this.viewWidth})}, 0)},touchstart(item) {this.imageList.forEach(v => {v.zIndex = v.index + 9})item.zIndex = 99item.moveEnd = truethis.tempItem = itemthis.timer = setTimeout(() => {item.scale = this.scaleitem.opacity = this.opacityclearTimeout(this.timer)this.timer = null}, 200)},touchend(item) {this.previewImage(item)item.scale = 1item.opacity = 1item.x = item.oldXitem.y = item.oldYitem.offset = 0item.moveEnd = falsesetTimeout(() => {this.$nextTick(() => {item.x = item.absX * this.viewWidthitem.y = item.absY * this.viewWidththis.tempItem = nullthis.changeStatus = true})// console.log('ccc', JSON.parse(JSON.stringify(item)));}, 0)// console.log('ddd', JSON.parse(JSON.stringify(item)));},previewImage(item) {if (this.timer && this.preStatus && this.changeStatus && item.offset < 28.28) {clearTimeout(this.timer)this.timer = nullconst list = this.value || this.modelValuelet srcList = list.map(v => this.getSrc(v))console.log(list, srcList);uni.previewImage({urls: srcList,current: item.src,success: () => {this.preStatus = falsesetTimeout(() => {this.preStatus = true}, 600)},fail: (e) => {console.log(e);}})} else if (this.timer) {clearTimeout(this.timer)this.timer = null}},mouseenter() {//#ifdef H5this.imageList.forEach(v => {v.disable = false})//#endif},mouseleave() {//#ifdef H5if (this.tempItem) {this.imageList.forEach(v => {v.disable = truev.zIndex = v.index + 9v.offset = 0v.moveEnd = falseif (v.id == this.tempItem.id) {if (this.timer) {clearTimeout(this.timer)this.timer = null}v.scale = 1v.opacity = 1v.x = v.oldXv.y = v.oldYthis.$nextTick(() => {v.x = v.absX * this.viewWidthv.y = v.absY * this.viewWidththis.tempItem = null})}})this.changeStatus = true}//#endif},addImages() {if (typeof this.addImage === 'function') {this.addImage.bind(this.$parent)()} else {let checkNumber = this.number - this.imageList.lengthuni.chooseImage({count: checkNumber,sourceType: ['album', 'camera'],success: res => {let count = checkNumber <= res.tempFilePaths.length ? checkNumber : res.tempFilePaths.lengthfor (let i = 0; i < count; i++) {this.addProperties(res.tempFilePaths[i])}this.sortList()}})}},delImages(item, index) {if (typeof this.delImage === 'function') {this.delImage.bind(this.$parent)(() => {this.delImageHandle(item, index)})} else {this.delImageHandle(item, index)}},delImageHandle(item, index) {this.imageList.splice(index, 1)for (let obj of this.imageList) {if (obj.index > item.index) {obj.index -= 1obj.x = obj.oldXobj.y = obj.oldYobj.absX = obj.index % this.colsValueobj.absY = Math.floor(obj.index / this.colsValue)this.$nextTick(() => {obj.x = obj.absX * this.viewWidthobj.y = obj.absY * this.viewWidth})}}this.add.x = (this.imageList.length % this.colsValue) * this.viewWidth + 'px'this.add.y = Math.floor(this.imageList.length / this.colsValue) * this.viewWidth + 'px'this.sortList()},delImageMp(item, index) {//#ifdef MPthis.delImages(item, index)//#endif},sortList() {console.log('sortList');const result = []let source = this.value// #ifdef VUE3source = this.modelValue// #endiflet list = this.imageList.slice()list.sort((a, b) => {return a.index - b.index})for (let s of list) {let item = source.find(d => this.getSrc(d) == s.src)if (item) {result.push(item)} else {if(this.keyName !== null) {result.push({[this.keyName]: s.src})} else {result.push(s.src)}}}this.$emit("input", result);this.$emit("update:modelValue", result);},addProperties(item) {console.log(item);let absX = this.imageList.length % this.colsValuelet absY = Math.floor(this.imageList.length / this.colsValue)let x = absX * this.viewWidthlet y = absY * this.viewWidththis.imageList.push({src: item,x,y,oldX: x,oldY: y,absX,absY,scale: 1,zIndex: 9,opacity: 1,index: this.imageList.length,id: this.guid(16),disable: false,offset: 0,moveEnd: false})this.add.x = (this.imageList.length % this.colsValue) * this.viewWidth + 'px'this.add.y = Math.floor(this.imageList.length / this.colsValue) * this.viewWidth + 'px'},nothing() {},rpx2px(v) {return this.width * v / 750},guid(len = 32) {const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')const uuid = []const radix = chars.lengthfor (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]uuid.shift()return `u${uuid.join('')}`}}}
</script><style lang="scss" scoped>.con {// padding: 30rpx;.area {width: 100%;.view {display: flex;justify-content: center;align-items: center;.area-con {position: relative;overflow: hidden;.pre-image {width: 100%;height: 100%;}.del-con {position: absolute;top: 0rpx;right: 0rpx;padding: 0 0 20rpx 20rpx;.del-wrap {width: 36rpx;height: 36rpx;background-color: rgba(0, 0, 0, 0.4);border-radius: 0 0 0 10rpx;display: flex;justify-content: center;align-items: center;.del-image {width: 20rpx;height: 20rpx;}}}}}.add {position: absolute;display: flex;justify-content: center;align-items: center;.add-wrap {display: flex;justify-content: center;align-items: center;background-color: #eeeeee;}}}}
</style>

三、使用

<template><view class="container"><uploadImage v-model="list"></uploadImage><view style="margin-top: 30rpx;"><u-button type="primary" shape="circle" text="上传图片" @click="uploadImg()"></u-button></view></view>
</template><script>import uploadImage from '@/components/Upload-image.vue'export default {components:{uploadImage},data() {return {list: []}},onLoad(){},methods: {uploadImg() {this.list.forEach((v,i)=>{uni.uploadFile({url: 'https://www.example.com/upload', //仅为示例,非真实的接口地址filePath: v,name: 'file',formData: {'user': 'test'},success: (uploadFileRes) => {console.log(uploadFileRes.data);}});})}}}
</script>
<style>
</style>