123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- import baseComponent from '../helpers/baseComponent'
- import classNames from '../helpers/classNames'
- baseComponent({
- properties: {
- prefixCls: {
- type: String,
- value: 'wux-upload',
- },
- max: {
- type: Number,
- value: -1,
- observer: 'updated',
- },
- count: {
- type: Number,
- value: 9,
- observer: 'updated',
- },
- defaultFileType: {
- type: String,
- value: 'image',
- },
- compressed: {
- type: Boolean,
- value: true,
- },
- maxDuration: {
- type: Number,
- value: 60,
- },
- camera: {
- type: String,
- value: 'back',
- },
- sizeType: {
- type: Array,
- value: ['original', 'compressed'],
- },
- sourceType: {
- type: Array,
- value: ['album', 'camera'],
- },
- url: {
- type: String,
- value: '',
- },
- name: {
- type: String,
- value: 'file',
- },
- header: {
- type: Object,
- value: {},
- },
- formData: {
- type: Object,
- value: {},
- },
- uploaded: {
- type: Boolean,
- value: true,
- },
- disabled: {
- type: Boolean,
- value: false,
- },
- progress: {
- type: Boolean,
- value: false,
- },
- listType: {
- type: String,
- value: 'text',
- },
- defaultFileList: {
- type: Array,
- value: [],
- },
- fileList: {
- type: Array,
- value: [],
- observer(newVal) {
- if (this.data.controlled) {
- this.setData({
- uploadFileList: newVal,
- })
- }
- },
- },
- controlled: {
- type: Boolean,
- value: false,
- },
- showUploadList: {
- type: Boolean,
- value: true,
- },
- showRemoveIcon: {
- type: Boolean,
- value: true,
- },
- },
- data: {
- uploadMax: -1,
- uploadCount: 9,
- uploadFileList: [],
- isVideo: false,
- },
- computed: {
- classes() {
- const { prefixCls, disabled, listType } = this.data
- const wrap = classNames(prefixCls, {
- [`${prefixCls}--${listType}`]: listType,
- [`${prefixCls}--disabled`]: disabled,
- })
- const files = `${prefixCls}__files`
- const file = `${prefixCls}__file`
- const thumb = `${prefixCls}__thumb`
- const remove = `${prefixCls}__remove`
- const select = `${prefixCls}__select`
- const button = `${prefixCls}__button`
- return {
- wrap,
- files,
- file,
- thumb,
- remove,
- select,
- button,
- }
- },
- },
- methods: {
- /**
- * 计算最多可以选择的图片张数
- */
- updated() {
- const { count, max } = this.data
- const { uploadMax, uploadCount } = this.calcValue(count, max)
- // 判断是否需要更新
- if (this.data.uploadMax !== uploadMax || this.data.uploadCount !== uploadCount) {
- this.setData({
- uploadMax,
- uploadCount,
- })
- }
- },
- /**
- * 计算最多可以选择的图片张数
- */
- calcValue(count, max) {
- const realCount = parseInt(count)
- const uploadMax = parseInt(max) > -1 ? parseInt(max) : -1
- let uploadCount = realCount
- // 限制总数时
- if (uploadMax !== -1 && uploadMax <= 9 && realCount > uploadMax) {
- uploadCount = uploadMax
- }
- return {
- uploadMax,
- uploadCount,
- }
- },
- /**
- * 从本地相册选择图片或使用相机拍照
- */
- onSelect() {
- const {
- uploadCount,
- uploadMax,
- sizeType,
- sourceType,
- uploaded,
- disabled,
- uploadFileList: fileList,
- isVideo,
- compressed,
- maxDuration,
- camera,
- } = this.data
- const { uploadCount: count } = this.calcValue(uploadCount, uploadMax - fileList.length)
- const success = (res) => {
- res.tempFilePaths = res.tempFilePaths || [res.tempFilePath]
- this.tempFilePaths = res.tempFilePaths.map((item) => ({ url: item, uid: this.getUid() }))
- this.triggerEvent('before', {...res, fileList })
- // 判断是否取消默认的上传行为
- if (uploaded) {
- this.uploadFile()
- }
- }
- // disabled
- if (disabled) return
- // choose video
- if (isVideo) {
- wx.chooseVideo({
- sourceType,
- compressed,
- maxDuration,
- camera,
- success,
- })
- return
- }
- // choose image
- wx.chooseImage({
- count,
- sizeType,
- sourceType,
- success,
- })
- },
- /**
- * 上传文件改变时的回调函数
- * @param {Object} info 文件信息
- */
- onChange(info = {}) {
- if (!this.data.controlled) {
- this.setData({
- uploadFileList: info.fileList,
- })
- }
- this.triggerEvent('change', info)
- },
- /**
- * 开始上传文件的回调函数
- * @param {Object} file 文件对象
- */
- onStart(file) {
- const targetItem = {
- ...file,
- status: 'uploading',
- }
- this.onChange({
- file: targetItem,
- fileList: [...this.data.uploadFileList, targetItem],
- })
- },
- /**
- * 上传文件成功时的回调函数
- * @param {Object} file 文件对象
- * @param {Object} res 请求响应对象
- */
- onSuccess(file, res) {
- const fileList = [...this.data.uploadFileList]
- const index = fileList.map((item) => item.uid).indexOf(file.uid)
- if (index !== -1) {
- const targetItem = {
- ...file,
- status: 'done',
- res,
- }
- const info = {
- file: targetItem,
- fileList,
- }
- // replace
- fileList.splice(index, 1, targetItem)
- this.triggerEvent('success', info)
- this.onChange(info)
- }
- },
- /**
- * 上传文件失败时的回调函数
- * @param {Object} file 文件对象
- * @param {Object} res 请求响应对象
- */
- onFail(file, res) {
- const fileList = [...this.data.uploadFileList]
- const index = fileList.map((item) => item.uid).indexOf(file.uid)
- if (index !== -1) {
- const targetItem = {
- ...file,
- status: 'error',
- res,
- }
- const info = {
- file: targetItem,
- fileList,
- }
- // replace
- fileList.splice(index, 1, targetItem)
- this.triggerEvent('fail', info)
- this.onChange(info)
- }
- },
- /**
- * 监听上传进度变化的回调函数
- * @param {Object} file 文件对象
- * @param {Object} res 请求响应对象
- */
- onProgress(file, res) {
- const fileList = [...this.data.uploadFileList]
- const index = fileList.map((item) => item.uid).indexOf(file.uid)
- if (index !== -1) {
- const targetItem = {
- ...file,
- progress: res.progress,
- res,
- }
- const info = {
- file: targetItem,
- fileList,
- }
- // replace
- fileList.splice(index, 1, targetItem)
- this.triggerEvent('progress', info)
- this.onChange(info)
- }
- },
- /**
- * 上传文件,支持多图递归上传
- */
- uploadFile() {
- if (!this.tempFilePaths.length) return
- const { url, name, header, formData, disabled, progress } = this.data
- const file = this.tempFilePaths.shift()
- const { uid, url: filePath } = file
- if (!url || !filePath || disabled) return
- this.onStart(file)
- this.uploadTask[uid] = wx.uploadFile({
- url,
- filePath,
- name,
- header,
- formData,
- success: (res) => this.onSuccess(file, res),
- fail: (res) => this.onFail(file, res),
- complete: (res) => {
- delete this.uploadTask[uid]
- this.triggerEvent('complete', res)
- this.uploadFile()
- },
- })
- // 判断是否监听上传进度变化
- if (progress) {
- this.uploadTask[uid].onProgressUpdate((res) => this.onProgress(file, res))
- }
- },
- /**
- * 点击文件时的回调函数
- * @param {Object} e 参数对象
- */
- onPreview(e) {
- this.triggerEvent('preview', {...e.currentTarget.dataset, fileList: this.data.uploadFileList })
- },
- /**
- * 点击删除图标时的回调函数
- * @param {Object} e 参数对象
- */
- onRemove(e) {
- const { file } = e.currentTarget.dataset
- const fileList = [...this.data.uploadFileList]
- const index = fileList.map((item) => item.uid).indexOf(file.uid)
- if (index !== -1) {
- const targetItem = {
- ...file,
- status: 'remove',
- }
- const info = {
- file: targetItem,
- fileList,
- }
- // delete
- fileList.splice(index, 1)
- this.triggerEvent('remove', {...e.currentTarget.dataset, ...info })
- this.onChange(info)
- }
- },
- /**
- * 中断上传任务
- * @param {String} uid 文件唯一标识
- */
- abort(uid) {
- const { uploadTask } = this
- if (uid) {
- if (uploadTask[uid]) {
- uploadTask[uid].abort()
- delete uploadTask[uid]
- }
- } else {
- Object.keys(uploadTask).forEach((uid) => {
- if (uploadTask[uid]) {
- uploadTask[uid].abort()
- delete uploadTask[uid]
- }
- })
- }
- },
- },
- /**
- * 组件生命周期函数,在组件实例进入页面节点树时执行
- */
- created() {
- this.index = 0
- this.createdAt = Date.now()
- this.getUid = () => `wux-upload--${this.createdAt}-${++this.index}`
- this.uploadTask = {}
- this.tempFilePaths = []
- },
- /**
- * 组件生命周期函数,在组件实例进入页面节点树时执
- */
- attached() {
- const { defaultFileType, defaultFileList, fileList, controlled } = this.data
- const uploadFileList = controlled ? fileList : defaultFileList
- const isVideo = defaultFileType === 'video'
- this.setData({ uploadFileList, isVideo })
- },
- /**
- * 组件生命周期函数,在组件实例被从页面节点树移除时执行
- */
- detached() {
- this.abort()
- },
- })
|