|
@@ -1,375 +1,573 @@
|
|
|
<template>
|
|
|
- <view class="imageUploadContainer">
|
|
|
- <view class="imageUploadList">
|
|
|
- <view class="imageItem" v-bind:key="index" v-for="(path, index) in imageListData">
|
|
|
- <image
|
|
|
- :src="path"
|
|
|
- :class="{ dragging: isDragging(index) }"
|
|
|
- draggable="true"
|
|
|
- @tap="previewImage"
|
|
|
- :data-index="index"
|
|
|
- @touchstart="start"
|
|
|
- @touchmove.stop.prevent="move"
|
|
|
- @touchend="stop"
|
|
|
- ></image>
|
|
|
- <view v-if="isShowDel" class="imageDel" @tap="deleteImage" :data-index="index">x</view>
|
|
|
- </view>
|
|
|
- <view v-if="isShowAdd" class="imageUpload" @tap="selectImage">+</view>
|
|
|
- </view>
|
|
|
- <image v-if="showMoveImage" class="moveImage" :style="{ left: posMoveImageLeft, top: posMoveImageTop }" :src="moveImagePath"></image>
|
|
|
+ <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="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAhdEVYdENyZWF0aW9uIFRpbWUAMjAyMDowNzoyNSAyMTo1NDoyOU4TkJAAAADcSURBVFhH7ZfRCoMwDEXLvkjwwVf/bH/emmAyN6glTW9WBjsgwm28OeCLpj81Sil7zvlJ90UiONS/yY5VogsO6XrBg3IEQ5a/s8vRSWUAKmLqp2w5jz5BiNQEGMo3GbloDLtFXJ1IkaEuhAiiY6gEIqB4yqACSk9piIBiKQ8VUFpLviKg3C2rESKgWERCBZSWiEfgIfffYvrrsAgoISJ3Apy3zuTxcSxLQkV6ykNEPKVQkZEyiAiiZKgDIaC4upACSlcn5fM/+WuDCAHF1E/Z/N9AhkMZnPNDPI+UDjPIXgAQIGjNAAAAAElFTkSuQmCC"
|
|
|
+ >
|
|
|
+ </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="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADYAAAA2CAYAAACMRWrdAAABIUlEQVRoQ+2a2w2DMAxFeQzWrsMUbadAsEw3S1CqVgppKwLX8BEOP4iHTXx8uUgWdVXoVhdaV0VhSmf7vr/H8V3XzY6V3P9iD+nYOI5P7/01LMI596AwoZV0TIBXIUWFXhKLFBWYSFGhhxQN6SFFQ5i4ogITKSr0cEVDekjRECauqMBEigq9U7piOk2yAti27SUe5ljlTfPEQ6KZecTvwl4P3ytvOv06R2HDMNzes7+6aRrvnHvtf50L13Lp50rx88zcvNlS3JpwKQ67XyK04nq2nFbk/LqVjin0TvmBNgQ2S4UUDcliHgpMpKjQwxUN6SFFQ5i4ogITKSr0cEVDekjRECauqMAsVoph+hVPtYr5+03p9tbYQ96xrYtT4ootbAJGVxxVTapVswAAAABJRU5ErkJggg=="
|
|
|
+ >
|
|
|
+ </image>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </movable-area>
|
|
|
+ </template>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { uploadurl } from "@/config/api";
|
|
|
-import { get } from "@/config/db";
|
|
|
export default {
|
|
|
- name: "robby-image-upload",
|
|
|
- props: ["value", "enableDel", "enableAdd", "enableDrag", "serverUrl", "formData", "header", "limit", "fileKeyName", "showUploadProgress", "serverUrlDeleteImage"],
|
|
|
+ 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,
|
|
|
+ },
|
|
|
+ // 图片圆角,单位 rpx
|
|
|
+ borderRadius: {
|
|
|
+ type: Number,
|
|
|
+ default: 0,
|
|
|
+ },
|
|
|
+ // 图片周围空白填充,单位 rpx
|
|
|
+ padding: {
|
|
|
+ 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 {
|
|
|
- imageBasePos: {
|
|
|
- x0: -1,
|
|
|
- y0: -1,
|
|
|
- w: -1,
|
|
|
- h: -1,
|
|
|
- },
|
|
|
- showMoveImage: false,
|
|
|
- moveImagePath: "",
|
|
|
- moveLeft: 0,
|
|
|
- moveTop: 0,
|
|
|
- deltaLeft: 0,
|
|
|
- deltaTop: 0,
|
|
|
- dragIndex: null,
|
|
|
- targetImageIndex: null,
|
|
|
imageList: [],
|
|
|
- isDestroyed: false,
|
|
|
+ width: 0,
|
|
|
+ add: {
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ },
|
|
|
+ colsValue: 0,
|
|
|
+ viewWidth: 0,
|
|
|
+ tempItem: null,
|
|
|
+ timer: null,
|
|
|
+ changeStatus: true,
|
|
|
+ preStatus: true,
|
|
|
+ first: true,
|
|
|
};
|
|
|
},
|
|
|
- mounted: function () {
|
|
|
- this.imageList = this.value;
|
|
|
-
|
|
|
- if (this.showUploadProgress === false) {
|
|
|
- this.showUploadProgress = false;
|
|
|
- } else {
|
|
|
- this.showUploadProgress = true;
|
|
|
- }
|
|
|
- },
|
|
|
- destroyed: function () {
|
|
|
- this.isDestroyed = true;
|
|
|
- },
|
|
|
computed: {
|
|
|
- imageListData: function () {
|
|
|
- if (this.value) {
|
|
|
- return this.value;
|
|
|
+ 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;
|
|
|
},
|
|
|
- posMoveImageLeft: function () {
|
|
|
- return this.moveLeft + "px";
|
|
|
+ childWidth() {
|
|
|
+ return this.viewWidth - this.rpx2px(this.padding) * 2 + "px";
|
|
|
},
|
|
|
- posMoveImageTop: function () {
|
|
|
- return this.moveTop + "px";
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ value: {
|
|
|
+ handler(n) {
|
|
|
+ if (!this.first && this.changeStatus) {
|
|
|
+ console.log("watch", n);
|
|
|
+ let flag = false;
|
|
|
+ for (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 = true;
|
|
|
+ this.imageList.splice(i);
|
|
|
+ this.addProperties(this.getSrc(n[i]));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ deep: true,
|
|
|
},
|
|
|
- isShowDel: function () {
|
|
|
- if (this.enableDel === false) {
|
|
|
- return false;
|
|
|
- } else {
|
|
|
- return true;
|
|
|
- }
|
|
|
+ modelValue: {
|
|
|
+ handler(n) {
|
|
|
+ if (!this.first && this.changeStatus) {
|
|
|
+ console.log("watch", n);
|
|
|
+ let flag = false;
|
|
|
+ for (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 = true;
|
|
|
+ this.imageList.splice(i);
|
|
|
+ this.addProperties(this.getSrc(n[i]));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ deep: true,
|
|
|
},
|
|
|
- isShowAdd: function () {
|
|
|
- if (this.enableAdd === false) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- if (this.limit && this.imageList && this.imageList.length >= this.limit) {
|
|
|
- return false;
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.width = uni.getSystemInfoSync().windowWidth;
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ const query = uni.createSelectorQuery().in(this);
|
|
|
+ query.select(".con").boundingClientRect((data) => {
|
|
|
+ this.colsValue = this.cols;
|
|
|
+ this.viewWidth = data.width / this.cols;
|
|
|
+ if (this.imageWidth > 0) {
|
|
|
+ this.viewWidth = this.rpx2px(this.imageWidth);
|
|
|
+ this.colsValue = Math.floor(data.width / this.viewWidth);
|
|
|
}
|
|
|
-
|
|
|
- return true;
|
|
|
- },
|
|
|
- isDragable: function () {
|
|
|
- if (this.enableDrag === false) {
|
|
|
- return false;
|
|
|
- } else {
|
|
|
- return true;
|
|
|
+ let list = this.value;
|
|
|
+ // #ifdef VUE3
|
|
|
+ list = this.modelValue;
|
|
|
+ // #endif
|
|
|
+ for (let item of list) {
|
|
|
+ this.addProperties(this.getSrc(item));
|
|
|
}
|
|
|
- },
|
|
|
+ this.first = false;
|
|
|
+ });
|
|
|
+ query.exec();
|
|
|
},
|
|
|
methods: {
|
|
|
- selectImage: function () {
|
|
|
- var _self = this;
|
|
|
- if (!_self.imageList) {
|
|
|
- _self.imageList = [];
|
|
|
+ getSrc(item) {
|
|
|
+ if (this.keyName !== null) {
|
|
|
+ return item[this.keyName];
|
|
|
}
|
|
|
-
|
|
|
- uni.chooseImage({
|
|
|
- count: _self.limit ? _self.limit - _self.imageList.length : 999,
|
|
|
- success: function (e) {
|
|
|
- var imagePathArr = e.tempFilePaths;
|
|
|
-
|
|
|
- //如果设置了limit限制,在web上count参数无效,这里做判断控制选择的数量是否合要求
|
|
|
- //在非微信小程序里,虽然可以选多张,但选择的结果会被截掉
|
|
|
- //在app里,会自动做选择数量的限制
|
|
|
- if (_self.limit) {
|
|
|
- var availableImageNumber = _self.limit - _self.imageList.length;
|
|
|
- if (availableImageNumber < imagePathArr.length) {
|
|
|
- uni.showToast({
|
|
|
- title: "图片总数限制为" + _self.limit + "张,当前还可以选" + availableImageNumber + "张",
|
|
|
- icon: "none",
|
|
|
- mask: false,
|
|
|
- duration: 2000,
|
|
|
- });
|
|
|
- return;
|
|
|
+ return item;
|
|
|
+ },
|
|
|
+ onChange(e, item) {
|
|
|
+ if (!item) return;
|
|
|
+ item.oldX = e.detail.x;
|
|
|
+ item.oldY = e.detail.y;
|
|
|
+ if (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) return;
|
|
|
+ let y = Math.floor((e.detail.y + this.viewWidth / 2) / this.viewWidth);
|
|
|
+ let index = this.colsValue * y + x;
|
|
|
+ if (item.index != index && index < this.imageList.length) {
|
|
|
+ this.changeStatus = false;
|
|
|
+ for (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 = 0;
|
|
|
+ obj.x = obj.oldX;
|
|
|
+ obj.y = obj.oldY;
|
|
|
+ setTimeout(() => {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ obj.x = obj.absX * this.viewWidth;
|
|
|
+ obj.y = obj.absY * this.viewWidth;
|
|
|
+ });
|
|
|
+ }, 0);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- //检查服务器地址是否设置,设置即表示图片要上传到服务器
|
|
|
- if (_self.serverUrl) {
|
|
|
- uni.showToast({
|
|
|
- title: "上传进度:0/" + imagePathArr.length,
|
|
|
- icon: "none",
|
|
|
- mask: false,
|
|
|
- });
|
|
|
-
|
|
|
- var remoteIndexStart = _self.imageList.length - imagePathArr.length;
|
|
|
- var promiseWorkList = [];
|
|
|
- var keyname = _self.fileKeyName ? _self.fileKeyName : "upload-images";
|
|
|
- var completeImages = 0;
|
|
|
-
|
|
|
- for (let i = 0; i < imagePathArr.length; i++) {
|
|
|
- promiseWorkList.push(
|
|
|
- new Promise((resolve, reject) => {
|
|
|
- let remoteUrlIndex = remoteIndexStart + i;
|
|
|
- uni.uploadFile({
|
|
|
- url: uploadurl,
|
|
|
- header: {
|
|
|
- "Content-Type": "multipart/form-data",
|
|
|
- Authorization: get("access_token"),
|
|
|
- },
|
|
|
- filePath: imagePathArr[i],
|
|
|
- name: "file",
|
|
|
- success: function (res) {
|
|
|
- if (res.statusCode === 200) {
|
|
|
- if (_self.isDestroyed) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- completeImages++;
|
|
|
-
|
|
|
- if (_self.showUploadProgress) {
|
|
|
- uni.showToast({
|
|
|
- title: "上传进度:" + completeImages + "/" + imagePathArr.length,
|
|
|
- icon: "none",
|
|
|
- mask: false,
|
|
|
- duration: 500,
|
|
|
- });
|
|
|
- }
|
|
|
- resolve(res.data);
|
|
|
- } else {
|
|
|
- reject("fail to upload image:" + remoteUrlIndex);
|
|
|
- }
|
|
|
- },
|
|
|
- fail: function (res) {
|
|
|
- reject("fail to upload image:" + remoteUrlIndex);
|
|
|
- },
|
|
|
- });
|
|
|
- })
|
|
|
- );
|
|
|
- }
|
|
|
- Promise.all(promiseWorkList).then((result) => {
|
|
|
- if (_self.isDestroyed) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- for (let i = 0; i < result.length; i++) {
|
|
|
- _self.imageList.push(JSON.parse(result[i]).Data.ResourceUrl);
|
|
|
- }
|
|
|
-
|
|
|
- _self.$emit("add", {
|
|
|
- currentImages: imagePathArr,
|
|
|
- allImages: _self.imageList,
|
|
|
+ item.index = index;
|
|
|
+ item.absX = x;
|
|
|
+ item.absY = y;
|
|
|
+ if (!item.moveEnd) {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ item.x = item.absX * this.viewWidth;
|
|
|
+ item.y = item.absY * this.viewWidth;
|
|
|
});
|
|
|
- _self.$emit("input", _self.imageList);
|
|
|
- });
|
|
|
+ }, 0);
|
|
|
}
|
|
|
- },
|
|
|
+ // console.log('bbb', JSON.parse(JSON.stringify(item)));
|
|
|
+ this.sortList();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ change(obj, i) {
|
|
|
+ obj.index += i;
|
|
|
+ obj.offset = 0;
|
|
|
+ obj.x = obj.oldX;
|
|
|
+ obj.y = obj.oldY;
|
|
|
+ obj.absX = obj.index % this.colsValue;
|
|
|
+ obj.absY = Math.floor(obj.index / this.colsValue);
|
|
|
+ setTimeout(() => {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ obj.x = obj.absX * this.viewWidth;
|
|
|
+ obj.y = obj.absY * this.viewWidth;
|
|
|
+ });
|
|
|
+ }, 0);
|
|
|
+ },
|
|
|
+ touchstart(item) {
|
|
|
+ this.imageList.forEach((v) => {
|
|
|
+ v.zIndex = v.index + 9;
|
|
|
});
|
|
|
+ item.zIndex = 99;
|
|
|
+ item.moveEnd = true;
|
|
|
+ this.tempItem = item;
|
|
|
+ this.timer = setTimeout(() => {
|
|
|
+ item.scale = this.scale;
|
|
|
+ item.opacity = this.opacity;
|
|
|
+ clearTimeout(this.timer);
|
|
|
+ this.timer = null;
|
|
|
+ }, 200);
|
|
|
},
|
|
|
- deleteImage: function (e) {
|
|
|
- var imageIndex = e.currentTarget.dataset.index;
|
|
|
- var deletedImagePath = this.imageList[imageIndex];
|
|
|
- this.imageList.splice(imageIndex, 1);
|
|
|
-
|
|
|
- //检查删除图片的服务器地址是否设置,如果设置则调用API,在服务器端删除该图片
|
|
|
- if (this.serverUrlDeleteImage) {
|
|
|
- uni.request({
|
|
|
- url: this.serverUrlDeleteImage,
|
|
|
- method: "GET",
|
|
|
- data: {
|
|
|
- imagePath: deletedImagePath,
|
|
|
+ touchend(item) {
|
|
|
+ this.previewImage(item);
|
|
|
+ item.scale = 1;
|
|
|
+ item.opacity = 1;
|
|
|
+ item.x = item.oldX;
|
|
|
+ item.y = item.oldY;
|
|
|
+ item.offset = 0;
|
|
|
+ item.moveEnd = false;
|
|
|
+ setTimeout(() => {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ item.x = item.absX * this.viewWidth;
|
|
|
+ item.y = item.absY * this.viewWidth;
|
|
|
+ this.tempItem = null;
|
|
|
+ this.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 = null;
|
|
|
+ const list = this.value || this.modelValue;
|
|
|
+ let srcList = list.map((v) => this.getSrc(v));
|
|
|
+ console.log(list, srcList);
|
|
|
+ uni.previewImage({
|
|
|
+ urls: srcList,
|
|
|
+ current: item.src,
|
|
|
+ success: () => {
|
|
|
+ this.preStatus = false;
|
|
|
+ setTimeout(() => {
|
|
|
+ this.preStatus = true;
|
|
|
+ }, 600);
|
|
|
+ },
|
|
|
+ fail: (e) => {
|
|
|
+ console.log(e);
|
|
|
},
|
|
|
- success: (res) => {},
|
|
|
});
|
|
|
+ } else if (this.timer) {
|
|
|
+ clearTimeout(this.timer);
|
|
|
+ this.timer = null;
|
|
|
}
|
|
|
-
|
|
|
- this.$emit("delete", {
|
|
|
- currentImage: deletedImagePath,
|
|
|
- allImages: this.imageList,
|
|
|
- });
|
|
|
- this.$emit("input", this.imageList);
|
|
|
- },
|
|
|
- previewImage: function (e) {
|
|
|
- var imageIndex = e.currentTarget.dataset.index;
|
|
|
- uni.previewImage({
|
|
|
- current: this.imageList[imageIndex],
|
|
|
- indicator: "number",
|
|
|
- loop: "true",
|
|
|
- urls: this.imageList,
|
|
|
- });
|
|
|
},
|
|
|
- initImageBasePos: function () {
|
|
|
- let paddingRate = 0.024;
|
|
|
- var _self = this;
|
|
|
- //计算图片基准位置
|
|
|
- uni.getSystemInfo({
|
|
|
- success: function (obj) {
|
|
|
- let screenWidth = obj.screenWidth;
|
|
|
- let leftPadding = Math.ceil(paddingRate * screenWidth);
|
|
|
- let imageWidth = Math.ceil((screenWidth - 2 * leftPadding) / 4);
|
|
|
-
|
|
|
- _self.imageBasePos.x0 = leftPadding;
|
|
|
- _self.imageBasePos.w = imageWidth;
|
|
|
- _self.imageBasePos.h = imageWidth;
|
|
|
- },
|
|
|
+ mouseenter() {
|
|
|
+ //#ifdef H5
|
|
|
+ this.imageList.forEach((v) => {
|
|
|
+ v.disable = false;
|
|
|
});
|
|
|
+ //#endif
|
|
|
},
|
|
|
- findOverlapImage: function (posX, posY) {
|
|
|
- let rows = Math.floor((posX - this.imageBasePos.x0) / this.imageBasePos.w);
|
|
|
- let cols = Math.floor((posY - this.imageBasePos.y0) / this.imageBasePos.h);
|
|
|
- let indx = cols * 4 + rows;
|
|
|
- return indx;
|
|
|
- },
|
|
|
- isDragging: function (indx) {
|
|
|
- return this.dragIndex === indx;
|
|
|
- },
|
|
|
- start: function (e) {
|
|
|
- if (!this.isDragable) {
|
|
|
- return;
|
|
|
- }
|
|
|
- this.dragIndex = e.currentTarget.dataset.index;
|
|
|
- this.moveImagePath = this.imageList[this.dragIndex];
|
|
|
- this.showMoveImage = true;
|
|
|
-
|
|
|
- //计算纵向图片基准位置
|
|
|
- if (this.imageBasePos.y0 === -1) {
|
|
|
- this.initImageBasePos();
|
|
|
-
|
|
|
- let basePosY = Math.floor(this.dragIndex / 4) * this.imageBasePos.h;
|
|
|
- let currentImageOffsetTop = e.currentTarget.offsetTop;
|
|
|
- this.imageBasePos.y0 = currentImageOffsetTop - basePosY;
|
|
|
+ mouseleave() {
|
|
|
+ //#ifdef H5
|
|
|
+ if (this.tempItem) {
|
|
|
+ this.imageList.forEach((v) => {
|
|
|
+ v.disable = true;
|
|
|
+ v.zIndex = v.index + 9;
|
|
|
+ v.offset = 0;
|
|
|
+ v.moveEnd = false;
|
|
|
+ if (v.id == this.tempItem.id) {
|
|
|
+ if (this.timer) {
|
|
|
+ clearTimeout(this.timer);
|
|
|
+ this.timer = null;
|
|
|
+ }
|
|
|
+ v.scale = 1;
|
|
|
+ v.opacity = 1;
|
|
|
+ v.x = v.oldX;
|
|
|
+ v.y = v.oldY;
|
|
|
+ this.$nextTick(() => {
|
|
|
+ v.x = v.absX * this.viewWidth;
|
|
|
+ v.y = v.absY * this.viewWidth;
|
|
|
+ this.tempItem = null;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.changeStatus = true;
|
|
|
}
|
|
|
-
|
|
|
- //设置选中图片当前左上角的坐标
|
|
|
- this.moveLeft = e.target.offsetLeft;
|
|
|
- this.moveTop = e.target.offsetTop;
|
|
|
+ //#endif
|
|
|
},
|
|
|
- move: function (e) {
|
|
|
- if (!this.isDragable) {
|
|
|
- return;
|
|
|
- }
|
|
|
- const touch = e.touches[0];
|
|
|
- this.targetImageIndex = this.findOverlapImage(touch.clientX, touch.clientY);
|
|
|
-
|
|
|
- //初始化deltaLeft/deltaTop
|
|
|
- if (this.deltaLeft === 0) {
|
|
|
- this.deltaLeft = touch.clientX - this.moveLeft;
|
|
|
- this.deltaTop = touch.clientY - this.moveTop;
|
|
|
+ addImages() {
|
|
|
+ if (typeof this.addImage === "function") {
|
|
|
+ this.addImage.bind(this.$parent)();
|
|
|
+ } else {
|
|
|
+ let checkNumber = this.number - this.imageList.length;
|
|
|
+ uni.chooseImage({
|
|
|
+ count: checkNumber,
|
|
|
+ sourceType: ["album", "camera"],
|
|
|
+ success: (res) => {
|
|
|
+ let count = checkNumber <= res.tempFilePaths.length ? checkNumber : res.tempFilePaths.length;
|
|
|
+ for (let i = 0; i < count; i++) {
|
|
|
+ this.addProperties(res.tempFilePaths[i]);
|
|
|
+ }
|
|
|
+ this.sortList();
|
|
|
+ },
|
|
|
+ });
|
|
|
}
|
|
|
-
|
|
|
- //设置移动图片位置
|
|
|
- this.moveLeft = touch.clientX - this.deltaLeft;
|
|
|
- this.moveTop = touch.clientY - this.deltaTop;
|
|
|
},
|
|
|
- stop: function (e) {
|
|
|
- if (!this.isDragable) {
|
|
|
- return;
|
|
|
+ delImages(item, index) {
|
|
|
+ if (typeof this.delImage === "function") {
|
|
|
+ this.delImage.bind(this.$parent)(() => {
|
|
|
+ this.delImageHandle(item, index);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.delImageHandle(item, index);
|
|
|
}
|
|
|
- if (this.dragIndex !== null && this.targetImageIndex !== null) {
|
|
|
- if (this.targetImageIndex < 0) {
|
|
|
- this.targetImageIndex = 0;
|
|
|
+ },
|
|
|
+ delImageHandle(item, index) {
|
|
|
+ this.imageList.splice(index, 1);
|
|
|
+ for (let obj of this.imageList) {
|
|
|
+ if (obj.index > item.index) {
|
|
|
+ obj.index -= 1;
|
|
|
+ obj.x = obj.oldX;
|
|
|
+ obj.y = obj.oldY;
|
|
|
+ obj.absX = obj.index % this.colsValue;
|
|
|
+ obj.absY = Math.floor(obj.index / this.colsValue);
|
|
|
+ this.$nextTick(() => {
|
|
|
+ obj.x = obj.absX * this.viewWidth;
|
|
|
+ obj.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 MP
|
|
|
+ this.delImages(item, index);
|
|
|
+ //#endif
|
|
|
+ },
|
|
|
+ sortList() {
|
|
|
+ console.log("sortList");
|
|
|
+ const result = [];
|
|
|
+ let source = this.value;
|
|
|
+ // #ifdef VUE3
|
|
|
+ source = this.modelValue;
|
|
|
+ // #endif
|
|
|
|
|
|
- if (this.targetImageIndex >= this.imageList.length) {
|
|
|
- this.targetImageIndex = this.imageList.length - 1;
|
|
|
- }
|
|
|
- //交换图片
|
|
|
- if (this.dragIndex !== this.targetImageIndex) {
|
|
|
- this.imageList[this.dragIndex] = this.imageList[this.targetImageIndex];
|
|
|
- this.imageList[this.targetImageIndex] = this.moveImagePath;
|
|
|
+ let 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.dragIndex = null;
|
|
|
- this.targetImageIndex = null;
|
|
|
- this.deltaLeft = 0;
|
|
|
- this.deltaTop = 0;
|
|
|
- this.showMoveImage = false;
|
|
|
-
|
|
|
- this.$emit("input", this.imageList);
|
|
|
+ this.$emit("input", result);
|
|
|
+ this.$emit("update:modelValue", result);
|
|
|
+ },
|
|
|
+ addProperties(item) {
|
|
|
+ console.log(item);
|
|
|
+ let absX = this.imageList.length % this.colsValue;
|
|
|
+ let absY = Math.floor(this.imageList.length / this.colsValue);
|
|
|
+ let x = absX * this.viewWidth;
|
|
|
+ let y = absY * this.viewWidth;
|
|
|
+ this.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.length;
|
|
|
+ for (let i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)];
|
|
|
+ uuid.shift();
|
|
|
+ return `u${uuid.join("")}`;
|
|
|
},
|
|
|
},
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
-<style>
|
|
|
-.dragging {
|
|
|
- transform: scale(1.2);
|
|
|
-}
|
|
|
+<style lang="scss" scoped>
|
|
|
+.con {
|
|
|
+ // padding: 30rpx;
|
|
|
|
|
|
-.imageUploadList {
|
|
|
- display: flex;
|
|
|
- flex-wrap: wrap;
|
|
|
-}
|
|
|
+ .area {
|
|
|
+ width: 100%;
|
|
|
|
|
|
-.imageItem,
|
|
|
-.imageUpload {
|
|
|
- width: 160upx;
|
|
|
- height: 160upx;
|
|
|
- margin: 20upx 16upx 20upx 0;
|
|
|
-}
|
|
|
+ .view {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
|
|
|
-.imageDel {
|
|
|
- position: relative;
|
|
|
- left: 120upx;
|
|
|
- bottom: 165upx;
|
|
|
- background-color: rgba(0, 0, 0, 0.5);
|
|
|
- width: 36upx;
|
|
|
- text-align: center;
|
|
|
- line-height: 35upx;
|
|
|
- border-radius: 17upx;
|
|
|
- color: white;
|
|
|
- font-size: 30upx;
|
|
|
- padding-bottom: 2upx;
|
|
|
-}
|
|
|
+ .area-con {
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
|
|
|
-.imageItem image,
|
|
|
-.moveImage {
|
|
|
- width: 160upx;
|
|
|
- height: 160upx;
|
|
|
- border-radius: 8upx;
|
|
|
-}
|
|
|
+ .pre-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
|
|
|
-.imageUpload {
|
|
|
- line-height: 130upx;
|
|
|
- text-align: center;
|
|
|
- font-size: 150upx;
|
|
|
- color: #d9d9d9;
|
|
|
- border: 1px solid #d9d9d9;
|
|
|
- border-radius: 8upx;
|
|
|
-}
|
|
|
+ .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;
|
|
|
|
|
|
-.moveImage {
|
|
|
- position: absolute;
|
|
|
+ .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>
|