小程序一些功能(二)

功能-手写板

页面布局

<view class="wrapper">

    <view class="handBtn">

        <image catchtap="selectColorEvent" src="{{ selectColor === 'black' ? '/resources/images/color_black_selected.png' : '/resources/images/color_black.png' }}" class="{{ selectColor === 'black' ? 'color_select' : '' }} black-select" data-color="black"

               data-color-value="#1A1A1A"></image>

        <image catchtap="selectColorEvent" src="{{ selectColor === 'red' ? '/resources/images/color_red_selected.png' : '/resources/images/color_red.png' }}" class="{{ selectColor === 'red' ? 'color_select' : '' }} red-select" data-color="red"

               data-color-value="#ca262a"></image>

        <button catchtap="retDraw" class="delBtn">重写</button>

        <!-- <button catchtap="subCanvas" class="subBtn">完成</button> -->

        <button catchtap="saveCanvasAsImg" class="saveBtn">保存</button>

        <button catchtap="previewCanvasImg" class="previewBtn">预览</button>

        <button catchtap="uploadCanvasImg" class="uploadBtn">上传</button>

        <button catchtap="subCanvas" class="subBtn">完成</button>

    </view>

    <view class="handCenter">

        <canvas class="handWriting" disable-scroll="true" bindtouchstart="uploadScaleStart" bindtouchmove="uploadScaleMove"

                bindtouchend="uploadScaleEnd" bindtap="mouseDown" canvas-id="handWriting">

        </canvas>

    </view>

    <view class="handRight">

        <view class="handTitle">手写板</view>

    </view>

</view>

页面样式

/* pages/signature/signature.wxss */

page {

    background#fbfbfb;

    heightauto;

    overflowhidden;

}

.wrapper {

    width100%;

    height95vh;

    margin30rpx 0;

    overflowhidden;

    display: flex;

    align-contentcenter;

    flex-direction: row;

    justify-contentcenter;

    font-size28rpx;

}

.handWriting {

    background#fff;

    width100%;

    height95vh;

}

.handRight {

    display: inline-flex;

    align-items: center;

}

.handCenter {

    border4rpx dashed #e9e9e9;

    flex: 5;

    overflowhidden;

    box-sizing: border-box;

}

.handTitle {

    transform: rotate(90deg);

    flex: 1;

    color#666;

}

.handBtn button {

    font-size28rpx;

}

.handBtn {

    height95vh;

    display: inline-flex;

    flex-direction: column;

    justify-content: space-between;

    align-content: space-between;

    flex: 1;

}

.delBtn {

    positionabsolute;

    top250rpx;

    left0rpx;

    transform: rotate(90deg);

    color#666;

}

.delBtn image {

    positionabsolute;

    top13rpx;

    left25rpx;

}

.subBtn {

    positionabsolute;

    bottom52rpx;

    left-3rpx;

    display: inline-flex;

    transform: rotate(90deg);

    background#008ef6;

    color#fff;

    margin-bottom30rpx;

    text-aligncenter;

    justify-contentcenter;

}

/*Peach - 新增 - 保存*/

.saveBtn {

    positionabsolute;

    top375rpx;

    left0rpx;

    transform: rotate(90deg);

    color#666;

}

.previewBtn {

    positionabsolute;

    top500rpx;

    left0rpx;

    transform: rotate(90deg);

    color#666;

}

.uploadBtn {

    positionabsolute;

    top625rpx;

    left0rpx;

    transform: rotate(90deg);

    color#666;

}

/*Peach - 新增 - 保存*/

.black-select {

    width60rpx;

    height60rpx;

    positionabsolute;

    top30rpx;

    left25rpx;

}

.black-select.color_select {

    width90rpx;

    height90rpx;

    top30rpx;

    left10rpx;

}

.red-select {

    width60rpx;

    height60rpx;

    positionabsolute;

    top:140rpx;

    left:25rpx;

}

.red-select.color_select {

    width90rpx;

    height90rpx;

    top120rpx;

    left10rpx;

}

逻辑代码

// packageB/pages/drawSignature/drawSignature.js

Page({

    /**

     * 页面的初始数据

     */

    data: {

        canvasName: 'handWriting',

        ctx: '',

        canvasWidth: 0,

        canvasHeight: 0,

        transparent: 1, // 透明度

        selectColor: 'black',

        lineColor: '#1A1A1A'// 颜色

        lineSize: 1.5,  // 笔记倍数

        lineMin: 0.5,   // 最小笔画半径

        lineMax: 4,     // 最大笔画半径

        pressure: 1,     // 默认压力

        smoothness: 60,  //顺滑度,用60的距离来计算速度

        currentPoint: {},

        currentLine: [],  // 当前线条

        firstTouch: true// 第一次触发

        radius: 1, //画圆的半径

        cutArea: {top: 0, right: 0, bottom: 0, left: 0}, //裁剪区域

        bethelPoint: [],  //保存所有线条 生成的贝塞尔点;

        lastPoint: 0,

        chirography: [], //笔迹

        currentChirography: {}, //当前笔迹

        linePrack: [] //划线轨迹 , 生成线条的实际点

    },

    /**

     * 生命周期函数--监听页面加载

     */

    onLoad: function (options) {

        let _this = this;

        let canvasName = this.data.canvasName

        let ctx = wx.createCanvasContext(canvasName)

        console.log(ctx);

        _this.setData({

            ctx: ctx

        })

        var query = _this.createSelectorQuery();

        query.select('.handCenter').boundingClientRect( rect => {

            console.log(rect);

            _this.setData({

                canvasWidth: rect.width,

                canvasHeight: rect.height

            })

            /* 将canvas背景设置为 白底,不设置  导出的canvas的背景为透明 */

            // console.log(this, 'hahah');

            _this.setCanvasBg('#fff');

        }).exec();

    },

    /*======所有自定义函数======*/

    // 笔迹开始

    uploadScaleStart(e) {

        if (e.type != 'touchstart'return false;

        let ctx = this.data.ctx;

        ctx.setFillStyle(this.data.lineColor);  // 初始线条设置颜色

        ctx.setGlobalAlpha(this.data.transparent);  // 设置半透明

        let currentPoint = {

            x: e.touches[0].x,

            y: e.touches[0].y

        }

        let currentLine = this.data.currentLine;

        currentLine.unshift({

            time: new Date().getTime(),

            dis: 0,

            x: currentPoint.x,

            y: currentPoint.y

        })

        this.setData({

            currentPoint,

            // currentLine

        })

        if (this.data.firstTouch) {

            this.setData({

                cutArea: {top: currentPoint.y, right: currentPoint.x, bottom: currentPoint.y, left: currentPoint.x},

                firstTouch: false

            })

        }

        this.pointToLine(currentLine);

    },

    // 笔迹移动

    uploadScaleMove(e) {

        if (e.type != 'touchmove'return false;

        if (e.cancelable) {

            // 判断默认行为是否已经被禁用

            if (!e.defaultPrevented) {

                e.preventDefault();

            }

        }

        let point = {

            x: e.touches[0].x,

            y: e.touches[0].y

        }

        //测试裁剪

        if (point.y < this.data.cutArea.top) {

            this.data.cutArea.top = point.y;

        }

        if (point.y < 0) this.data.cutArea.top = 0;

        if (point.x > this.data.cutArea.right) {

            this.data.cutArea.right = point.x;

        }

        if (this.data.canvasWidth - point.x <= 0) {

            this.data.cutArea.right = this.data.canvasWidth;

        }

        if (point.y > this.data.cutArea.bottom) {

            this.data.cutArea.bottom = point.y;

        }

        if (this.data.canvasHeight - point.y <= 0) {

            this.data.cutArea.bottom = this.data.canvasHeight;

        }

        if (point.x < this.data.cutArea.left) {

            this.data.cutArea.left = point.x;

        }

        if (point.x < 0) this.data.cutArea.left = 0;

        this.setData({

            lastPoint: this.data.currentPoint,

            currentPoint: point

        })

        let currentLine = this.data.currentLine

        currentLine.unshift({

            time: new Date().getTime(),

            dis: this.distance(this.data.currentPoint, this.data.lastPoint),

            x: point.x,

            y: point.y

        })

        // this.setData({

        //   currentLine

        // })

        this.pointToLine(currentLine);

    },

    // 笔迹结束

    uploadScaleEnd(e) {

        if (e.type != 'touchend'return 0;

        let point = {

            x: e.changedTouches[0].x,

            y: e.changedTouches[0].y

        }

        this.setData({

            lastPoint: this.data.currentPoint,

            currentPoint: point

        })

        let currentLine = this.data.currentLine

        currentLine.unshift({

            time: new Date().getTime(),

            dis: this.distance(this.data.currentPoint, this.data.lastPoint),

            x: point.x,

            y: point.y

        })

        // this.setData({

        //   currentLine

        // })

        if (currentLine.length > 2) {

            var info = (currentLine[0].time - currentLine[currentLine.length - 1].time) / currentLine.length;

            //$("#info").text(info.toFixed(2));

        }

        //一笔结束,保存笔迹的坐标点,清空,当前笔迹

        //增加判断是否在手写区域;

        this.pointToLine(currentLine);

        var currentChirography = {

            lineSize: this.data.lineSize,

            lineColor: this.data.lineColor

        };

        var chirography = this.data.chirography

        chirography.unshift(currentChirography);

        this.setData({

            chirography

        })

        var linePrack = this.data.linePrack

        linePrack.unshift(this.data.currentLine);

        this.setData({

            linePrack,

            currentLine: []

        })

    },

    retDraw() {

        this.data.ctx.clearRect(0, 0, 700, 730)

        this.data.ctx.draw();

        //设置canvas背景

        this.setCanvasBg("#fff");

    },

    //画两点之间的线条;参数为:line,会绘制最近的开始的两个点;

    pointToLine(line) {

        this.calcBethelLine(line);

        return;

    },

    //计算插值的方式;

    calcBethelLine(line) {

        if (line.length <= 1) {

            line[0].r = this.data.radius;

            return;

        }

        let x0, x1, x2, y0, y1, y2, r0, r1, r2, len, lastRadius, dis = 0, time = 0, curveValue = 0.5;

        if (line.length <= 2) {

            x0 = line[1].x

            y0 = line[1].y

            x2 = line[1].x + (line[0].x - line[1].x) * curveValue;

            y2 = line[1].y + (line[0].y - line[1].y) * curveValue;

            //x2 = line[1].x;

            //y2 = line[1].y;

            x1 = x0 + (x2 - x0) * curveValue;

            y1 = y0 + (y2 - y0) * curveValue;

            ;

        else {

            x0 = line[2].x + (line[1].x - line[2].x) * curveValue;

            y0 = line[2].y + (line[1].y - line[2].y) * curveValue;

            x1 = line[1].x;

            y1 = line[1].y;

            x2 = x1 + (line[0].x - x1) * curveValue;

            y2 = y1 + (line[0].y - y1) * curveValue;

        }

        //从计算公式看,三个点分别是(x0,y0),(x1,y1),(x2,y2) ;(x1,y1)这个是控制点,控制点不会落在曲线上;实际上,这个点还会手写获取的实际点,却落在曲线上

        len = this.distance({x: x2, y: y2}, {x: x0, y: y0});

        lastRadius = this.data.radius;

        for (let n = 0; n < line.length - 1; n++) {

            dis += line[n].dis;

            time += line[n].time - line[n + 1].time;

            if (dis > this.data.smoothness) break;

        }

        this.setData({

            radius: Math.min(time / len * this.data.pressure + this.data.lineMin, this.data.lineMax) * this.data.lineSize

        });

        line[0].r = this.data.radius;

        //计算笔迹半径;

        if (line.length <= 2) {

            r0 = (lastRadius + this.data.radius) / 2;

            r1 = r0;

            r2 = r1;

            //return;

        else {

            r0 = (line[2].r + line[1].r) / 2;

            r1 = line[1].r;

            r2 = (line[1].r + line[0].r) / 2;

        }

        let n = 5;

        let point = [];

        for (let i = 0; i < n; i++) {

            let t = i / (n - 1);

            let x = (1 - t) * (1 - t) * x0 + 2 * t * (1 - t) * x1 + t * t * x2;

            let y = (1 - t) * (1 - t) * y0 + 2 * t * (1 - t) * y1 + t * t * y2;

            let r = lastRadius + (this.data.radius - lastRadius) / n * i;

            point.push({x: x, y: y, r: r});

            if (point.length == 3) {

                let a = this.ctaCalc(point[0].x, point[0].y, point[0].r, point[1].x, point[1].y, point[1].r, point[2].x, point[2].y, point[2].r);

                a[0].color = this.data.lineColor;

                // let bethelPoint = this.data.bethelPoint;

                // console.log(a)

                // console.log(this.data.bethelPoint)

                // bethelPoint = bethelPoint.push(a);

                this.bethelDraw(a, 1);

                point = [{x: x, y: y, r: r}];

            }

        }

        this.setData({

            currentLine: line

        })

    },

    //求两点之间距离

    distance(a, b) {

        let x = b.x - a.x;

        let y = b.y - a.y;

        return Math.sqrt(x * x + y * y);

    },

    ctaCalc(x0, y0, r0, x1, y1, r1, x2, y2, r2) {

        let a = [], vx01, vy01, norm, n_x0, n_y0, vx21, vy21, n_x2, n_y2;

        vx01 = x1 - x0;

        vy01 = y1 - y0;

        norm = Math.sqrt(vx01 * vx01 + vy01 * vy01 + 0.0001) * 2;

        vx01 = vx01 / norm * r0;

        vy01 = vy01 / norm * r0;

        n_x0 = vy01;

        n_y0 = -vx01;

        vx21 = x1 - x2;

        vy21 = y1 - y2;

        norm = Math.sqrt(vx21 * vx21 + vy21 * vy21 + 0.0001) * 2;

        vx21 = vx21 / norm * r2;

        vy21 = vy21 / norm * r2;

        n_x2 = -vy21;

        n_y2 = vx21;

        a.push({mx: x0 + n_x0, my: y0 + n_y0, color: "#1A1A1A"});

        a.push({c1x: x1 + n_x0, c1y: y1 + n_y0, c2x: x1 + n_x2, c2y: y1 + n_y2, ex: x2 + n_x2, ey: y2 + n_y2});

        a.push({

            c1x: x2 + n_x2 - vx21,

            c1y: y2 + n_y2 - vy21,

            c2x: x2 - n_x2 - vx21,

            c2y: y2 - n_y2 - vy21,

            ex: x2 - n_x2,

            ey: y2 - n_y2

        });

        a.push({c1x: x1 - n_x2, c1y: y1 - n_y2, c2x: x1 - n_x0, c2y: y1 - n_y0, ex: x0 - n_x0, ey: y0 - n_y0});

        a.push({

            c1x: x0 - n_x0 - vx01,

            c1y: y0 - n_y0 - vy01,

            c2x: x0 + n_x0 - vx01,

            c2y: y0 + n_y0 - vy01,

            ex: x0 + n_x0,

            ey: y0 + n_y0

        });

        a[0].mx = a[0].mx.toFixed(1);

        a[0].mx = parseFloat(a[0].mx);

        a[0].my = a[0].my.toFixed(1);

        a[0].my = parseFloat(a[0].my);

        for (let i = 1; i < a.length; i++) {

            a[i].c1x = a[i].c1x.toFixed(1);

            a[i].c1x = parseFloat(a[i].c1x);

            a[i].c1y = a[i].c1y.toFixed(1);

            a[i].c1y = parseFloat(a[i].c1y);

            a[i].c2x = a[i].c2x.toFixed(1);

            a[i].c2x = parseFloat(a[i].c2x);

            a[i].c2y = a[i].c2y.toFixed(1);

            a[i].c2y = parseFloat(a[i].c2y);

            a[i].ex = a[i].ex.toFixed(1);

            a[i].ex = parseFloat(a[i].ex);

            a[i].ey = a[i].ey.toFixed(1);

            a[i].ey = parseFloat(a[i].ey);

        }

        return a;

    },

    bethelDraw(point, is_fill, color) {

        let ctx = this.data.ctx;

        ctx.beginPath();

        ctx.moveTo(point[0].mx, point[0].my);

        if (undefined != color) {

            ctx.setFillStyle(color);

            ctx.setStrokeStyle(color);

        else {

            ctx.setFillStyle(point[0].color);

            ctx.setStrokeStyle(point[0].color);

        }

        for (let i = 1; i < point.length; i++) {

            ctx.bezierCurveTo(point[i].c1x, point[i].c1y, point[i].c2x, point[i].c2y, point[i].ex, point[i].ey);

        }

        ctx.stroke();

        if (undefined != is_fill) {

            ctx.fill(); //填充图形 ( 后绘制的图形会覆盖前面的图形, 绘制时注意先后顺序 )

        }

        ctx.draw(true)

    },

    selectColorEvent(event) {

        console.log(event)

        var color = event.currentTarget.dataset.colorValue;

        var colorSelected = event.currentTarget.dataset.color;

        this.setData({

            selectColor: colorSelected,

            lineColor: color

        })

    },

    //将Canvas内容转成 临时图片 --> cb 为回调函数 形参 tempImgPath 为 生成的图片临时路径

    canvasToImg(cb) { //这种写法移动端 出不来

        this.data.ctx.draw(true, () => {

            wx.canvasToTempFilePath({

                canvasId: 'handWriting',

                fileType: 'png',

                quality: 1, //图片质量

                success(res) {

                    // console.log(res.tempFilePath, 'canvas生成图片地址');

                    wx.showToast({

                        title: '执行了吗?',

                    })

                    cb(res.tempFilePath);

                }

            })

        });

    },

    //完成

    subCanvas() {

        // console.log(121);

        /*

            this.data.ctx.draw( true, ()=>{

              wx.canvasToTempFilePath({

                canvasId: 'handWriting',

                fileType: 'png',

                quality: 1, //图片质量

                success(res){

        */

        // console.log(res.tempFilePath, 'canvas生成图片地址');

        /*

                            wx.showModal({

                                title: '哈哈啊',

                                content: '这是什么',

                            })

        */

        /*

                            wx.showToast({

                                title: '以保存',

                            })

        */

        //保存到系统相册

        /*

                            wx.saveImageToPhotosAlbum({

                                filePath: res.tempFilePath,

                                success(res) {

                                    console.log(res,'保存res');

                                    wx.showToast( {

                                        title: '已成功保存到相册',

                                        duration: 2000

                                    } );

                                }

                            })

        */

        /*

                }

              })

            } );

        */

    },

    //保存到相册

    saveCanvasAsImg() {

        console.log(1212);

        wx.canvasToTempFilePath({

            canvasId: 'handWriting',

            fileType: 'png',

            quality: 1, //图片质量

            success(res) {

                // console.log(res.tempFilePath, 'canvas生成图片地址');

                wx.saveImageToPhotosAlbum({

                    filePath: res.tempFilePath,

                    success(res) {

                        wx.showToast({

                            title: '已保存到相册',

                            duration: 2000

                        });

                    }

                })

            }

        })

    },

    //预览

    previewCanvasImg() {

        wx.canvasToTempFilePath({

            canvasId: 'handWriting',

            fileType: 'jpg',

            quality: 1, //图片质量

            success(res) {

                // console.log(res.tempFilePath, 'canvas生成图片地址');

                wx.previewImage({

                    urls: [res.tempFilePath], //预览图片 数组

                })

            }

        })

    },

    //上传

    uploadCanvasImg() {

        // console.log(999);

        wx.canvasToTempFilePath({

            canvasId: 'handWriting',

            fileType: 'png',

            quality: 1, //图片质量

            success(res) {

                // console.log(res.tempFilePath, 'canvas生成图片地址');

                //上传

                wx.uploadFile({

                    url: 'https://example.weixin.qq.com/upload', // 仅为示例,非真实的接口地址

                    filePath: res.tempFilePath,

                    name: 'file_signature',

                    formData: {

                        user: 'test'

                    },

                    success(res) {

                        const data = res.data

                        // do something

                    }

                })

            }

        })

    },

    //设置canvas背景色  不设置  导出的canvas的背景为透明

    //@params:字符串  color

    setCanvasBg(color) {

        console.log(999);

        /* 将canvas背景设置为 白底,不设置  导出的canvas的背景为透明 */

        //rect() 参数说明  矩形路径左上角的横坐标,左上角的纵坐标, 矩形路径的宽度, 矩形路径的高度

        //这里是 canvasHeight - 4 是因为下边盖住边框了,所以手动减了写

        this.data.ctx.rect(0, 0, this.data.canvasWidth, this.data.canvasHeight - 4);

        // ctx.setFillStyle('red')

        this.data.ctx.setFillStyle(color)

        this.data.ctx.fill()  //设置填充

        this.data.ctx.draw()    //开画

    },

    /*======所有自定义函数=END=====*/

})

后期会将其抽离成组件进行使用,实际效果请参考小程序组件库,  Sign in · GitLab  

 


 功能-文字复制

剪切板API

wx.setClipboardData(Object object)

设置系统剪贴板的内容

参数

属性

类型

默认值

必填

说明

datastring剪贴板的内容
successfunction接口调用成功的回调函数
failfunction接口调用失败的回调函数
completefunction接口调用结束的回调函数(调用成功、失败都会执行)

示例代码

wx.setClipboardData({
  data: 'data',
  success(res) {
    wx.getClipboardData({
      success(res) {
        console.log(res.data) // data
      }
    })
  }
})

一键复制

<view>

  <view>{{taokouling||''}}</view>

  <!-- 复制的对象-->

  <button bindtap="copyTBL">一键复制</button>

  <!-- 复制操作 -->

</view>

Page({

  /**

   * 页面的初始数据

   */

  data: {

    taokouling:"这里是需要复制的文字,点击“一键复制”按钮进行复制"

  },

  copyTBL: function (e) {

    var self = this;

    wx.setClipboardData({

      data: self.data.taokouling,

      success: function (res) {

        // self.setData({copyTip:true}),

        wx.showModal({

          title: '提示',

          content: '复制成功',

          success: function (res) {

            if (res.confirm) {

              console.log('确定')

            else if (res.cancel) {

              console.log('取消')

            }

          }

        })

      }

    });

  }

})

长按复制

在微信小程序内的文字无法长按复制,除了text节点以外。但是要在text标签内加一个“selectable”属性。

 <text selectable='true'>< text/>  

text

文本。

属性

类型

默认值

必填

说明

最低版本

selectablebooleanfalse文本是否可选1.1.0
spacestring显示连续空格1.4.0
decodebooleanfalse是否解码1.4.0

<view>

    订单号:

    <text selectable='true' bindlongpress='copy'>{{orderNo}}</text>

    <button bindtap="copyBtn">一键复制</button>

  </view>

Page({

  /**

   * 页面的初始数据

   */

  data: {

    orderNo:"1134341111111111111111dfsgfd",

  },

  /**

  * 长按复制

  */

  copy: function (e) {

    var that = this;

    console.log(e);

    wx.setClipboardData({

      data: that.data.orderNo,

      success: function (res) {

        wx.showToast({

          title: '复制成功',

        });

      }

    });

  },

  /**

  * 一键复制

  */

  copyBtn: function (e) {

    var that = this;

    wx.setClipboardData({

      data: that.data.orderNo,

      success: function (res) {

        wx.showToast({

          title: '复制成功',

        });

      }

    });

  },

})


功能-用户授权

本文主要针对需要授权的功能性api,例如:wx.startRecord,wx.saveImageToPhotosAlbum, wx.getLocation

小程序内如果要调用部分接口需要用户进行授权,例如获取地理位置信息,收获地址,录音等等,但是小程序对于这些需要授权的接口并不是特别友好,最明显的有两点:

  • 如果用户已拒绝授权,则不会出现弹窗,而是直接进入接口 fail 回调
  • 没有统一的错误信息提示,例如错误码

一般情况下每次授权时都应该激活弹窗进行提示,是否进行授权

而小程序内只有第一次进行授权时才会主动激活弹窗(微信提供的),其他情况下都会直接走fail回调,微信文档也在句末添加了一句请开发者兼容用户拒绝授权的场景

这种未做兼容的情况下如果用户想要使用录音功能,第一次点击拒绝授权,那么之后无论如何也无法再次开启录音权限

针对二次授权的解决方案

常见处理方法

先看一下官方的demo

下面这段代码是微信官方提供的授权代码, 可以看到也并没有兼容拒绝过授权的场景查询是否授权(即无法再次调起授权)

// 可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.record" 这个 scope

wx.getSetting({

  success(res) {

    if (!res.authSetting['scope.record']) {

      wx.authorize({

        scope: 'scope.record',

        success () {

          // 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问

          wx.startRecord()

        }

      })

    }

  }

})

一般处理方法

以地理位置信息授权为例:

wx.getLocation({

   success(res) {

      console.log('success', res);

   },

   fail(err) {

      // 检查是否是因为未授权引起的错误

      wx.getSetting({

         success (res) {              

            // 当未授权时直接调用modal窗进行提示

            !res.authSetting['scope.userLocation'] && wx.showModal({

               content: '您暂未开启权限,是否开启',

               confirmColor: '#72bd4a',

               success: res => {             

                  // 用户确认授权后,进入设置列表

                  if (res.confirm) {

                     wx.openSetting({

                        success(res){

                           // 查看设置结果

                           console.log(!!res.authSetting['scope.userLocation'] ? '设置成功' '设置失败');

                        },

                     });

                  }

               }

            });

         }

      });

   }

});

上面代码,可能会对在fail回调里直接使用wx.getSetting有些疑问,这里主要是因为

  • 微信返回的错误信息没有一个统一code
  • errMsg又在不同平台有不同的表现
  • 从埋点数据得出结论,调用这些api接口出错率基本集中在未授权的状态下

这里为了方便就直接调用权限检查了 ,也可以稍微封装一下,方便扩展和复用,变成:

bindGetLocation(e) {

      let that = this;

      wx.getLocation({

          success(res) {

              console.log('success', res);

          },

          fail(err) {

              that.__authorization('scope.userLocation');

          }

      });

  },

  bindGetAddress(e) {

      let that = this;

      wx.chooseAddress({

          success(res) {

              console.log('success', res);

          },

          fail(err) {

              that.__authorization('scope.address');

          }

      });

  },

  __authorization(scope) {

          /** 为了节省行数,不细写了,可以参考上面的fail回调,大致替换了下变量res.authSetting[scope] **/

  }

这里如果只针对较少页面的话已经够用了,不适用调用场景偏多的情况

扩展wx[function]方法

为了节省认知成本和减少出错概率,我希望他是这个api默认携带的功能,也就是说因未授权出现错误时自动调起是否开启授权的弹窗 

需要对wx的原生API进行一层封装

为wx.getLocation添加自己的方法

注:直接使用常见的装饰模式是会出现报错,因为wx这个对象在设置属性时没有设置set方法,这里需要单独处理

// 直接装饰,会报错 Cannot set property getLocation of #<Object> which has only a getter

let $getLocation = wx.getLocation;

wx.getLocation = function (obj) {

    $getLocation(obj); 

};

// 需要做一些小处理

wx = {...wx};                                       //  对wx对象重新赋值

let $getLocation = wx.getLocation;

wx.getLocation = function (obj) {                  

    console.log('调用了wx.getLocation');

    $getLocation(obj); 

};

// 再次调用时会在控制台打印出 '调用了wx.getLocation' 字样

wx.getLocation()

劫持fail方法

第一步我们已经控制了wx.getLocation这个api,接下来就是对于fail方法的劫持,因为我们需要在fail里加入我们自己的授权逻辑

// 方法劫持

wx.getLocation = function (obj) {

    let originFail = obj.fail;

    obj.fail = async function (errMsg) {

        // 0 => 已授权 1 => 拒绝授权 2 => 授权成功

        let authState = await authorization('scope.userLocation');

         

        // 已授权报错说明并不是权限问题引起,所以继续抛出错误

        // 拒绝授权,走已有逻辑,继续排除错误

        authState !== 2 && originFail(errMsg);

    };

    $getLocation(obj);

};

// 定义检查授权方法

function authorization(scope) {

    return new Promise((resolve, reject) => {

        wx.getSetting({

            success (res) {

                !res.authSetting[scope]

                    ? wx.showModal({

                        content: '您暂未开启权限,是否开启',

                        confirmColor: '#72bd4a',

                        success: res => {

                            if (res.confirm) {

                                wx.openSetting({

                                    success(res){

                                        !!res.authSetting[scope] ? resolve(2) : resolve(1)

                                    },

                                });

                            }else {

                                resolve(1);

                            }

                        }

                    })

                    : resolve(0);

            }

        })

    });

}

// 业务代码中的调用

  bindGetLocation(e) {

        let that = this;

        wx.getLocation({

            type: 'wgs84',

            success(res) {

                console.log('success', res);

            },

            fail(err) {

                console.warn('fail', err);

            }

        });

  }

可以看到现在已实现的功能已经达到了我们最开始的预期,即因授权报错作为了wx.getLocation默认携带的功能,我们在业务代码里再也不需要处理任何再次授权的逻辑

也意味着wx.getLocation这个api不论在任何页面,组件,出现频次如何,我们都不需要关心它的授权逻辑


微信小程序-获取手机号code-代码示例

小程序更新后不需要sessionKey、openId、iv和encryptedData传给后端解密

// let param = {

//     encryptedData: e.detail.encryptedData,

//     iv: e.detail.iv,

//     sessionKey: this.data.sessionKey,

//     openId: this.data.openid

// }

通过按钮触发,获取code,后端根据code可拿到手机号

组件使用vant:Vant Weapp - 轻量、可靠的小程序 UI 组件库

wxml内容

wxml

<!--  授权手机号  -->

<van-dialog

        title="需要获取您的手机号进行账号验证"

        show="{{ showPhoneDialog }}"

        show-cancel-button

        bind:cancel="cancelGetPhone"

        confirm-button-open-type="getPhoneNumber"

        bind:getphonenumber="getPhoneNumber">

</van-dialog>

js内容

js

import Dialog from '../../miniprogram_npm/@vant/weapp/dialog/dialog';

import Toast from '../../miniprogram_npm/@vant/weapp/toast/toast';

let utils = require('../../utils/util');

let cache = require('../../utils/wcache');

let router = require('../../router/router');

let http = require('../../api/api');

const app = getApp()

Page({

    data: {

        showPhoneDialog: false,

        phone: ''

    },

    // 获取手机号

    getPhoneNumber(e) {

        console.log(e);

        const { flag } = this.data

        const userInfo = wx.getStorageSync('userInfo')

        if (e.detail.errMsg === "getPhoneNumber:ok") {

            // let param = {

            //     encryptedData: e.detail.encryptedData,

            //     iv: e.detail.iv,

            //     sessionKey: this.data.sessionKey,

            //     openId: this.data.openid

            // }

            const params = {

                code: e.detail.code

            }

            // 发送请求

            http.getPhoneNumber(params)

                .then(res => {

                    const { code, data, message } = res

                    const { errcode, errmsg, phone_info } = data

                    const phone = phone_info.purePhoneNumber

                    if (code === 200) {

                        if (errcode === 0) {

                            this.setData({

                                phone: phone

                            })

                        else {

                            Toast({

                                message: errmsg

                            });

                        }

                    else {

                        Toast({

                            message: message,

                        });

                    }

                })

        else {

            // Toast({

            //     message: '授权失败',

            // })

        }

    },

    // 拒绝获取手机号

    cancelGetPhone() {

        this.setData({

            auth: false

        })

    }

})


微信小程序中生成二维码工具weapp.qrcode.js

一、使用

创建canvas标签

先在 wxml 文件中,创建绘制的 canvas,并定义好 widthheightcanvasId 。由于小程序没有动态创建标签的api,所以这一步不能省略。

<canvas style="width: 200px; height: 200px;" canvas-id="myQrcode"></canvas>

调用绘制方法

由于微信小程序不支持引入NPM包,可以将dist目录下,weapp.qrcode.min.js 拷贝至项目中。

如果你的小程序使用了支持引入NPM包的框架,如 wepy , 也可以直接安装 weapp-qrcode NPM包。

npm install weapp-qrcode --save

引入 js 文件后,调用 drawQrcode() 绘制二维码。

import drawQrcode from 'weapp-qrcode'
// 或者,将 dist 目录下,weapp.qrcode.min.js
// import drawQrcode from '../../utils/weapp.qrcode.min.js'

drawQrcode({
  width: 200,
  height: 200,
  canvasId: 'myQrcode',
  text: 'https://github.com/yingye'
}

API说明

参数

说明

示例

参数

说明

示例

width必须,二维码宽度,与canvaswidth保持一致200
height必须,二维码高度,与canvasheight保持一致200
canvasId必须,绘制的canvasId'myQrcode'
text必须,二维码内容'yingye (yingye) · GitHub'
typeNumber非必须,二维码的计算模式,默认值-18
correctLevel非必须,二维码纠错级别,默认值为高级,取值:{ L: 1, M: 0, Q: 3, H: 2 }1
background非必须,二维码背景颜色,默认值白色'#ffffff'
foreground非必须,二维码前景色,默认值黑色'#000000'

如果想更深入的了解二维码的原理,推荐大家阅读 二维码的生成细节和原理 。

原始文档

GitHub - yingye/weapp-qrcode: weapp.qrcode.js 在 微信小程序 中,快速生成二维码

微信小程序开发常用事例 

一、设置Button透明无边框

.price_detail .img_info button::after {

  bordernone;

}

.price_detail .img_info button {

  backgroundnone;

}

二、设置CheckBox样式为圆形

/* 重写 checkbox 样式 */

/* 未选中的 背景样式 */

checkbox .wx-checkbox-input {

  border-radius: 50%;

  width46rpx;

  height46rpx;

}

/* 选中后的 背景样式 (红色背景 无边框 可根据UI需求自己修改) */

checkbox .wx-checkbox-input .wx-checkbox-input-checked {

  border1rpx solid #ff783b;

  background#ff783b;

}

/* 选中后的 对勾样式 (白色对勾 可根据UI需求自己修改) */

checkbox .wx-checkbox-input .wx-checkbox-input-checked ::before {

  border-radius: 50%;

  width40rpx;

  height40rpx;

  line-height40rpx;

  text-aligncenter;

  font-size30rpx;

  color#fff;

  /* 对勾颜色 白色 */

  backgroundtransparent;

  transform: translate(-50%-50%) scale(1);

  -webkit-transform: translate(-50%-50%) scale(1);

}

三、Text文本内显示空格

先看下效果

使用全角空格即可,Mac 上使用方式如下:

Shift + option + B: 选择全角空格即可

<van-field clearable label="微  信" placeholder="请输入微信号码" />

四、点击左上角返回直接返回首页

/**

   * 生命周期函数--监听页面卸载

   */

  onUnload: function() {

    wx.navigateBack({

      delta: 6

    })

  },

/**

  * 返回首页

  */

  goBackHome: function() {

   wx.switchTab({

     url: '/pages/index/index',

   })

 },

  

/**

 * 生命周期函数--监听页面卸载

 */

 onUnload: function() {

   wx.switchTab({

     url: '/pages/index/index',

   })

 },

附上一张未兼容和已兼容的效果图:

适配步骤:

Step 1: App.js 中检测当前设备是否为 iPhone X

globalData: {

  // 是否为 iPhoneX 以上版本

  isIphoneX: false

},

/**

 * 检测当前设备是否为 iPhone X 及以上

 */

checkIsiPhoneX: function() {

  const self = this

  wx.getSystemInfo({

    success: function(res) {

      // 根据 model 进行判断

      if (res.model.search('iPhone X') != -1) {

        self.globalData.isIphoneX = true

      }

      // 或者根据 screenHeight 进行判断

      // if (res.screenHeight == 812) {

      //   self.globalData.isIphoneX = true

      // }

    }

  })

},

onLaunch: function() {

  // 判断设备是否为 iPhone X 及以上

  this.checkIsiPhoneX()

}

Step 2: 设置兼容以及普通机型下的样式

/* 提交按钮 */

.submit_btn {

  background#d04801;

  color#fff;

  border-radius: 50rpx;

  margin30rpx;

  font-size32rpx;

  padding15rpx;

  bottom0;

  left0;

  right0;

  positionabsolute;

}

/* 点击效果 */

.submit_btn:active {

  opacity: 0.6;

}

/* 提交按钮 iPhone X */

.submit_btn_iPhoneX {

  margin-bottom68rpx;

}

Step 3: 具体的 Page.js 中匹配

const app = getApp()

Page({

  /**

   * 页面的初始数据

   */

  data: {

    isIphoneX: app.globalData.isIphoneX,

  },

}

Step 4: 未指定的控件设置对应的样式兼容

<button class="{{ isIphoneX ? 'submit_btn submit_btn_iPhoneX' :'submit_btn'}}" bindtap="{{phone.length ? 'confirmOrder' : ''}}" open-type="{{phone.length ? '' : 'getPhoneNumber'}}" bindgetphonenumber='bindgetphonenumber'>下一步</button>

功能-微信小程序跳转小程序

一、使用限制

1.需要用户触发跳转

从 2.3.0 版本开始,若用户未点击小程序页面任意位置,则开发者将无法调用此接口自动跳转至其他小程序。

2.需要用户确认跳转

从 2.3.0 版本开始,在跳转至其他小程序前,将统一增加弹窗,询问是否跳转,用户确认后才可以跳转其他小程序。如果用户点击取消,则回调 fail cancel。

3.每个小程序可跳转的其他小程序数量限制为不超过 10 个

从 2.4.0 版本以及指定日期(具体待定)开始,开发者提交新版小程序代码时,如使用了跳转其他小程序功能,则需要在代码配置中声明将要跳转的小程序名单,限定不超过 10 个,否则将无法通过审核。该名单可在发布新版时更新,不支持动态修改。配置方法详见 如下代码。调用此接口时,所跳转的 appId 必须在配置列表中,否则回调 fail appId "${appId}" is not in navigateToMiniProgramAppIdList。

4.关于调试

在开发者工具上调用此 API 并不会真实的跳转到另外的小程序,但是开发者工具会校验本次调用跳转是否成功。详情
开发者工具上支持被跳转的小程序处理接收参数的调试。详情

二、配置详情

app.json文件中 最后一行 是你配置要跳转到的小程序 appid ,最多能配置10个

1

"navigateToMiniProgramAppIdList": ["wxe5f52902cf4de896"]

app.json

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

app.json

{

  "pages": ["pages/index/index""pages/logs/index"],

  "window": {

    "navigationBarTitleText""Demo"

  },

  "tabBar": {

    "list": [

      {

        "pagePath""pages/index/index",

        "text""首页"

      },

      {

        "pagePath""pages/logs/logs",

        "text""日志"

      }

    ]

  },

  "networkTimeout": {

    "request": 10000,

    "downloadFile": 10000

  },

  "debug"true,

  "navigateToMiniProgramAppIdList": ["wxe5f52902cf4de896"]

}

三、使用方法

1.  使用wx.navigateToMiniProgram 打开 。wx.navigateToMiniProgram 官方api

    如果你打开之后想返回之前的小程序 使用 wx.navigateBackMiniProgram 返回之前小程序api 

     注意:返回到上一个小程序。只有在当前小程序是被其他小程序打开时可以调用成功  。   

1

2

3

4

5

6

7

8

9

10

11

wx.navigateToMiniProgram({

  appId: '',//要打开的小程序 appId

  path: 'page/index/index?id=123',//打开的页面路径,如果为空则打开首页

  extraData: {

    foo: 'bar'//需要传递给目标小程序的数据,目标小程序可在 App.onLaunch,App.onShow 中获取到这份数据

  },

  envVersion: 'develop',//要打开的小程序版本。仅在当前小程序为开发版或体验版时此参数有效。如果当前小程序是正式版,则打开的小程序必定是正式版。

  success(res) {

    // 打开成功

  }

})

2. 使用 navigator 组件

1

<navigator target="miniProgram" open-type="navigate" app-id="" path="" extra-data="" version="release">打开绑定的小程序</navigator>

功能-小程序间跳转

打开另一个小程序

示例代码

navigateToMiniProgram() {

    wx.navigateToMiniProgram({

        appId: '',

        path: 'page/index/index?id=123',

    extraData: {

         foo: 'bar'

    },

    envVersion: 'develop',

    success(res) {

        // 打开成功

    }

    })

}

参数

属性

类型

默认值

必填

说明

appIdstring要打开的小程序 appId
pathstring打开的页面路径,如果为空则打开首页。path 中 ? 后面的部分会成为 query,在小程序的 App.onLaunchApp.onShow 和 Page.onLoad 的回调函数或小游戏的 wx.onShow 回调函数、wx.getLaunchOptionsSync 中可以获取到 query 数据。对于小游戏,可以只传入 query 部分,来实现传参效果,如:传入 "?foo=bar"。
extraDataobject需要传递给目标小程序的数据,目标小程序可在 App.onLaunchApp.onShow 中获取到这份数据。如果跳转的是小游戏,可以在 wx.onShowwx.getLaunchOptionsSync 中可以获取到这份数据数据。
envVersionstringrelease要打开的小程序版本。仅在当前小程序为开发版或体验版时此参数有效。如果当前小程序是正式版,则打开的小程序必定是正式版。
successfunction接口调用成功的回调函数
failfunction接口调用失败的回调函数
completefunction接口调用结束的回调函数(调用成功、失败都会执行)

object.envVersion 的合法值

说明

最低版本

develop开发版
trial体验版
release正式版

还需要在本小程序app.json里声明要跳转到的小程序的appid

 

使用限制

需要用户触发跳转

从 2.3.0 版本开始,若用户未点击小程序页面任意位置,则开发者将无法调用此接口自动跳转至其他小程序。

需要用户确认跳转从 2.3.0 版本开始,在跳转至其他小程序前,将统一增加弹窗,询问是否跳转,用户确认后才可以跳转其他小程序。如果用户点击取消,则回调 fail cancel。

每个小程序可跳转的其他小程序数量限制为不超过 10 个

从 2.4.0 版本以及指定日期(具体待定)开始,开发者提交新版小程序代码时,如使用了跳转其他小程序功能,则需要在代码配置中声明将要跳转的小程序名单,限定不超过 10 个,否则将无法通过审核。该名单可在发布新版时更新,不支持动态修改。配置方法详见 配置。调用此接口时,所跳转的 appId 必须在配置列表中,否则回调 fail appId "${appId}" is not in navigateToMiniProgramAppIdList。

功能-小程序swiper组件实现间距轮播

先看三种效果图(效果图是copy网上资源,代码亲测有效)

效果一

 

效果二

 

效果三

 

小程序swiper 滑动的时候,滑来滑去会卡在中间,跳转到其他页面返回还是会卡在这里,猜测是轮播瞎标的问题,解决办法,在onshow中初始化下标

this.setData({

     current: 1,

 })

前两种都是通过css实现的

第一种 普通间隔轮播

wxml

<view class='test'>

    <swiper  display-multiple-items='1'>    // 这里是设置显示一张

      <block wx:for="{{imgUrls}}">             // 遍历js中的图片

        <swiper-item>                                 // box外层swiper

          <view class='box'>                      // 重点处理box

            <image src='{{item}}'></image>

            <view class='content'>

              <text>测试</text>

            </view>

          </view>

        </swiper-item>

      </block>

    </swiper>

</view>

wxss

.test{

  width100%;

  height100vh;

  box-sizing: border-box;

}

swiper{

  height100%;

}

.content{

  font-size16px;

  color#333;

  padding20rpx 40rpx;

}

swiper-item{                            // 此时的swiper-item是占据一个页面的

  text-aligncenter;                  // 让其中的内容居中显示

}

swiper-item image{

  width100%;

}

.box{                               // box设置宽高(更具设计稿自定义吧)

  width80%;

  height700rpx;

  display: inline-block;

  margin-top40px;

  box-sizing: border-box;

  box-shadow: 0 0 4px 4px #f2f2f2;  // 给box添加阴影效果更显著

}

swiper利用display-multiple-items='1’属性 一次展示一张
swiper-item添加内容居中
内容设置宽高
最后就可以得到一次一张且有间距的轮播图

第二种  带边界的间隔轮播

依旧照着上面的css,改一下box的宽度即可,按照效果图进行更改

.box{

  width90%;

  }

然后在swiper组件上加两个属性,来达到预留空间给里面的box。再加上circular属性衔接滑动。

 

第三种效果  两边小,中间大动画轮播

wxml

<view class='test'>

    <swiper  display-multiple-items='1' circular previous-margin='50px' next-margin='50px' bindchange='change' current='{{current}}'>

      <block wx:for="{{imgUrls}}" wx:key='{{index}}'>

        <swiper-item>

          <view class="box" data-index='{{index}}' animation="{{index == current?animationData:animationData2}}">

            <image src='{{item}}'></image>

            <view class='content'>

              <text>测试</text>

              <text>测试</text>

            </view>

          </view>

        </swiper-item>

      </block>

    </swiper>

</view>

wxss

.test{

  width100%;

  height100vh;

  box-sizing: border-box;

}

swiper{

  height100%;

}

.content{

  font-size16px;

  color#333;

  padding20rpx 40rpx;

}

swiper-item{

  text-aligncenter;

}

swiper-item image{

  width100%;

}

.box{

  width90%;

  height:600rpx;

  display: inline-block;

  margin-top40px;

  box-sizing: border-box;

  box-shadow: 0 0 4px 4px #f2f2f2;

  position:relative;

  top:33%;

  transform:translateY(-45%);

}

js利用animate来过渡动画,当下标相同时执行放大动画

Page({

  /**

   * 页面的初始数据

   */

  data: {

    imgUrls: [

      'http://img02.tooopen.com/images/20150928/tooopen_sy_143912755726.jpg',

      'http://img06.tooopen.com/images/20160818/tooopen_sy_175866434296.jpg',

      'http://img06.tooopen.com/images/20160818/tooopen_sy_175833047715.jpg'

    ],

    current: 0,

    animationData: {},

    animationData2: {}

  },

  /**

   * 生命周期函数--监听页面加载

   */

  onLoad: function (options) {

    this.stretch(350)

  },

  change(e){

    this.setData({

      current: e.detail.current

    })

    this.stretch(350)

     

    this.shrink(300)

  },

  // 收缩

  stretch(h){

    var animation = wx.createAnimation({

      duration: 1000,

      timingFunction: 'ease',

    })

    this.animation = animation

    animation.height(h).step()

    this.setData({

      animationData: animation.export(),

    })

  },

  // 展开

  shrink(h){

    var animation2 = wx.createAnimation({

      duration: 1000,

      timingFunction: 'ease',

    })

    this.animation2 = animation2

    animation2.height(h).step()

    this.setData({

      animationData2: animation2.export()

    })

  },

})

功能-腾讯云慧眼人脸核果

一、进行腾讯云慧眼人脸核身试用申请

原文链接 登录 - 腾讯云

二、嵌入式的SDK开发

创建申请对应的小程序业务流程,下载对应业务流程的SDK文件到小程序开发目录下,引入实名方法

三、腾讯云慧眼控制台创建业务流程

腾讯云慧眼控制台

进行小程序的相关信息填写


 

接入流程的配置

选择对比源

选择身份证信息获取方式

活体检测方式

结果页面配置

选择完成,点击下一步即可完成配置

配置完成就可以在我们的业务服务列表中,看到我们的待审核业务流程

至此我们的业务流程已配置完成

四、整体接入流程及原理

参考微信小程序接入文档 

1、业务后端调用 DetectAuth 进行核身前鉴权,获取业务流水号(BizToken)

2、根据业务逻辑需求,在需要实名的入口进入实名核身流程。前台获取后端返回的BizToken 按照小程序SDK进行接入

3、人脸核身完成后,流程会回调到客户前端,SDK是以回调函数形式返回,成功的回调中会再次返回BizToken,后端通过BizToken调用 GetDetectInfo 接口获取本次核身的详细信息

五、SDK接入使用

1、首先下载流程的sdk文件到开发目录中,利用require引入文件

2、初始化慧眼实名核身SDK

在 app.js 的 onLaunch() 中加入相应代码,在 app.json 文件里添加活体验证页面verify_mpsdk/index/index

//app.js

App({

 onLaunch: function () {

     // 初始化慧眼实名核身组件

     const Verify = require('/verify_mpsdk/main');

     Verify.init();

 }

})

// app.json

{

 "pages":[

     "verify_mpsdk/index/index"

 ]

}

3、调用 SDK 功能函数 wx.startVerify()

在需要实名认证的地方调用 wx.startVerify() 进入实名认证页面,认证完成会触发对应的回调函数。

// 单击某个按钮时,触发该函数

gotoVerify: function () {

 let BizToken = getBizToken();// 去客户后端调用DetectAuth接口获取BizToken

 // 调用实名核身功能

 wx.startVerify({

     data: {

         token: BizToken // BizToken

     },

     success: (res) => { // 验证成功后触发

         // res 包含验证成功的token, 这里需要加500ms延时,防止iOS下不执行后面的逻辑

         setTimeout(() => {

             // 验证成功后,拿到token后的逻辑处理,具体以客户自身逻辑为准

         }, 500);

     },

     fail: (err) => {  // 验证失败时触发

         // err 包含错误码,错误信息,弹窗提示错误

         setTimeout(() => {

             wx.showModal({

                 title: "提示",

                 content: err.ErrorMsg,

                 showCancel: false

             })

         }, 500);

     }

 });

}

4、添加域名服务器白名单。

将这两个域名加入小程序的与域名白名单中

faceid.qq.com、btrace.qq.com

六、基本API描述

  • Verify.init(options):初始化插件。
    • options:Obejct required 初始化的参数。
    • options.env:String required 接口环境。正式环境为 release,开发环境为 dev。
  • wx.startVerify(options):进入实名认证页面。
    • options:Object required 初始化的参数。
    • options.data.token:String required 客户后端调用 DetectAuth 接口获取的 BizToken。
    • options.success:Function(res) required 验证成功的回调。res 包含验证成功的 token。
    • options.fail:Function(err) required 验证失败的回调。err 包含错误码、错误信息。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值