星期五 2020 年 7 月 10 日
来自 Sandy Galloway

编辑器二维码扫描仪的整合

最近我们在论坛收到一条有趣的帖子,询问是否可以将二维码扫描仪整合到编辑器中。我很高兴地说这确实可行,在本篇博文中,我将演示如何为编辑器创建一个 字段类型外挂程序,使二维码能够读入字段。我已经使用第三方 Instascan 库在您自己的系统中实现了这一点。

在进一步深入探讨之前,这里有一个关于此外挂程序的效果预览。只需编辑或创建新行,然后按“描述”字段输入元素旁边的“扫描”按钮。您应该能够从这里扫描二维码并在输入元素中看到结果。

姓名 城市 描述

快速开始

如果您希望将 Instascan 与编辑器一起用作二维码扫描仪,您可以通过 NPM 安装 Instascan(npm install --save instascan)或直接在脚本标签中导入 Instascan 来实现。

JS

还需要此整合外挂程序,才能让它与编辑器一起使用,可以从此处下载

JS

最后,(这就是这么容易!)您需要将 fields.type 选项设为 qr - 例如:

fields: [
    {
        label: 'Code:',
        name: 'code',
        type: 'qr'
    },
    // ...
]

从中您会发现,当您编辑或创建记录时,您可以按您指定为 QR 字段的字段的输入旁边显示的扫描按钮。这随后会将活动信息流显示到您的网络摄像头,当您扫描二维码时,值将显示在输入元素中。

构建外挂程序

使用它足够简单,下面让我们深入了解它是如何工作的,我们调查一下如何为编辑器创建 自定义字段类型外挂程序

Instascan

首先我们需要一个二维码扫描仪, Instascan 就是我们可用于此目的的库。它自我描述为“实时网络摄像头驱动的 HTML5 二维码扫描仪”,这正是我们所需的。

有几个 API 方法和配置选项,我们在这里不会讨论,但它们可能对您有用,我建议您仔细阅读他们在 github 上的自述文件,这样您才能设置 Instascan 以满足您自己的需求。他们也有一个 演示页面,很好地展示了它们提供的功能。

将 Instascan 与编辑器整合

为了使二维码扫描仪完全可重复使用,并在单个表单中允许多个二维码,我们将为编辑器创建一个 自定义字段类型外挂程序。我们需要为我们的编辑器外挂程序定义三个功能

  • create - 当字段首次初始化时调用
  • get - 从字段中获取值
  • set - 将值设置到字段中。

create

这是此插件中几乎所有有趣的地方!以下是我们函数的结构,划分为几个部分(当一起使用时,它变得非常大)

create: function (conf) {
    create: function (conf) {
        // Section 1 - DOM setup, including container
        // Section 2 - Instascan setup
        // Section 3 - Toggle control
        // Section 4 - Close behaviour

        return container;
    },

我们create函数中的第一部分用于构造字段的 DOM,因为我们需要汇集几个不同的元素。请注意,我们将 input 元素分配给 conf 对象,这样就可以在其他插件方法中访问它。

// Section 1 - DOM setup
var safeId = DataTable.Editor.safeId(conf.id);
var video = $('<video/>').css({
    display: 'none',
    'max-width': '100%',
    padding: '2% 0%',
});
var input = $('<input id="' + safeId + '"/>');
var scan = $('<button>Scan</button>').css({ margin: '0% 1%' });
var container = $('<div/>').append(input).append(scan).append(video);

conf.qrInput = input;

接下来是初始化 Instascan 实例。我们需要向 Instascan 实例添加一个scan侦听器。在检测到二维码时,它将被触发,并会将 input 元素的值设置为二维码的值。这里添加的另一个内容是为 input 元素和视频 feed 都添加一个边框,持续半秒钟。这会直观地向用户表明已进行扫描。

var scanner = new Instascan.Scanner({ video: video[0] });
scanner.addListener('scan', function (content) {
    input.val(content).css({ border: 'blue 2px solid' });
    video.css({ border: 'blue 2px solid' });

    setTimeout(() => {
        input.css({ border: 'none' });
        video.css({ border: 'none' });
    }, 500);
});

现在我们有了准备就绪的 Instascan 实例,我们需要使用它!在此插件中,当单击上面定义的scan按钮元素时,我们将为字段激活相机。为了启用扫描开始,我们使用Instascan.Camera.getCameras方法,它会返回Promise,然后使用实例的start()方法。我们还将显示 video 元素,以便用户可以看到摄像头看到的内容。该切换的反向调用会调用 Instascan 实例的stop()方法。在这两种情况下,都会更新按钮的内容,以反映单击它的操作。

// Section 3 - Toggle control
scan.on('click', function () {
    if (this.innerHTML === 'Scan') {
        Instascan.Camera.getCameras()
            .then(function (cameras) {
                if (cameras.length > 0) {
                    video.css({ display: 'block' });
                    scanner.start(cameras[0]);
                } else {
                    console.error('No cameras found.');
                }
            })
            .catch(function (e) {
                console.error(e);
            });

        this.innerHTML = 'Stop';
    } else if (this.innerHTML === 'Stop') {
        video.css({ display: 'none' });
        scanner.stop();
        this.innerHTML = 'Scan';
    }
});

要添加的最后一项是关闭表单的一个监听器,以确保在我们关闭表单时停止扫描二维码并关闭摄像头。

// Section 4 - Close behaviour
this.on('close', function () {
    scanner.stop();
});

get

get 函数非常简单。因为我们在 create 函数中将 input 元素添加到 config 对象中,而且我们在 create 函数中安装的 Instascan scan 事件处理程序会向其写入值,所以我们只需获取它的值

get: function ( conf ) {
    return conf.qrInput.val();
}

set

set 函数也相对简单,在这种情况下,将给定的值设置到 input 元素中

set: function (conf, val) {
    conf.qrInput.val(val !== null ? val : '');
},

将所有这些函数放到一个插件中,就得到了上面显示的行为。最后的脚本可以从

JS

高级用法

当然,还有更高级的方法来使用与 Editor 集成的 QR 阅读器。您可能有一些表示由逗号分隔的一系列字符串的 QR 代码,您希望将其直接放入一张表中。您可以读取代码,将结果拆分并分别将其放入各个字段,或基于扫描的代码,查询另一个 API 来填写其他字段(例如地理位置 API)。

实现计数系统也是可能的。假设您有一个项目的库存,并且需要扫描每个项目并跟踪每个项目的计数。您可以在表外运行 Instascan,并使用 DataTables API 来在每次扫描时递增每个项目类型的计数。

反馈

与往常一样,我们渴望听到您如何使用 DataTables 和 Editor。请在论坛中给我们留言,告诉我们您如何使用我们的软件,或者如果您遇到任何问题,或者对未来的增强功能有任何想法。我们很想了解是否有人能够将 Instascan 集成到他们的项目中。

根据反馈进行的补充

自发布此博客文章以来,我们已收到一些有关如何在移动设备上改进此文章的反馈,涵盖 Android 和 IOS。感谢 Daniel Bierschwale 提供这些内容。

后置摄像头

大多数移动设备既有后置摄像头,也有前置摄像头,你需要针对哪一个进行操作可能取决于你使用的设备和应用程序。在 Android 上,访问后置摄像头很简单,你只需在第二个摄像头开始扫描即可。这意味着将

scanner.start(cameras[0]);

更改为以下内容

scanner.start(cameras[1]);

但在 IOS 上,此操作并不简单。如这个 Github 问题 中详细说明的那样,你必须修改 camera.js 文件并设置

facingMode: "environment"

但是,这样做的缺点是无法在摄像头之间切换。

IOS 修复首帧冻结问题

在 IOS 上首次打开摄像头时,视频有时不会立即播放,只会显示第一帧。可通过编辑视频标签为

<video autoplay muted id="video" controls="true"/>