123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- <template>
- <view>
- <sjs src="../wxs/utils.sjs" module="utils" />
- <view class="van-uploader">
- <view class="van-uploader__wrapper">
- <!-- 预览样式 -->
- <view :wx:if="previewImage" :wx:for="lists" wx:key="index" class="van-uploader__preview">
- <image
- :wx:if="item.isImage"
- :mode="imageFit"
- :src="item.url || item.path"
- :alt="item.name || '图片' + index"
- class="van-uploader__preview-image"
- :style="'width: ' + computedPreviewSize + '; height: ' + computedPreviewSize + ';'"
- :data-url="item.url || item.path"
- @tap="doPreviewImage"
- />
- <view wx:else class="van-uploader__file" :style="'width: ' + computedPreviewSize + '; height: ' + computedPreviewSize + ';'">
- <van-icon name="description" class="van-uploader__file-icon" />
- <view class="van-uploader__file-name van-ellipsis">{{ item.name || item.url || item.path }}</view>
- </view>
- <van-icon :wx:if="deletable" name="clear" class="van-uploader__preview-delete" :data-index="index" @tap.native="deleteItem($event, { index })" />
- </view>
- <!-- 上传样式 -->
- <block :wx:if="isInCount">
- <view :wx:if="useSlot" class="van-uploader__slot" @tap="startUpload">
- <slot />
- </view>
- <!-- 默认上传样式 -->
- <view wx:else class="van-uploader__upload" :style="'width: ' + computedPreviewSize + '; height: ' + computedPreviewSize + ';'" @tap="startUpload">
- <van-icon name="plus" class="van-uploader__upload-icon" />
- <text :wx:if="uploadText" class="van-uploader__upload-text">{{ uploadText }}</text>
- </view>
- </block>
- </view>
- </view>
- </view>
- </template>
- <script>
- import { VantComponent } from '../common/component';
- import { isImageFile } from './utils';
- import { addUnit } from '../common/utils';
- export default {
- data() {
- return {
- lists: [],
- computedPreviewSize: '',
- isInCount: true
- };
- },
- props: {
- disabled: Boolean,
- multiple: Boolean,
- uploadText: String,
- useSlot: Boolean,
- useBeforeRead: Boolean,
- previewSize: {
- type: null,
- default: 90
- },
- name: {
- type: [Number, String],
- default: ''
- },
- accept: {
- type: String,
- default: 'image'
- },
- fileList: {
- type: Array,
- default: () => []
- },
- maxSize: {
- type: Number,
- default: Number.MAX_VALUE
- },
- maxCount: {
- type: Number,
- default: 100
- },
- deletable: {
- type: Boolean,
- default: true
- },
- previewImage: {
- type: Boolean,
- default: true
- },
- previewFullImage: {
- type: Boolean,
- default: true
- },
- imageFit: {
- type: String,
- default: 'scaleToFill'
- }
- },
- methods: {
- formatFileList() {
- const { fileList = [], maxCount } = this;
- const lists = fileList.map((item) =>
- Object.assign(Object.assign({}, item), {
- isImage: typeof item.isImage === 'undefined' ? isImageFile(item) : item.isImage
- })
- );
- this.setData({
- lists,
- isInCount: lists.length < maxCount
- });
- },
- setComputedPreviewSize(val) {
- this.setData({
- computedPreviewSize: addUnit(val)
- });
- },
- startUpload() {
- if (this.disabled) {
- return;
- }
- const { name = '', capture = ['album', 'camera'], maxCount = 100, multiple = false, maxSize, accept, lists, useBeforeRead = false } = this;
- let chooseFile = null;
- const newMaxCount = maxCount - lists.length;
- if (accept === 'image') {
- chooseFile = new Promise((resolve, reject) => {
- wx.chooseImage({
- count: multiple ? (newMaxCount > 9 ? 9 : newMaxCount) : 1,
- sourceType: capture,
- success: resolve,
- fail: reject
- });
- });
- } else {
- chooseFile = new Promise((resolve, reject) => {
- wx.chooseMessageFile({
- count: multiple ? newMaxCount : 1,
- type: 'file',
- success: resolve,
- fail: reject
- });
- });
- }
- chooseFile.then((res) => {
- const file = multiple ? res.tempFiles : res.tempFiles[0];
- if (file instanceof Array) {
- const sizeEnable = file.every((item) => item.size <= maxSize);
- if (!sizeEnable) {
- this.$emit('oversize', {
- name
- });
- return;
- }
- } else if (file.size > maxSize) {
- this.$emit('oversize', {
- name
- });
- return;
- }
- if (useBeforeRead) {
- this.$emit('before-read', {
- file,
- name,
- callback: (result) => {
- if (result) {
- this.$emit('after-read', {
- file,
- name
- });
- }
- }
- });
- } else {
- this.$emit('after-read', {
- file,
- name
- });
- }
- });
- },
- deleteItem(event, _dataset) {
- /* ---处理dataset begin--- */
- this.handleDataset(event, _dataset);
- /* ---处理dataset end--- */
- const { index } = event.currentTarget.dataset;
- this.$emit('delete', {
- index,
- name: this.name
- });
- },
- doPreviewImage(event) {
- if (!this.previewFullImage) {
- return;
- }
- const curUrl = event.currentTarget.dataset.url;
- const images = this.lists.filter((item) => item.isImage).map((item) => item.url || item.path);
- this.$emit('click-preview', {
- url: curUrl,
- name: this.name
- });
- wx.previewImage({
- urls: images,
- current: curUrl,
- fail() {
- wx.showToast({
- title: '预览图片失败',
- icon: 'none'
- });
- }
- });
- }
- },
- watch: {
- previewSize: {
- handler: function (val) {
- this.setData({
- computedPreviewSize: addUnit(val)
- });
- },
- immediate: true
- },
- fileList: {
- handler: function () {
- const { fileList = [], maxCount } = this;
- const lists = fileList.map((item) =>
- Object.assign(Object.assign({}, item), {
- isImage: typeof item.isImage === 'undefined' ? isImageFile(item) : item.isImage
- })
- );
- this.setData({
- lists,
- isInCount: lists.length < maxCount
- });
- },
- immediate: true,
- deep: true
- }
- }
- };
- </script>
- <style>
- @import '../common/index.ttss';
- .van-uploader {
- position: relative;
- display: inline-block;
- }
- .van-uploader__wrapper {
- display: -webkit-flex;
- display: flex;
- -webkit-flex-wrap: wrap;
- flex-wrap: wrap;
- }
- .van-uploader__upload {
- position: relative;
- display: -webkit-flex;
- display: flex;
- -webkit-flex-direction: column;
- flex-direction: column;
- -webkit-align-items: center;
- align-items: center;
- -webkit-justify-content: center;
- justify-content: center;
- box-sizing: border-box;
- width: 80px;
- height: 80px;
- margin: 0 8px 8px 0;
- background-color: #fff;
- border: 1px dashed #ebedf0;
- border-radius: 4px;
- }
- .van-uploader__upload-icon {
- display: inline-block;
- width: 24px;
- height: 24px;
- color: #969799;
- font-size: 24px;
- }
- .van-uploader__upload-text {
- margin-top: 8px;
- color: #969799;
- font-size: 12px;
- }
- .van-uploader__preview {
- position: relative;
- margin: 0 8px 8px 0;
- }
- .van-uploader__preview-image {
- display: block;
- width: 80px;
- height: 80px;
- border-radius: 4px;
- }
- .van-uploader__preview-delete {
- position: absolute;
- top: -8px;
- right: -8px;
- color: #969799;
- font-size: 18px;
- background-color: #fff;
- border-radius: 100%;
- }
- .van-uploader__file {
- display: -webkit-flex;
- display: flex;
- -webkit-flex-direction: column;
- flex-direction: column;
- -webkit-align-items: center;
- align-items: center;
- -webkit-justify-content: center;
- justify-content: center;
- width: 80px;
- height: 80px;
- background-color: #f7f8fa;
- border-radius: 4px;
- }
- .van-uploader__file-icon {
- display: inline-block;
- width: 20px;
- height: 20px;
- color: #646566;
- font-size: 20px;
- }
- .van-uploader__file-name {
- box-sizing: border-box;
- width: 100%;
- margin-top: 8px;
- padding: 0 5px;
- color: #646566;
- font-size: 12px;
- text-align: center;
- }
- </style>
|