## 兼容性

IE7+、Chrome、Firefox、Safari、Opera、主流手机浏览器、iOS 及 Android上的内嵌Webview

## 开始使用

### 引入初始化JS

**http示例如下：**
```html
  <script src="http://cstaticdun.126.net/load.min.js?t=201903281201"></script>
```
**https示例如下：**
```html
  <script src="https://cstaticdun.126.net/load.min.js?t=201903281201"></script>
```

地址中的t参数强烈建议设置为分钟级别时间戳，避免该文件被浏览器长时间缓存。示例见完整示例


### 调用初始化函数

`initNECaptcha(config, onload, onerror)`
```js
// initNECaptcha为全局函数，可直接调用
initNECaptcha({
    // config对象，参数配置
    captchaId: '从易盾申请的captchaId',
    element: '#captcha',
    mode: 'float',
    width: '320px'
}, function  onload (instance) {
    // 初始化成功后得到验证实例instance，可以调用实例的方法
}, function  onerror (err) {
    // 初始化失败后触发该函数，err对象描述当前错误信息
})
```

## 参数配置

这里指初始化时传入的`config`对象，即调用初始化函数`initNECaptcha`时传入的第一个参数。智能无感知验证码设置参数有些不同，详见表格下方特别说明。

参数 | 参数类型 | 必填 | 默认 | 说明
---|---|---|---|---
`captchaId` | string | 是 | 无 | 验证码id
`element` | string/HTMLElement | * | 无 | 容器元素或容器元素选择器。当`mode`是"popup"且用户使用表单提交时，必填；`mode`是"float"或"embed"时均是必填
`mode` | string | 否 | PC端默认`"float"`，移动端默认`"popup"` | 验证码模式，常规验证码三种模式可选：`"float"`、`"embed"`、`"popup"`，即触发式、嵌入式、弹出式。智能无感知验证码类型可设置`"bind"`模式，绑定自有按钮模式
`protocol` | string | 否 | 与用户网站的网络协议一致 | 验证码传输数据使用的网络协议，可选：`"http"`、`"https"`
`width` | number &#124;string | 否 | `"auto"` | 验证按钮宽度，推荐使用宽度260px-400px。类型为string时，支持后缀`px`、`rem`、`%`，类型为number时，内部会将其转换成`px`单位的值。`"auto"`时，其宽度与容器元素宽度一致。`mode`为`"popup"`时，百分比单位无效。
`lang` | string | 否 | "zh-CN" | 验证码语言选项。支持"zh-CN"-简体中文"、"zh-TW"-繁体中文、"en"-英语、"ja"-日语、"ko"-韩语、"th"-泰语、"vi"-越南语、"fr"-法语、"ru"-俄语、"ar"-阿拉伯语
`appendTo` | string/HTMLElement | 否 | 无 | 验证码弹框的指定区域元素或者指定区域元素选择器。该配置仅在popup模式、bind模式及H5下的智能无感知类型有效。请注意，指定区域的元素必须为非静态定位
`onReady` | function | 否 | 无 | NECaptcha所有工作准备就绪，用户可以使用验证码时触发该回调。具体使用见完整示例
`onVerify` | function | 否 | 无 | 验证码验证结束回调函数。具体使用见完整示例
`onClose` | function | 否 | 无 | 验证码关闭弹框后回调函数。具体使用见完整示例
`enableClose` | boolean | 否 | false | 由业务方控制验证码弹框关闭，具体使用见完整示例
`extraData` | String/Function | 否 | 无 | 如果需要在check阶段透传业务数据，可以使用extraData配置，支持字符串和函数，函数可以解决动态数据问题。当调用二次校验结果接口时，会原样返回该字段，详见[后端响应参数](http://support.dun.163.com/documents/15588062143475712?docId=69218161355051008)。

<md-attention>

#### 特别注意
对于智能无感知验证码，参数`mode`只可设置bind，其他值无效；当mode为非bind时，`width`设置无效，验证按钮宽度与容器宽度一致，容器宽度最小240px。当mode为bind时，验证码宽度等于`width`值。

对于指定弹框区域的验证码，参数`appendTo`表示的元素必须为非静态定位，即position不能为static。

</md-attention>

## 实例方法

这里指`initNECaptcha`初始化成功，`onload`触发时传入的实例的方法。

- `refresh`：刷新验证码，获取新的验证信息，具体见onVerify示例。

- `destroy`：销毁当前实例

- `popUp`：当验证码是常规验证码并且`mode`为"popup"时，可调用该实例方法弹出验证码进行验证

- `close`：当验证码为popup弹框样式，且开启`enableClose`时，可调用该实例方法关闭验证码弹框

示例：

```js
initNECaptcha(config, function onload (instance) {
    // 可在此处调用实例方法
}, onerror)
```

## 完整示例

### 使用时间戳引入初始化js

```js
  var url = 'http://cstaticdun.126.net/load.min.js' + '?t=' + getTimestamp(1 * 60 * 1000) // 时长1分钟，建议时长分钟级别
  loadScript(url, function () {
    // 进行初始化验证码等后续逻辑
    // initNECaptcha({
    //   captchaId: '从易盾申请的captchaId',
    //   element: '#captcha',
    //   width: '320px'
    // })
  })
  
  function getTimestamp (msec) {
    msec = !msec && msec !== 0 ? msec : 1
    return parseInt((new Date()).valueOf() / msec, 10)
  }
  
  function loadScript (src, cb) {
    var head = document.head || document.getElementsByTagName('head')[0]
    var script = document.createElement('script')

    cb = cb || function () {}

    script.type = 'text/javascript'
    script.src = src

    if (!('onload' in script)) {
      script.onreadystatechange = function () {
        if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
        this.onreadystatechange = null
        cb(script)
      }
    }

    script.onload = function () {
      this.onload = null
      cb(script)
    }

    head.appendChild(script)
  }
```

### 使用form表单

```html
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta  name="viewport" content="width=device-width, initial-scale=1.0">
   <meta  http-equiv="X-UA-Compatible" content="ie=edge">
<title>验证码示例</title>
</head>
<body>
   <form action="/login" method="post">
   <input  type="text" name="username" placeholder="用户名">
   <input  type="password" name="password" placeholder="密码">
   <input  type="hidden" name="captchaId" value="从易盾申请的captchaId">
    <div id="captcha"></div> <!-- 验证码容器元素 -->
       <button type="submit">登录</button>
     </form>
   <script src="http://cstaticdun.126.net/load.min.js?t=201903281201"></script>
   <!-- 地址中的t参数强烈建议设置为分钟级别时间戳，避免该文件被浏览器长时间缓存 -->
   <script>
    initNECaptcha({
      captchaId: '从易盾申请的captchaId',
      element: '#captcha',
      mode: 'float',
      width: 320
    }, function onload (instance) {
      // 初始化成功后，用户输入对应用户名和密码，以及完成验证后，直接点击登录按钮即可
    }, function onerror (err) {
      // 验证码初始化失败处理逻辑，例如：提示用户点击按钮重新初始化
    })
    </script>
</body>
</html>
```


### 使用popup弹出模式

```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
   <meta  charset="UTF-8">
   <meta  name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
   <meta  http-equiv="X-UA-Compatible" content="ie=edge">
  <title>验证码示例-popup模式</title>
</head>
<body>
<button id="j-popup">点击弹出验证码</button>
<div id="captcha"></div>
<script  charset="UTF-8" type="text/javascript" src="http://cstaticdun.126.net/load.min.js?t=201903281201"></script>
<!-- 地址中的t参数强烈建议设置为分钟级别时间戳，避免该文件被浏览器长时间缓存 -->
<script>
  var captchaIns;
  initNECaptcha({
    element: '#captcha',
    captchaId: '从易盾申请的captchaId',
    mode: 'popup',
    width: '320px',
    onClose: function () {
      // 弹出关闭结束后将会触发该函数
    }
  }, function (instance) {
    // 初始化成功后得到验证实例instance，可以调用实例的方法
    captchaIns = instance
  }, function (err) {
    // 初始化失败后触发该函数，err对象描述当前错误信息
  })

  // 监听button的点击事件，弹出验证码
  document.getElementById('j-popup').addEventListener('click', function () {
    captchaIns && captchaIns.popUp()
  })
</script>
</body>
</html>
```

### 智能无感知bind模式

*  当验证码是智能无感知时，且设置 mode为 ‘bind’ 时，可以通过调用实例的 verify 接口进行手动验证，实现绑定自有按钮的无感知验证

*  这种形式的好处是，用户可以在验证验证码之前做一些自定义的事件（比如表单参数处理验证），通过后再决定是否调用验证接口

*  验证码验证成功之后在 onVerify 的回调里面做实际的提交行为

```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
   <meta  charset="UTF-8">
   <meta  name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
   <meta  http-equiv="X-UA-Compatible" content="ie=edge">
  <title>验证码示例-智能无感知bind模式</title>
</head>
<body>

<form action="/login" method="post">
   <input  type="text" name="username" placeholder="用户名">
   <input  type="password" name="password" placeholder="密码">
   <input  type="hidden" name="captchaId" value="从易盾申请的captchaId">
   <div id="captcha"></div> <!-- 验证码容器元素 -->
   <button type="submit" id="submit-btn">登录</button>
</form>

<script charset="UTF-8" type="text/javascript" src="http://cstaticdun.126.net/load.min.js?t=201903281201"></script>
<!-- 地址中的t参数强烈建议设置为分钟级别时间戳，避免该文件被浏览器长时间缓存 -->
<script>

    var captchaIns;
    initNECaptcha({
        element: '#captcha',
        captchaId: '从易盾申请的captchaId',
        mode: 'bind', // 仅智能无感知验证码时，mode 才能设置为 bind
        width: '320px',
        //enableClose: true, // 由业务方控制验证码弹框关闭
        onVerify: function(err){
            // 用户验证码验证成功后，进行实际的提交行为
            // todo
            // if (!err) {
              // 验证成功后，调用close方法关闭弹框（enableClose为true时调用）
              //captchaIns.close()
            //}
        }
    }, function (instance) {
        // 初始化成功后得到验证实例instance，可以调用实例的方法
        captchaIns = instance
    }, function (err) {
        // 初始化失败后触发该函数，err对象描述当前错误信息
    })
    // 监听需要绑定的 button 的点击事件，手动调用实例的verify方法来验证
    document.getElementById('submit-btn').addEventListener('click', function (e) {
      e.preventDefault()
      //  if (doSomething()) {               // 在验证之前做一些自定义
            captchaIns && captchaIns.verify ()  // 手动调用verify方法
       // }
    })
</script>
</body>
</html>

```

### 使用onVerify获取验证结果回调

```html
<!DOCTYPE html>
<html lang="en">
<head>
   <meta  charset="UTF-8">
   <meta  name="viewport" content="width=device-width, initial-scale=1.0">
   <meta  http-equiv="X-UA-Compatible" content="ie=edge">
  验证码示例
</head>
<body>
  <div class="form-container">
    <input  type="text" name="username" id="username" placeholder="用户名">
    <input  type="password" name="password" id="password" placeholder="密码">
    <div id="captcha"></div> <!-- 验证码容器元素 -->
    登录
  </div>
  <script src="http://cstaticdun.126.net/load.min.js?t=201903281201"></script>
  <!-- 地址中的t参数强烈建议设置为分钟级别时间戳，避免该文件被浏览器长时间缓存 -->
  <script>
    var captchaIns;

    initNECaptcha({
      captchaId: '从易盾申请的captchaId',
      element: '#captcha',
      mode: 'float',
      width: 320,
      onReady: function (instance) {
     // 验证码一切准备就绪，此时可正常使用验证码的相关功能
      },
      onVerify: function (err, data) {
        /**
         * 第一个参数是err（Error的实例），验证失败才有err对象
         * 第二个参数是data对象，验证成功后的相关信息，data数据结构为key-value，如下：
         * {
         *   validate: 'xxxxx' // 二次验证信息
         * }
        **/
        if (err) return  // 当验证失败时，内部会自动refresh方法，无需手动再调用一次
        // 点击登录按钮后可调用服务端接口，以下为伪代码，仅作示例用
        ajax('/login', {
          captchaId: '从易盾申请的captchaId',
          username: $('#username').val(),
          password: $('#password').val(),
          validate: data.validate
        }, function onsuccess (data) {
          // if (loginFail) {
          // 密码错误等原因导致登陆失败，业务上若需要刷新验证码，可调用refresh方法
          //   captchaIns && captchaIns.refresh()
          // } else {
          // 登录成功后，相关处理逻辑
          // }
        })
      }
    }, function onload (instance) {
      // 初始化成功
      captchaIns = instance
    }, function onerror (err) {
      // 验证码初始化失败处理逻辑，例如：提示用户点击按钮重新初始化
    })
    </script>
</body>
</html>
```

### 使用appendTo（用于指定弹框区域）

```html
<!DOCTYPE html>
<html lang="en">
<head>
   <meta  charset="UTF-8">
   <meta  name="viewport" content="width=device-width, initial-scale=1.0">
   <meta  http-equiv="X-UA-Compatible" content="ie=edge">
  验证码示例

  <style type="text/css">
    #appendWrap {
      position: relative;
    }
  </style>
</head>
<body>
  <div class="form-container" id="appendWrap">
    <button id="j-popup">点击弹出验证码</button>
    <div id="captcha"></div>
  </div>
  <script src="http://cstaticdun.126.net/load.min.js?t=201903281201"></script>
  <!-- 地址中的t参数强烈建议设置为分钟级别时间戳，避免该文件被浏览器长时间缓存 -->
  <script>
    initNECaptcha({
      captchaId: '从易盾申请的captchaId',
      element: '#captcha',
      mode: 'popup',
      width: 320,
      appendTo: '#appendWrap'
    }, function onload (instance) {
      // 初始化成功
      captchaIns = instance
    }, function onerror (err) {
      // 验证码初始化失败处理逻辑，例如：提示用户点击按钮重新初始化
    })
    
    // 监听button的点击事件，弹出验证码
    document.getElementById('j-popup').addEventListener('click', function () {
      captchaIns && captchaIns.popUp()
    })
  </script>
</body>
</html>
```
<md-note>

#### 特别说明
- `onload`和`onReady`的区别：  
  `onload`和`onReady`触发时，均会返回验证码的实例，即传入的第一个参数。二者触发时机有所不同，`onload`触发时，初始化函数结束和完成实例的生成，注意这并不代表验证码是可用的（比如验证码相关背景图片和信息并没有加载），此方法只触发一次。`onReady`触发时，说明验证码准备就绪（比如背景图片等信息均已加载），在`popup`模式下，每次弹出均会触发`onReady`，其他模式下`onReady`只触发一次。

</md-note>