主頁 > 企業開發 > 記錄--uni-app實作藍牙列印小票

記錄--uni-app實作藍牙列印小票

2022-09-14 06:51:20 企業開發

這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

說明

基于uni-app開發,呼叫官方藍牙相關api實作連接藍牙與向藍牙熱敏列印機發送位元組流,可列印文字,二維碼,圖片,調整字體大小等,本文提供大概思路

結構

image.png

  • bluetooth.js 藍牙連接相關模塊封裝
  • commands.js 列印十六進制相關代碼庫
  • gbk.js 編碼轉換庫地址
  • printerjobs.js 列印實作庫

bluetooth.js

藍牙連接相關封裝代碼

class Bluetooth {

    constructor() {
        this.isOpenBle = false;
        this.deviceId = "";
        this.serviceId = "";
        this.writeId = "";
        this.notifyId = "";
        this.BluetoothConnectStatus = false this.printStatus = false this.init()
    }
    init() {
        this.closeBluetoothAdapter().then(() = >{
            console.log("init初始關閉藍牙模塊") this.openBluetoothAdapter().then(() = >{
                console.log("init初始化藍牙模塊") this.reconnect() //自動連接藍牙設備
            })

        })
    }

    showToast(title) {
        uni.showToast({
            title: title,
            icon: 'none',
            'duration': 2000
        });
    }

    openBluetoothAdapter() {
        return new Promise((resolve, reject) = >{
            uni.openBluetoothAdapter({
                success: res = >{
                    this.isOpenBle = true;
                    resolve(res);
                },
                fail: err = >{
                    this.showToast(`藍牙未打開`);
                    reject(err);
                },
            });
        });

    }

    startBluetoothDevicesDiscovery() {
        if (!this.isOpenBle) {
            this.showToast(`初始化藍牙模塊失敗`) return;
        }

        let self = this;
        uni.showLoading({
            title: '藍牙搜索中'
        }) return new Promise((resolve, reject) = >{
            setTimeout(() = >{
                uni.startBluetoothDevicesDiscovery({
                    success: res = >{
                        resolve(res)
                    },
                    fail: res = >{
                        self.showToast(`搜索設備失敗` + JSON.stringify(err));
                        reject(err);
                    }
                })
            },
            300);
        });
    }

    stopBluetoothDevicesDiscovery() {
        let self = this;
        return new Promise((resolve, reject) = >{
            uni.stopBluetoothDevicesDiscovery({
                success: e = >{
                    uni.hideLoading();
                },
                fail: e = >{
                    uni.hideLoading();
                    self.showToast(`停止搜索藍牙設備失敗` + JSON.stringify(err));
                }
            })
        });
    }

    createBLEConnection() {
        //設備deviceId
        let deviceId = this.deviceId;
        let self = this;

        // uni.showLoading({
        // 	mask: true,
        // 	title: '設別連接中,請稍候...'
        // })
        console.log(this.deviceId);
        return new Promise((resolve, reject) = >{
            uni.createBLEConnection({
                deviceId,
                success: (res) = >{
                    console.log("res:createBLEConnection " + JSON.stringify(res));
                    resolve(res)
                },
                fail: err = >{
                    uni.hideLoading();
                    self.showToast(`停止搜索藍牙設備失敗` + JSON.stringify(err));
                    reject(err);
                }
            })
        });
    }

    //獲取藍牙設備所有服務(service)
    getBLEDeviceServices() {
        let _serviceList = [];
        let deviceId = this.deviceId;
        let self = this;

        return new Promise((resolve, reject) = >{
            setTimeout(() = >{
                uni.getBLEDeviceServices({
                    deviceId,
                    success: res = >{
                        for (let service of res.services) {
                            if (service.isPrimary) {
                                _serviceList.push(service);
                            }
                        }
                        uni.hideLoading();
                        console.log("_serviceList: " + JSON.stringify(_serviceList));
                        resolve(_serviceList)
                    },
                    fail: err = >{
                        uni.hideLoading();
                        // self.showToast(`獲取設備Services` + JSON.stringify(err));
                        reject(err);
                    },
                })
            },
            500);
        });
    }

    //獲取藍牙設備某個服務中所有特征值(characteristic)
    getBLEDeviceCharacteristics() {
        // console.log("getBLEDeviceCharacteristics")
        let deviceId = this.deviceId;
        let serviceId = this.serviceId;

        let self = this;
        return new Promise((resolve, reject) = >{
            uni.getBLEDeviceCharacteristics({
                deviceId,
                serviceId,
                success: res = >{
                    for (let _obj of res.characteristics) {
                        //獲取notify
                        if (_obj.properties.notify) {
                            self.notifyId = _obj.uuid;
                            uni.setStorageSync('notifyId', self.notifyId);
                        }
                        //獲取writeId
                        if (_obj.properties.write) {
                            self.writeId = _obj.uuid;
                            uni.setStorageSync('writeId', self.writeId);
                        }
                    }

                    //console.log("res:getBLEDeviceCharacteristics " + JSON.stringify(res));
                    let result = {
                        'notifyId': self.notifyId,
                        'writeId': self.writeId
                    };
                    // self.showToast(`獲取服務中所有特征值OK,${JSON.stringify(result)}`);
                    this.BluetoothStatus = true resolve(result)
                },
                fail: err = >{
                    self.showToast(`getBLEDeviceCharacteristics` + JSON.stringify(err));
                    reject(err);
                }
            })
        });
    }

    //斷開聯鏈接
    closeBLEConnection() {
        let deviceId = this.deviceId;
        uni.closeBLEConnection({
            deviceId,
            success(res) {
                console.log("closeBLEConnection" + res)
            }
        })
    }

    notifyBLECharacteristicValue() {
        let deviceId = this.deviceId;
        let serviceId = this.serviceId;
        let characteristicId = this.notifyId;

        uni.notifyBLECharacteristicValueChange({
            state: true,
            // 啟用 notify 功能
            deviceId,
            serviceId,
            characteristicId,
            success(res) {
                uni.onBLECharacteristicValueChange(function(res) {
                    console.log('onBLECharacteristicValueChange', res);
                });
            },
            fail(res) {
                console.log('notifyBLECharacteristicValueChange failed:' + res.errMsg);

            }
        });
    }

    writeBLECharacteristicValue(buffer) {
        let deviceId = this.deviceId;
        let serviceId = this.serviceId;
        let characteristicId = this.writeId;

        // console.log(deviceId);
        // console.log(serviceId);
        // console.log(characteristicId);
        return new Promise((resolve, reject) = >{
            uni.writeBLECharacteristicValue({
                deviceId,
                serviceId,
                characteristicId,
                value: buffer,
                success(res) {
                    // console.log('message發送成功', JSON.stringify(res));
                    resolve(res);
                },
                fail(err) {
                    // console.log('message發送失敗', JSON.stringify(err));
                    reject(err);
                }
            });
        });
    }

    closeBluetoothAdapter() {
        return new Promise((resolve, reject) = >{
            uni.closeBluetoothAdapter({
                success: res = >{
                    resolve()
                }
            });
        })

    }

    //若APP在之前已有搜索過某個藍牙設備,并成功建立連接,可直接傳入之前搜索獲取的 deviceId 直接嘗試連接該設備,無需進行搜索操作,
    reconnect() { (async() = >{
            try {
                this.deviceId = this.deviceId || uni.getStorageSync("deviceId");
                this.serviceId = this.serviceId || uni.getStorageSync("serviceId");
                console.log("this.deviceId", this.deviceId) console.log("this.serviceId", this.serviceId) let result1 = await this.createBLEConnection();
                console.log("createBLEConnection: " + JSON.stringify(result1));

                let result2 = await this.getBLEDeviceServices();
                console.log("getBLEDeviceServices: " + JSON.stringify(result2));

                let result3 = await this.getBLEDeviceCharacteristics();
                console.log("getBLEDeviceCharacteristics: " + JSON.stringify(result3));
                this.BluetoothConnectStatus = true this.showToast("藍牙列印設備連接成功")
                // this.writeId = uni.getStorageSync("writeId");
                // this.notifyId = uni.getStorageSync("notifyId");
            } catch(err) {
                console.log("err: " + err);
                // this.showToast("藍牙列印設備連接失敗")
            }

        })();
    }
}

export
default Bluetooth;

commands.js

列印機ESC/POS十六進制編碼庫

/**
 * 修改自https://github.com/song940/node-escpos/blob/master/commands.js
 * ESC/POS _ (Constants)
 */
var _ = {
  LF: [0x0a],
  FS: [0x1c],
  FF: [0x0c],
  GS: [0x1d],
  DLE: [0x10],
  EOT: [0x04],
  NUL: [0x00],
  ESC: [0x1b],
  EOL: '\n',
};

/**
 * [FEED_CONTROL_SEQUENCES Feed control sequences]
 * @type {Object}
 */
_.FEED_CONTROL_SEQUENCES = {
  CTL_LF: [0x0a],   // Print and line feed
  CTL_GLF: [0x4a, 0x00],   // Print and feed paper (without spaces between lines)
  CTL_FF: [0x0c],   // Form feed
  CTL_CR: [0x0d],   // Carriage return
  CTL_HT: [0x09],   // Horizontal tab
  CTL_VT: [0x0b],   // Vertical tab
};

_.CHARACTER_SPACING = {
  CS_DEFAULT: [0x1b, 0x20, 0x00],
  CS_SET: [0x1b, 0x20]
};

_.LINE_SPACING = {
  LS_DEFAULT: [0x1b, 0x32],
  LS_SET: [0x1b, 0x33]
};

/**
 * [HARDWARE Printer hardware]
 * @type {Object}
 */
_.HARDWARE = {
  HW_INIT: [0x1b, 0x40], // Clear data in buffer and reset modes
  HW_SELECT: [0x1b, 0x3d, 0x01], // Printer select
  HW_RESET: [0x1b, 0x3f, 0x0a, 0x00], // Reset printer hardware
  Print:[0x1b, 0x64,0x01] //Print and feed paper
};

/**
 * [CASH_DRAWER Cash Drawer]
 * @type {Object}
 */
_.CASH_DRAWER = {
  CD_KICK_2: [0x1b, 0x70, 0x00], // Sends a pulse to pin 2 []
  CD_KICK_5: [0x1b, 0x70, 0x01], // Sends a pulse to pin 5 []
};

/**
 * [MARGINS Margins sizes]
 * @type {Object}
 */
_.MARGINS = {
  BOTTOM: [0x1b, 0x4f], // Fix bottom size
  LEFT: [0x1b, 0x6c], // Fix left size
  RIGHT: [0x1b, 0x51], // Fix right size
};

/**
 * [PAPER Paper]
 * @type {Object}
 */
_.PAPER = {
  PAPER_FULL_CUT: [0x1d, 0x56, 0x00], // Full cut paper
  PAPER_PART_CUT: [0x1d, 0x56, 0x01], // Partial cut paper
  PAPER_CUT_A: [0x1d, 0x56, 0x41], // Partial cut paper
  PAPER_CUT_B: [0x1d, 0x56, 0x42], // Partial cut paper
};

/**
 * [TEXT_FORMAT Text format]
 * @type {Object}
 */
_.TEXT_FORMAT = {
  TXT_NORMAL: [0x1b, 0x21, 0x00], // Normal text
  TXT_2HEIGHT: [0x1b, 0x21, 0x10], // Double height text
  TXT_2WIDTH: [0x1b, 0x21, 0x20], // Double width text
  TXT_4SQUARE: [0x1b, 0x21, 0x30], // Double width & height text

  TXT_UNDERL_OFF: [0x1b, 0x2d, 0x00], // Underline font OFF
  TXT_UNDERL_ON: [0x1b, 0x2d, 0x01], // Underline font 1-dot ON
  TXT_UNDERL2_ON: [0x1b, 0x2d, 0x02], // Underline font 2-dot ON
  TXT_BOLD_OFF: [0x1b, 0x45, 0x00], // Bold font OFF
  TXT_BOLD_ON: [0x1b, 0x45, 0x01], // Bold font ON
  TXT_ITALIC_OFF: [0x1b, 0x35], // Italic font ON
  TXT_ITALIC_ON: [0x1b, 0x34], // Italic font ON

  TXT_FONT_A: [0x1b, 0x4d, 0x00], // Font type A
  TXT_FONT_B: [0x1b, 0x4d, 0x01], // Font type B
  TXT_FONT_C: [0x1b, 0x4d, 0x02], // Font type C

  TXT_ALIGN_LT: [0x1b, 0x61, 0x00], // Left justification
  TXT_ALIGN_CT: [0x1b, 0x61, 0x01], // Centering
  TXT_ALIGN_RT: [0x1b, 0x61, 0x02], // Right justification
};

/**
 * [BARCODE_FORMAT Barcode format]
 * @type {Object}
 */
_.BARCODE_FORMAT = {
  BARCODE_TXT_OFF: [0x1d, 0x48, 0x00], // HRI barcode chars OFF
  BARCODE_TXT_ABV: [0x1d, 0x48, 0x01], // HRI barcode chars above
  BARCODE_TXT_BLW: [0x1d, 0x48, 0x02], // HRI barcode chars below
  BARCODE_TXT_BTH: [0x1d, 0x48, 0x03], // HRI barcode chars both above and below

  BARCODE_FONT_A: [0x1d, 0x66, 0x00], // Font type A for HRI barcode chars
  BARCODE_FONT_B: [0x1d, 0x66, 0x01], // Font type B for HRI barcode chars

  BARCODE_HEIGHT: function (height) { // Barcode Height [1-255]
    return [0x1d, 0x68, height];
  },
  BARCODE_WIDTH: function (width) {   // Barcode Width  [2-6]
    return [0x1d, 0x77, width];
  },
  BARCODE_HEIGHT_DEFAULT: [0x1d, 0x68, 0x64], // Barcode height default:100
  BARCODE_WIDTH_DEFAULT: [0x1d, 0x77, 0x01], // Barcode width default:1

  BARCODE_UPC_A: [0x1d, 0x6b, 0x00], // Barcode type UPC-A
  BARCODE_UPC_E: [0x1d, 0x6b, 0x01], // Barcode type UPC-E
  BARCODE_EAN13: [0x1d, 0x6b, 0x02], // Barcode type EAN13
  BARCODE_EAN8: [0x1d, 0x6b, 0x03], // Barcode type EAN8
  BARCODE_CODE39: [0x1d, 0x6b, 0x04], // Barcode type CODE39
  BARCODE_ITF: [0x1d, 0x6b, 0x05], // Barcode type ITF
  BARCODE_NW7: [0x1d, 0x6b, 0x06], // Barcode type NW7
  BARCODE_CODE93: [0x1d, 0x6b, 0x48], // Barcode type CODE93
  BARCODE_CODE128: [0x1d, 0x6b, 0x49], // Barcode type CODE128
};

/**
 * [IMAGE_FORMAT Image format]
 * @type {Object}
 */
_.IMAGE_FORMAT = {
  S_RASTER_N: [0x1d, 0x76, 0x30, 0x00], // Set raster image normal size
  S_RASTER_2W: [0x1d, 0x76, 0x30, 0x01], // Set raster image double width
  S_RASTER_2H: [0x1d, 0x76, 0x30, 0x02], // Set raster image double height
  S_RASTER_Q: [0x1d, 0x76, 0x30, 0x03], // Set raster image quadruple
};

/**
 * [BITMAP_FORMAT description]
 * @type {Object}
 */
_.BITMAP_FORMAT = {
  BITMAP_S8: [0x1b, 0x2a, 0x00],
  BITMAP_D8: [0x1b, 0x2a, 0x01],
  BITMAP_S24: [0x1b, 0x2a, 0x20],
  BITMAP_D24: [0x1b, 0x2a, 0x21]
};

/**
 * [GSV0_FORMAT description]
 * @type {Object}
 */
_.GSV0_FORMAT = {
  GSV0_NORMAL: [0x1d, 0x76, 0x30, 0x00],
  GSV0_DW: [0x1d, 0x76, 0x30, 0x01],
  GSV0_DH: [0x1d, 0x76, 0x30, 0x02],
  GSV0_DWDH: [0x1d, 0x76, 0x30, 0x03]
};

/**
 * [BEEP description]
 * @type {string}
 */
_.BEEP = [0x1b, 0x42]; // Printer Buzzer pre hex

/**
 * [COLOR description]
 * @type {Object}
 */

_.COLOR = {
  0: [0x1b, 0x72, 0x00], // black
  1: [0x1b, 0x72, 0x01] // red
};

/**
 * [exports description]
 * @type {[type]}
 */
module.exports = _;

printerjobs.js

const commands = require('./commands');
const gbk = require('./gbk');

const printerJobs = function() {
	this._queue = Array.from(commands.HARDWARE.HW_INIT);
	this._enqueue = function(cmd) {
		this._queue.push.apply(this._queue, cmd);
	}
};

/**
 * 增加列印內容
 * @param  {string} content  文字內容
 */
printerJobs.prototype.text = function(content) {
	if (content) {
		let uint8Array = gbk.encode(content);
		let encoded = Array.from(uint8Array);
		this._enqueue(encoded);
	}
	return this;
};

/**
 * 列印文字
 * @param  {string} content  文字內容
 */
printerJobs.prototype.print = function(content) {
	this.text(content);
	// this._enqueue(commands.LF);
	return this;
};
printerJobs.prototype.printL = function(content) {
	this.text(content);
	this._enqueue(commands.LF);
	return this;
};

printerJobs.prototype.printImage = function(content) {

	if (content) {
		const cmds = [].concat([29, 118, 48, 0], content);
		// console.log("cmds",cmds)
		this._enqueue(cmds);
		this._enqueue(commands.LF);
	}

	return this;
};


/**
 * 列印文字并換行
 * @param  {string}  content  文字內容
 */
printerJobs.prototype.println = function(content = '') {
	return this.print(content + commands.EOL);
};

/**
 * 設定對齊方式
 * @param {string} align 對齊方式 LT/CT/RT
 */
printerJobs.prototype.setAlign = function(align) {
	this._enqueue(commands.TEXT_FORMAT['TXT_ALIGN_' + align.toUpperCase()]);
	return this;
};

/**
 * 設定字體
 * @param  {string} family A/B/C
 */
printerJobs.prototype.setFont = function(family) {
	this._enqueue(commands.TEXT_FORMAT['TXT_FONT_' + family.toUpperCase()]);
	return this;
};

/**
 * 設定字體尺寸
 * @param  {number} width 字體寬度 1~2
 * @param  {number} height 字體高度 1~2
 */
printerJobs.prototype.setSize = function(width, height) {
	if (2 >= width && 2 >= height) {
		this._enqueue(commands.TEXT_FORMAT.TXT_NORMAL);
		if (2 === width && 2 === height) {
			this._enqueue(commands.TEXT_FORMAT.TXT_4SQUARE);
		} else if (1 === width && 2 === height) {
			this._enqueue(commands.TEXT_FORMAT.TXT_2HEIGHT);
		} else if (2 === width && 1 === height) {
			this._enqueue(commands.TEXT_FORMAT.TXT_2WIDTH);
		}
	}
	return this;
};

/**
 * 設定字體是否加粗
 * @param  {boolean} bold
 */
printerJobs.prototype.setBold = function(bold) {
	if (typeof bold !== 'boolean') {
		bold = true;
	}
	this._enqueue(bold ? commands.TEXT_FORMAT.TXT_BOLD_ON : commands.TEXT_FORMAT.TXT_BOLD_OFF);
	return this;
};

/**
 * 設定是否開啟下劃線
 * @param  {boolean} underline
 */
printerJobs.prototype.setUnderline = function(underline) {
	if (typeof underline !== 'boolean') {
		underline = true;
	}
	this._enqueue(underline ? commands.TEXT_FORMAT.TXT_UNDERL_ON : commands.TEXT_FORMAT.TXT_UNDERL_OFF);
	return this;
};

/**
 * 設定行間距為 n 點行,默認值行間距是 30 點
 * @param {number} n 0≤n≤255
 */
printerJobs.prototype.setLineSpacing = function(n) {
	if (n === undefined || n === null) {
		this._enqueue(commands.LINE_SPACING.LS_DEFAULT);
	} else {
		this._enqueue(commands.LINE_SPACING.LS_SET);
		this._enqueue([n]);
	}
	return this;
};

/**
 * 列印空行
 * @param {number} n
 */
printerJobs.prototype.lineFeed = function(n = 1) {
	return this.print(new Array(n).fill(commands.EOL).join(''));
};

/**
 *  設定字體顏色,需要列印機支持
 *  @param  {number} color - 0 默認顏色黑色 1 紅色
 */
printerJobs.prototype.setColor = function(color) {
	this._enqueue(commands.COLOR[color === 1 ? 1 : 0]);
	return this;
};

/**
 * https://support.loyverse.com/hardware/printers/use-the-beeper-in-a-escpos-printers
 * 蜂鳴警報,需要列印機支持
 * @param  {number} n    蜂鳴次數,1-9
 * @param  {number} t 蜂鳴長短,1-9
 */
printerJobs.prototype.beep = function(n, t) {
	this._enqueue(commands.BEEP);
	this._enqueue([n, t]);
	return this;
};

/**
 * 清空任務
 */
printerJobs.prototype.clear = function() {
	this._queue = Array.from(commands.HARDWARE.HW_RESET);
	// this._enqueue(commands.HARDWARE.Print);
	return this;
};

/**
 * 回傳ArrayBuffer
 */
printerJobs.prototype.buffer = function() {
	return new Uint8Array(this._queue).buffer;
};

module.exports = printerJobs;

代碼實作

封裝藍牙連接,搜索,斷開相關操作模塊

藍牙搜索

startBluetoothDeviceDiscovery() {
    let self = this;
    self.tempDeviceList = [];

    uni.startBluetoothDevicesDiscovery({
        success: res = >{
            uni.onBluetoothDeviceFound(devices = >{
                // console.log("發現設備: " + JSON.stringify(devices));
                if (!self.tempDeviceList.some(item = >{
                    return item.deviceId === devices.devices[0].deviceId || item.name === devices.devices[0].name
                })) {
                    // console.log("new", devices.devices)
                    self.tempDeviceList.push(devices.devices[0])
                }
            });

            this.connect = false this.$refs.popup.open()
        },
        fail: err = >{
            uni.showToast({
                title: '搜索設備失敗' + JSON.stringify(err),
                icon: 'none'
            })
        }
    })
},

搜索完成選擇設備

async select_deviceId(item) {
    this.deviceId = item.deviceId;
    this.$bluetooth.deviceId = item.deviceId;
    uni.setStorageSync('deviceId', this.$bluetooth.deviceId);
    this.serviceList = [];

    try {
        //1.鏈接設備
        let result = await this.$bluetooth.createBLEConnection();
        //2.尋找服務
        let result2 = null setTimeout(async() = >{
            result2 = await this.$bluetooth.getBLEDeviceServices();
            console.log("獲取服務: " + JSON.stringify(result2));
            this.serviceList = result2;

            console.log("serviceList", this.serviceList.length)

            if (this.serviceList[2].uuid) {
                this.select_service(this.serviceList[2].uuid)
            } else {
                uni.showToast({
                    title: '不是列印設備',
                    icon: 'none'
                })
            }

        },
        1000)

    } catch(e) {
        //TODO handle the exception
        console.log("e: " + JSON.stringify(e));
    }
},

選中服務

async select_service(res) {
    console.log("select_service", res)

    this.$bluetooth.serviceId = res;
    console.log("this.$bluetooth.serviceId", this.$bluetooth.serviceId) uni.setStorageSync('serviceId', res);

    try {
        let result = await this.$bluetooth.getBLEDeviceCharacteristics();
        console.log("resultresult", result) this.$refs.popup.close()

        uni.showToast({
            title: "連接成功"
        })
        // this.pickUpOnce()
    } catch(e) {
        //TODO handle the exception
        console.log("e: " + JSON.stringify(e));
    }
},

列印內容組合

async writeBLECharacteristicValueTongzhishu() {
	let Qrcode_res = await this.get_Qrcode()
	let sign = await this.getSign()
	console.log("sign")
	let printerJobs = new PrinterJobs()
	let p = printerJobs.setAlign('ct')
		.setBold(true)
		.printL("列印測驗")

	let buffer = printerJobs.buffer();
	this.printbuffs(buffer);
},

列印內容組合

主要是實作列印編碼推送回圈,手機藍牙可能出現編碼發送失敗情況,這個時候就是要回圈保證每個位元組準確推送

printbuffs(buffer, fun) {
    console.log("printbuffs", buffer.byteLength) const maxChunk = 8;
    let p = Promise.resolve();
    for (let i = 0, j = 0, length = buffer.byteLength; i < length; i += maxChunk, j++) {
        let subPackage = buffer.slice(i, i + maxChunk <= length ? (i + maxChunk) : length);
        p = p.then(() = >{
            if (i == 0) {
                this.$bluetooth.printStatus = true this.$refs.loading.open();

            }
            if ((i + maxChunk) >= length) {
                console.log("printEnd")

                setTimeout(() = >{
                    this.$bluetooth.printStatus = false this.$refs.loading.close();
                },
                1000)
            }
            return this.printbuff(subPackage)
        })
    }
    p = p.then(() = >{
        console.log("printEve") fun()
    })

},
async printbuff(buffer) {
    while (true) {
        try {
            await this.$bluetooth.writeBLECharacteristicValue(buffer);
            break;
        } catch(e) {}
    }
},

本文轉載于:

https://juejin.cn/post/7001752261722537991

如果對您有所幫助,歡迎您點個關注,我會定時更新技術檔案,大家一起討論學習,一起進步,

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/507233.html

標籤:其他

上一篇:基于 vite 創建 vue3 全家桶專案(vite + vue3 + tsx + pinia)

下一篇:jsonp跨域

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more