uniapp实现Android、iOS原生文件选取上传

369 阅读1分钟

uniapp官方并没有提供app端的本地文件选取api,官方人员提供的思路是使用webview,内嵌html使用<input type="file"/>实现,我从插件市场找到的插件看源码学习了一下,基于这个思路,可以利用renderjs更方便的实现

template的写法有点不同

<template>
    <button @click="openFilePicker">上传文件</button>
    <view v-show="false" v-html="input" :props="mergeProps" :change:props="file.renderProps"></view>
</template>
// 这里自定义自己的样式
// v-html绑定则是需要渲染的input组件
// props绑定需要监听的属性
// change:props则是对props实行监听,类似于watch
// 只要props绑定的属性值变化,就会执行change所绑定的事件

普通script中定义属性,还有openFilePicker方法

<script>
export default {
    data() {
        return {
            input:'',
            inputId:'',
            uploadUrl:''// 上传接口地址,
        }
    },
    computed: {
        mergeProps(){
            return {
                input: this.input,
                inputId: this.inputId,
                uploadUrl: this.uploadUrl
            };
        }
    },
    methods: {
        openFilePicker(){
            // 生成一个随机id,使其产生变化,从而触发change事件
            this.inputId = Date.now().toString(36) + Math.random().toString(36);
            // 渲染input组件
            this.input = `<input type="file" id="file-upload-${this.inputId}" />`;
        },
        handleEmits(e){
            // 上传成功后,数据会回调到这里,然后写自己的业务逻辑
            ...
        }
    }
}
</script>

在renderjs中实现上传方法

// 在script标签上声明renderjs,给一个module名字,上面change绑定的方法就需要这个名字获取
<script module="file" lang="renderjs">
export default {
    methods: {
        // change事件实际绑定的方法
        renderProps(data){
            // data则是props绑定的属性值,业务需要什么值,就从props传,renderjs无法直接获取
            if(data.input) return
            this.$nextTick(() => {
                // renderjs可以直接使用web端的document属性获取dom
                const dom = document.getElementById(`file-upload-${data.inputId}`);
                // 注册input组件的change事件,即选取文件后的回调
                dom.addEventListener('change', (e) => {
                    // e.target.files为选取的文件列表,返回一个数组
                    const files = e.target.files
                    // 使用xhr上传
                    const xhr = new XMLHttpRequest()
                    let formData = new FormData()
                    formData.append('file',files[0])
                    xhr.open('POST', data.uploadUrl)
                    xhr.onreadystatechange = ()=> {
                        if(xhr.readyState == 4){
                            const res = JSON.parse(xhr.responseText)
                            if(res.code===200){
                                // res.data为上传接口返回数据
                                // 使用$ownerInstance.callMethod调用上面script中的方法,类似$emit()
                                this.$ownerInstance.callMethod('handleEmits', res.data);
                            }
                        }
                    }
                    xhr.send(formData)
                })
            }
        }
    }
}
</script>