作者: admin

  • 微信jssdk授权签名以及config配置

    凡是要想在h5页面使用jweixin.js的功能就必须授权签名才行。以下流程
    1,申请公众账号测试  或者 是已经有了公众号

    2,用appID和 appsecret来换取access_token
    access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token`)

    3,用access_token来换取jsapi_ticket
    jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket`)

    4,有了jsapi_ticket就能生成signature
    appid
    noncestr 一般自己生成
    jsapi_ticket
    timestamp 一般自己生成
    url //当前页面url
    signature // jsapi_ticket+noncestr+timestamp+url,字符串拼接后用sha1加密  (这里还有点不清楚是不是这样)

    5,之后就是把生成的参数传给前端

    如果想获取用户的基本信息,如openid或者unionid,头像、性别什么的,请看《微信公众号授权第三方 OAuth2.0

  • base64、blob和file数据类型相互转换并使用FormData模拟表单上传

    涉及到new FileReader()、new File()、new FormData()、createObjectURL() 上传 压缩

    FormData js模拟表单上传

    var  formData = new FormData();
    formData.append("type","2");
    formData.append("file",blob,"recorder.mp3"); //添加上传blob数据类型
    formData.append("file",file,"1.jpg"); //添加上传file数据类型
    
    $('#xx').click(function () {
        $.ajax({
            beforeSend:function(e){
                var type='(jpg|png)'
                if(  !(new RegExp(".+\."+type+"$",'ig').test( $('#file')[0].files[0].name ) ) ){
                    layer.msg('文件类型不正确');
                    _this.val('')
                    return false
                }
    
            },
            url:"/uploadbase64" //上传接口地址
            ,type:"POST"
            ,contentType:false //让xhr自动处理Content-Type header,multipart/form-data需要生成随机的boundary
            ,processData:false //不要处理data,让xhr自动处理
            ,data:formData
            ,success:function(v){
                console.log("上传成功",v);
    
            }
            ,error:function(s){
                console.error("上传失败",s);
            }
        });
    });
    
    
    

     

    //多文件上传
    <input id="file" type="file" name="uploads" multiple="multiple" onchange="cb()"><br>
    
    function cb(){
        for(let i=0;i<$('#file')[0].files.length;i++){
          //
            sendfild(i)
        }
    
    
    
       function sendfild(x){
           formData = new FormData();
           formData.append("uploads",$('#file')[0].files[x],$('#file')[0].files[x].name); //添加上传file数据类型name
           $.ajax({
               beforeSend:function(e){
                   // var type='(jpg|png)'
                   // if(  !(new RegExp(".+\."+type+"$",'ig').test( $('#file')[0].files[0].name ) ) ){
                   //     layer.msg('文件类型不正确');
                   //     _this.val('')
                   //     return false
                   // }
    
               },
               url:"/upload" //上传接口地址
               ,type:"POST"
               ,contentType:false //让xhr自动处理Content-Type header,multipart/form-data需要生成随机的boundary
               ,processData:false //不要处理data,让xhr自动处理
               ,data:formData
               ,success:function(v){
                   console.log("上传成功",v);
    
                      // sendfild(x)
    
    
               }
               ,error:function(s){
                   console.error("上传失败",s);
               }
           })
       }
    
    
        return false
    }

     

     

     

     

    file 转 base64   (FileReader方法)

    <input id="fielinput" type="file" multiple="multiple" accept="image/*" onchange="showPreview(this)">
    
    function showPreview(source) {
        var file = source.files[0];
    
        //判断文件类型
        var extfile = file.name;
        var AllImgExt=".jpg|.jpeg|.gif|.bmp|.png|";
        var extName = extfile.substring(extfile.lastIndexOf(".")).toLowerCase();//(把路径中的所有字母全部转换为小写)
        if(AllImgExt.indexOf(extName+"|")==-1)
        {
            var ErrMsg="该文件类型不允许上传。请上传 "+AllImgExt+" 类型的文件,当前文件类型为"+extName;
            alert(ErrMsg);
            return false;
        }
        if(window.FileReader) {
            var fr = new FileReader();
            fr.readAsDataURL(file);
            fr.onloadend = function(e) {
                   // e.target.result  base64
                  document.getElementById("fielImg").src = e.target.result;
                // document.getElementById("baseimg").value = e.target.result;
                //  console.log(convertBase64UrlToBlob(e.target.result));
            };
        }else{
            alert('浏览器不支持预览图片');
        }
    };

     

     

    图片 转 base64   (canvas的toDataURL方法)  

    *注意toDataURL方法会涉及到跨域问题,要让后台对图片链接的处理

    var img = "https://img.alicdn.com/bao/uploaded/TB1qimQIpXXXXXbXFXXSutbFXXX.jpg";
    
    function getBase64Image(img) {
      var canvas = document.createElement("canvas");
      canvas.width = img.width;
      canvas.height = img.height;
    
      var ctx = canvas.getContext("2d");
      ctx.drawImage(img, 0, 0, img.width, img.height);
      var ext = img.src.substring(img.src.lastIndexOf(".")+1).toLowerCase();
      var dataURL = canvas.toDataURL("image/"+ext);
      return dataURL;
    }
    var image = new Image();
    image.crossOrigin = '';
    image.src = img;
    image.onload = function(){
      var base64 = getBase64Image(image);  //这里获取base64
     
    }

     

     

    base64 转 file

    function base64URLtoFile(base64Data, filename) {  //*filename包括后缀名,例如1.png
        var arr = base64Data.split(','),
            mime = arr[0].match(/:(.*?);/)[1],
            bstr = atob(arr[1]),
            n = bstr.length,
            u8arr = new Uint8Array(n);
        while (n--) {
            u8arr[n] = bstr.charCodeAt(n);
        }
        return new File([u8arr], filename, { type: mime });
    }

     

     

     

    blob转json

    const reader = new FileReader();
    reader.readAsText(blobData, 'utf-8');
    reader.onload = function (e) {
      const readerres = reader.result;
      const parseObj = JSON.parse(readerres);
    }

     

     

     

     

    base64 转 blob

    function convertBase64UrlToBlob(urlData){
        var bytes=window.atob(urlData.split(',')[1]);        //去掉url的头,并转换为byte
    
        //处理异常,将ascii码小于0的转换为大于0
        var ab = new ArrayBuffer(bytes.length);
        var ia = new Uint8Array(ab);
        for (var i = 0; i < bytes.length; i++) {
            ia[i] = bytes.charCodeAt(i);
        }
        return new Blob( [ab] , {type : 'image/png'});
    }

     

     

    file 转 blob   (createObjectURL方法)

    或者file转base64在转blob

    预览上传图片、视频——createObjectURL

     

    url地址转base64

    js将url图片地址转base64

     

     

    url地址转file对象

    var img =
      "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=508387608,2848974022&fm=26&gp=0.jpg"; //imgurl 就是你的图片路径
    
    function getBase64Image(img) {
      var canvas = document.createElement("canvas");
      canvas.width = img.width;
      canvas.height = img.height;
      var ctx = canvas.getContext("2d");
      ctx.drawImage(img, 0, 0, img.width, img.height);
      var ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
      var dataURL = canvas.toDataURL("image/" + ext);
    
      return dataURL;
    }
    
    var image = new Image();
    image.src = img;
    image.setAttribute("crossOrigin", "Anonymous");
    image.onload = function() {
      var base64 = getBase64Image(image);
      console.log(base64);
    
      document.getElementById("img").src = base64;
    
      var formData = new FormData();
    
      //转换base64到file
      var file = btof(base64, "test");
      formData.append("imageName", file);
    };
    
    function btof(data, fileName) {
      const dataArr = data.split(",");
      const byteString = atob(dataArr[1]);
    
      const options = {
        type: "image/jpeg",
        endings: "native"
      };
      const u8Arr = new Uint8Array(byteString.length);
      for (let i = 0; i < byteString.length; i++) {
        u8Arr[i] = byteString.charCodeAt(i);
      }
      return new File([u8Arr], fileName + ".jpg", options);
    }

     

     

     

    数据类型上传

    file:直接上传,就是我们平时用的<input type=”file”>

    base64:直接传,但需要将data:image/png;base64,这段内容过滤掉,后台才能转为成 图片,

    案例:https://sdeno.com/?p=5633

     

    blob:需要转成file类型,可以利用new FormData()

    案例:https://sdeno.com/?p=7387

     

    上传还需要涉及到 《post发送数据时的两种编码格式

     

    前端压缩图片并上传

    (1)图片转blob

    pic_blobxxx

     

    (2)图片转base64位

    js base64图片压缩

    ———————————–

    exif.js

    <script src="js/exif.js"></script>
    
    <div class="IDcardA"><input id="zm" @change="getImageBase64($event, 'IDcardA')" type="file" accept="image/*"></div>
    <div class="IDcardB"><input id="fm" @change="getImageBase64($event, 'IDcardB')" type="file" accept="image/*"></div>
    
    
    
    function rotateImg(img, step, canvas) {
            //最小与最大旋转方向,图片旋转4次后回到原方向  
            var min_step = 0;
            var max_step = 3;
            if (img === null) return;
            //img的高度和宽度不能在img元素隐藏后获取,否则会出错  
            var height = img.height;
            var width = img.width;
            //旋转角度以弧度值为参数  
            var degree = step * 90 * Math.PI / 180;
            var ctx = canvas.getContext('2d');
            switch (step) {
                case 0:
                    canvas.width = width;
                    canvas.height = height;
                    ctx.drawImage(img, 0, 0);
                    break;
                case 1:
                    canvas.width = height;
                    canvas.height = width;
                    ctx.rotate(degree);
                    ctx.drawImage(img, 0, -height);
                    break;
                case 2:
                    canvas.width = width;
                    canvas.height = height;
                    ctx.rotate(degree);
                    ctx.drawImage(img, -width, -height);
                    break;
                case 3:
                    canvas.width = height;
                    canvas.height = width;
                    ctx.rotate(degree);
                    ctx.drawImage(img, -width, 0);
                    break;
            }
            return canvas;
        }
    
    methods:{
     getImageBase64: function(e, className) {
    
        var self = this;
        // self.jsOpenCamear();
        var el = e.target;
        var imgBase64 = '';
    
        if(!el.files || !el.files.length){
            return;
        }
        var file = el.files[0];
        if (/\.txt/.test(file.name) || !file.size) {
            Tools.loading(false);
            return Tools.dialog.alert('请拍照或者上传图片!');
        }
        Tools.loading(true);
        EXIF.getData(file, function() {
            self.orientation = EXIF.getTag(file, 'Orientation');
        });
        var fileName = file.name;
        var reader = new FileReader();
        //读取文件以数据URI的形式保存在reader的result属性中
        reader.readAsDataURL(file);
        //获取图片大小,以M为单位
        var fileSize = Math.round(file.size / 1024 / 1024);
        //获取图片大小,以KB为单位
        var fileSizeKB = Math.round(file.size / 1024);
        //上传图片的尺寸必需大于200KB
        if (fileSizeKB > 1024) {
            // Tools.dialog.alert('请上传1MB以内的图片', '好的');
            // return;
        }
    
        el.value = '';
    
    
        reader.onload = function () {
            var cvs = document.createElement("canvas");
            var img = new Image();
            img.src = this.result;
            img.onload = function() {
                var width = img.width, height = img.height;
                switch (cvs.width = width,
                    cvs.height = height,
                    self.orientation) {
                    case 3:
                        cvs = rotateImg(this, 2, cvs);
                        break;
                    case 6:
                        cvs = rotateImg(this, 1, cvs);
                        break;
                    case 8:
                        cvs = rotateImg(this, 3, cvs);
                        break;
                    default:
                        cvs = rotateImg(this, 0, cvs);
                }
                var imgData = cvs.toDataURL('image/png');
                if (fileSizeKB > 60) {
                    compress(imgData, fileSize, 1024, fileName, function(imgBase64Data, fileName){
                        imgBase64 = imgBase64Data;
                        imgBase64 = imgBase64Data.replace(/data:image\/(png|jpeg|jpg|gif);base64,/g,'');
                        Tools.loading(false);
                        self.uploadProfile(imgBase64, className);
                    },'', 0.6);
                } else {
                    Tools.loading(false);
                    imgBase64 = imgData;
                    imgBase64 = imgData.replace(/data:image\/(png|jpeg|jpg|gif);base64,/g,'');
                    self.uploadProfile(imgBase64, className);
                }
            };
    
            //获取原图的base64信息
    
        };
     },
     /*预览*/
     previewPic: function(imageUrl, className) {
        if (className == 'IDcardA') {
            imageIdcardFront=imageUrl;
            $('.positive').css({background:'#EEF0F1 url('+imageUrl+') no-repeat center',backgroundSize:'contain'}).find('.dele-img').show();
        } else if (className == 'IDcardB') {
            $('.back').css({background:'#EEF0F1 url('+imageUrl+') no-repeat center',backgroundSize:'contain'}).find('.dele-img').show();
            imageIdcardBack=imageUrl;
        }
    
        // $('.'+className).css({
        //     'background': 'url('+imageUrl+') no-repeat',
        //     'background-size': 'contain',
        //     'border': 'dashed .05rem #ccc',
        //     'border-radius': '.3rem'
        // });
     },
     // 上传照片到后台
     uploadProfile: function(imgBase64, className) {
        var self = this;
        if (!imgBase64) {
            return Tools.dialog.alert('当前图片不合格,请换一张试试!');
        }
        Tools.loading(true);
    
        //-----------需要后台能接收到base64的数据类型并生成图片---------------------
        $.ajax({
            // xhrFields:{
            //     withCredentials:true
            // },
            // crossDomain:true,
            type: 'post',
            data: JSON.stringify({
                strFiles: imgBase64
            }),
            contentType: "application/json",
            dataType: "json",
            url: ajaxUrl,
            timeout: 60000,
            headers:{
                "userToken": sessionStorage.getItem('userToken')
            },
            complete: function(x, t) {
                if(typeof completeFn == 'function'){
                    completeFn(x, t);
                } else {
                    if(Tools && Tools.loading){
                        Tools.loading(false);
                    }
                }
               
            },
            success:function (res) {
                self.previewPic(res.data, className);
            },
            error:function (res) {
    
            }
        });
       //--------------------------------
    
     },
    
    }  //methods

     

     

  • 另存为效果

    js 另存为 a 下载 html 下载

    (推荐)前端方法:

    <a href="http://localhost:3000/upload/index_logo.gif" download="xxx">下载11</a>   //下载后是xxx.gif

    *注意所下载的文件必须是同域名不然无法实现另存为效果,仅仅不兼容IE。谷歌、火狐,Edge兼容

     

    如果下载需要token验证,参考https://sdeno.com/?p=8002

     

    后端方法:

    例如php需要设置

    header('Content-type: image/jpeg'); 
    header("Content-Disposition: attachment; filename='download.jpg'");

     

    这里以koa2为案例:

    路由设置

    router.get('xxxpath', (ctx) => {
      ctx.set('Content-disposition','attachment;filename=name.txt'); // 设置你的文件名
      const data = new Buffer('Im a example of text') // 创建一个buffer
      ctx.body = data // 返回在响应体里
    });

     

    前端设置

    <a onclick="window.open('xxxpath')">下载</a>  //下载后会得到一个txt,内容是Im a example of text

     

    —————————————

     

    为了方便将其他文件也转化为Buffer,推荐使用

    npm i urllib -S
    const urllib = require('urllib');
    
    router.get('down',async ctx=>{
      let file = await urllib.request('https://sdeno.com/wp-content/themes/flat_ui/img/icons/png/jquery.png');
      ctx.set('Content-disposition','attachment;filename='+'name.jpg');
      ctx.body=file.data; //返回的是 Buffer类型
    });

     

    https://www.zhangxinxu.com/wordpress/2016/04/know-about-html-download-attribute/

  • 微信公众号页面授权获取用户基本信息

    微信 授权 微信 公众号 授权

    授权仅仅是获取用户的基本信息例如头像,昵称,并非使用jssdk,跟分享和拉起支付没关系。

    想看分享功能点击《微信端分享、手机QQ好友分享以及小程序和H5数据交互》

     

    快速了解步骤:

    //以下步骤是让H5在公众号能获取到用户的基本信息
    1,我们网站的/a
    2,授权https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=encodeURIComponent(/a)&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
    3,授权后,调回/a?code=123
    4,用code换取 token和openid
    5,用token和openid,换取用户资料

     

    打开一个微信公众号号,点击一个链接要跳转到,其他页面。但是跳转到其他页面需要授权才能跳转。这就是本教程需要说的。

     

     

    什么是OAuth

    假如本站要获取其他用户的qq基本信息,要通过OAuth开放协议,这样可以在不提供密码的时候把信息拿到,前提是qq用户要授权。

     

    准备条件:

    (1)“开发 — 接口权限 — 网页服务 — 网页帐号 — 网页授权获取用户基本信息”
    的配置选项中,修改授权回调域名。

     

    (2)用户要已关注公众号

     

    注意:使用snsapi_base静默授权,不会弹窗但仅仅能获取到openid,但也足以实现分享、支付功能。

    要获取unionid就必须使用snsapi_userinfo。

     

    网页授权文档

    https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

     

    开始授权

    以下教程使用snsapi_base授权,静默授权就是不会弹窗让用户去点击。

    1,以下地址由后台去请求,用户授权后获取code:

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

     

    案例:

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect

    *注意redirect_uri参数要做encodeURIComponent(url)处理

     

    用户点击后且没报错说明执行成功并执行回调访问链接且带code参数例如,

    http://mascot.duapp.com/oauth2.php?code=00b788e3b42043c8459a57a8d8ab5d9f&state=1  //code码会拼接到redirect_uri地址上返回给我们
    http://mascot.duapp.com/oauth2.php //我们之前设置的redirect_uri
    state=1 //携带的参数同时也传回来
    code // 用这个code来换取access_token

     

    2,使用code换取access_token和openid

    上一个步骤执行成功就会,再次执行我们后台自己的接口,并且还带有参数:http://mascot.duapp.com/oauth2.php?code=00b788e3b42043c8459a57a8d8ab5d9f&state=1

    利用code参数的值去调用以下链接

     

    换取的连接是:

    https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

     

    例如:
    https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx8888888888888888&secret=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&code=00b788e3b42043c8459a57a8d8ab5d9f&grant_type=authorization_code

    如果成功换成后就会返回类似这样的数据结构
    {
    “access_token”: “OezXcEiiBSKSxW0eoylIeAsR0GmYd1awCffdHgb4fhS_KKf2CotGj2cBNUKQQvj-G0ZWEE5-uBjBz941EOPqDQy5sS_GCs2z40dnvU99Y5AI1bw2uqN–2jXoBLIM5d6L9RImvm8Vg8cBAiLpWA8Vw”,
    “expires_in”: 7200,
    “refresh_token”: “OezXcEiiBSKSxW0eoylIeAsR0GmYd1awCffdHgb4fhS_KKf2CotGj2cBNUKQQvj-G0ZWEE5-uBjBz941EOPqDQy5sS_GCs2z40dnvU99Y5CZPAwZksiuz_6x_TfkLoXLU7kdKM2232WDXB3Msuzq1A”,
    “openid”: “oLVPpjqs9BhvzwPj5A-vTYAX3GLc”,
    “scope”: “snsapi_userinfo,”
    }

    注意这里的token有效时间是2个小时,也就是7200秒,所以本地用cookies存储access_token时最好设置过期时间是7000秒保证拉取最新

     

    3,用access_token和openid换取用户基本信息 (如果之前用的是snsapi_userinfo方式授权那么这步也会返回获取unionid)

    请求结构是:

    https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID

    例如:
    https://api.weixin.qq.com/sns/userinfo?access_token=OezXcEiiBSKSxW0eoylIeAsR0GmYd1awCffdHgb4fhS_KKf2CotGj2cBNUKQQvj-G0ZWEE5-uBjBz941EOPqDQy5sS_GCs2z40dnvU99Y5AI1bw2uqN–2jXoBLIM5d6L9RImvm8Vg8cBAiLpWA8Vw&openid=oLVPpjqs9BhvzwPj5A-vTYAX3GLc

    成功后会获得类似这样的数据结构:
    {
    “openid”: “oLVPpjqs9BhvzwPj5A-vTYAX3GLc”,
    “nickname”: “刺猬宝宝”,
    “sex”: 1,
    “language”: “简体中文”,
    “city”: “深圳”,
    “province”: “广东”,
    “country”: “中国”,
    “headimgurl”: “http://wx.qlogo.cn/mmopen/utpKYf69VAbCRDRlbUsPsdQN38DoibCkrU6SAMCSNx558eTaLVM8PyM6jlEGzOrH67hyZibIZPXu4BK1XNWzSXB3Cs4qpBBg18/0”,
    “privilege”: []
    }

     

    4,OAuth2认证就完成了

     

     

    5,如何获取unionid

    条件:

    如果希望微信公众号和小程序都能获取unionid,必须在微信开放平台同时绑定公众号和小程序。

    微信开放平台https://open.weixin.qq.com/

     

    绑定小程序也一样。剩下的教程跟1,2,3步骤一样

    http://www.3jke.com/news/2030/?tdsourcetag=s_pcqq_aiomsg

     

    https://www.cnblogs.com/txw1958/p/weixin71-oauth20.html

     

  • js判断微信、小程序、qq内置浏览器和其他第三方浏览器

    js 平台 判断 分享 判断

    主要是判断,小程序或者微信。

    var ua = navigator.userAgent.toLowerCase();
    if(ua.match(/MicroMessenger/i)=="micromessenger") {
       //ios的ua中无miniProgram,但都有MicroMessenger(表示是微信浏览器)
       wx.miniProgram.getEnv((res)=>{
        if (res.miniprogram) {
           //alert("在小程序里");
          wx.miniProgram.navigateTo({
            url: '/pages/user/my-order/my-money',
          })
        } else {
          //alert("不在小程序里,但在微信里");
          window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx231ea8dfba02c266&redirect_uri=http%3a%2f%2fapi.bugegaming.com%2fv1.0.6%2fwx%2fgzh%2fpay%2flogin%2fmenu&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect';
        }
      })
    }else{
    
      if (ua.match(/QQ/i) == "qq") {
         //alert("qq内置浏览器");
      }else {
         //alert("不是微信浏览器或手机qq浏览器,例如自带浏览器");
      }
    
    }