Implementation of WeChat applet upload file function

In the development of small programs, there may be scenarios where files need to be uploaded. Users need to select files from the mobile phone file manager and upload them to the server. However, WeChat small programs only support the selection of files in the session, and cannot be selected from the mobile phone. .And this api only supports WeChat, not enterprise WeChat.

image.png

We can realize it through the web-view of the applet . The file upload is realized through the <input> of html.

Precautions for using web-view:

  1. The applet web-view does not support local paths, only remote links, and the link must be configured with a business domain name in the applet management background;
  2. Web-view loading needs to be displayed on a single page, and it will fill the screen, and does not support partial rendering.

Parameter passing: (The following demo is based on uni-app)

  1. Small program --> web-view
    is passed through link splicing parameters.
<template name="input">
    <view>
        <web-view @message="handleMessage" :src="src()"></web-view>
    </view>
</template>
<script>
export default {
    data() {
        return {
            pageUrl: '', // 页面地址
            uploadUrl: '', //文件上传地址
        }
    },
    methods: {
        src() {
            return `${this.pageUrl}?url=${this.uploadUrl}`
        },
    }
}
</script>

Receive parameters:

<script>
function getUrlParam(name) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)")
        var r = window.location.search.substr(1).match(reg)
        if (r != null) return unescape(r[2])
        return null
    }
    var uploadUrl = getUrlParam('url');
</script>

  1. web-view --> The parameters passed by the applet must be returned through data:{}, and the value of the parameter in data must be a string type.
wx.miniProgram.postMessage({
     data: {
             fileName: res.data.fileName,
             fileUrl: res.data.url
       }
})

Receiving parameters:
When the web page postsMessage to the applet, it will trigger and receive the message at a specific time (backup of the applet, component destruction, sharing). The Mini Program triggers the bindmessage event
html page:
after calling the parameter passing, closing the page (wx.miniProgram.navigateBack()) triggers the receiving parameter event

wx.miniProgram.postMessage({
     data: {
             fileName: res.data.fileName,
             fileUrl: res.data.url
       }
})
setTimeout(() => {
    wx.miniProgram.navigateBack()
}, 500)

Mini Program page:

<web-view @message="handleMessage" :src="src()"></web-view>
...
handleMessage(evt) {
    console.log('接收到的消息:' + JSON.stringify(evt.detail.data));

}
...

Complete code sharing:

image.png

Mini Program page:

<template name="input">
    <view>
        <web-view @message="handleMessage" :src="src()"></web-view>
    </view>
</template>
<script>
export default {
    data() {
        return {
            pageUrl: 'http://test.com/upload.html', //页面地址
            uploadUrl: 'http://test.com/upload', //文件上传接口地址
        }
    },

    methods: {
        src() {
            return `${this.pageUrl}?url=${this.uploadUrl}&accessToken=${this.accessToken}`
        },
        handleMessage(evt) {
            console.log('接收到的消息:' + JSON.stringify(evt.detail.data));
            this.$bus.$emit("fileUpload", evt.detail.data)
        }
    }
}
</script>
<style>
</style>

html page:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
        content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0">
    <title>文件上传</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <!-- 微信 JS-SDK 如果不需要兼容小程序,则无需引用此 JS 文件。 -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
    <!-- uni 的 SDK,必须引用。 -->
    <script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.0.1.52.js">
    </script>

    <style>
        svg {
            margin-top: -100px;
        }

        div {
            height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            width: 100%;
        }

        .file {
            position: relative;
            display: inline-block;
            background: #007aff;
            padding: 12px 70px;
            overflow: hidden;
            text-decoration: none;
            text-indent: 0;
            border-radius: 20px;
            color: #fff;
            font-size: 13px;
            margin-top: 70px;

        }

        .file input {
            position: absolute;
            font-size: 100px;
            right: 0;
            top: 0;
            opacity: 0;
        }
    </style>
</head>

<body>
    <div id="app">
        <p style="margin-top: 20px;" id="status"></p>
        <p v-if="upLoadProgress > 0">上传进度: {
     
     {upLoadProgress}}%</p>
        <a href="javascript:;" class="file gradient">选择文件
            <input id="upload" type="file" name="upload" @change="changeExcel($event)">
        </a>
        <p style="color: #ccc; font-size: 12px;" id="content">选择文件开始上传</p>
    </div>
</body>
<script>
    function viewPort() {
        const meta = document.querySelector('meta[name="viewport"]');
        const scale = window.screen.width / 375 < 1 ? 1 : window.screen.width / 375;
        meta.content = `width=device-width,initial-scale=${scale}`
    }
    viewPort()
    window.onresize = viewPort;

    function getUrlParam(name) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)")
        var r = window.location.search.substr(1).match(reg)
        if (r != null) return unescape(r[2])
        return null
    }
    var uploadUrl = getUrlParam('url'); 
    var accessToken = getUrlParam('accessToken');
    new Vue({
        el: '#app',
        data: {
            imgPath: '',
            upLoadProgress: 0,
        },
        components: {

        },
        methods: {

            changeExcel(ev) {
                const files = ev.target.files;
                console.log(ev, files);
                if (files.length < 0) {
                    document.getElementById("status").innerHTML = '请选择文件';
                    return false;
                } else {
                    let param = new FormData(); //创建form对象
                    param.append('file', files[0], files[0].name); //通过append向form对象添加数据
                    let fileReader = new FileReader()
                    console.log("get uploadUrl:", uploadUrl);
                    console.log("get uploadUrl:", accessToken);
                    axios({
                        url: uploadUrl,
                        method: 'POST',
                        data: param,
                        headers: {
                            Authorization: accessToken
                        },
                        onUploadProgress: function (progressEvent) { //原生获取上传进度的事件
                            if (progressEvent.lengthComputable) {
                                //属性lengthComputable主要表明总共需要完成的工作量和已经完成的工作是否可以被测量
                                //如果lengthComputable为false,就获取不到progressEvent.total和progressEvent.loaded
                                upLoadProgress = progressEvent.loaded / progressEvent.total * 100 //实时获取上传进度
                            }
                        }
                    }).then(
                        res => {
                            if (res.data && res.data.code == 200) {
                                console.log("get res:", res);
                                document.getElementById("status").innerHTML = '上传成功';
                                wx.miniProgram.postMessage({
                                    data: {
                                        fileName: res.data.data.fileName,
                                        fileUrl: res.data.data.url
                                    }
                                })
                                setTimeout(() => {
                                    wx.miniProgram.navigateBack()
                                }, 500)
                            }

                        }, error => {
                            document.getElementById("status").innerHTML = '上传失败';
                        })
                }
            }
        }
    })

</script>



</html>

Guess you like

Origin blog.csdn.net/m0_37780940/article/details/129006507