123. 自动完成API(autocomplete API)

    自动完成是指用户在表单上进行输入时,系统依据已输入内容给出一个相关的备选列表(或叫备选菜单),该列表随输入变化而自动更新,用户可从列表中直接选择,从而代替继续输入,输入越多相关程度越高,相关性由匹配逻辑决定,通常是字符串包含,但相关性逻辑是可以自定义的,因此有时这也用于推荐信息;列表里面的数据来源能以变量方式存储在前端js中(称为本地数据),如果量较大也可以储存在后端,通过ajax远程取回;自动完成让用户输入更快、更准确、更方便,可进行自动完成的元素有inputtextarea或具备contenteditable属性的元素

基础:

drupal前端系统的自动完成功能是建立在jquery UI基础之上的,明白了jquery UI自动完成后你将很容易理解drupal自动完成的实现,jquery UI组件的官方下载地址是:
  
https://jqueryui.com/download/
在该页面你可以选择jQuery UI的版本、下载的库中包含的组件、UI使用的主题样式,然后点击下载,这里假设你选择了全部组件,并下载解压到“jqueryui”目录,这里提供一个自动完成的使用示例:

自动完成示例:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>jQuery UI 自动完成示范页</title>
    <link href="jqueryui/jquery-ui.css" rel="stylesheet">
</head>
<body>
<h2>自动完成展示</h2>
<div>
    <input id="autocomplete">
</div>
<br><br><br><br><br><br><br>
<div id="yunke"></div>

<script src="jqueryui/external/jquery/jquery.js"></script>
<script src="jqueryui/jquery-ui.js"></script>
<script>
    var availableTags = [
        "ActionScript",
        "AppleScript",
        "Asp",
        "BASIC",
        "C",
        "C++",
        "Clojure",
        "COBOL",
        "ColdFusion",
        "Erlang",
        "Fortran",
        "Groovy",
        "Haskell",
        "Java",
        "JavaScript",
        "Lisp",
        "Perl",
        "PHP",
        "Python",
        "Ruby",
        "Scala",
        "Scheme"
    ];
    $( "#autocomplete" ).autocomplete({
        source: availableTags,
        appendTo: '#yunke',
        autoFocus: true,
        delay: 100,
        disabled: false,
        minLength: 1,
        position: { my: "left top", at: "left bottom", collision: "none" }
    });

</script>
</body>
</html>

示例说明:

该例引用了三个关键文件: UI样式、jquery库、jquery-uijquery库必须在jquery-ui库之前引用,后者扩展了前者,如你所见,简单的使用UI库提供的方法即可实现自动完成功能。
关于jquery-ui库的自动完成用法不属于本系列范围,如何使用请详见官方文档:
  
https://api.jqueryui.com/autocomplete/
在继续阅读前强烈建议你花几十分钟学习该API,本篇仅列出自动完成相关的选项。

jquery-ui原生自动完成选项及含义:

如下:

appendTo:一个jquery选择器,用于指示用来放置备选列表的元素(注意该选项只是指示DOM放置位置,并不影响显示位置,显示位置见position选项),默认为NULL,此时将查找输入元素的第一个有“ui-front”类属性的父元素,如果存在即用,而不管值为何,如果不存在将使用body元素

autoFocus:布尔值,默认为false,指示在备选列表显示时是否选中第一个元素

classes:用于给控件元素添加额外的类,这样便于自定义控制,值为一个对象,在控件主题化中用到的任意类名可以作为属性名,属性值为要添加的自定义类,这使得在原类出现的地方额外添加了自定义类

delay:一个毫秒为单位的整数,默认为300,指定击键开始到执行数据搜索之间的时间间隔,用于控制备选列表的延迟显示,总延迟还包括搜索时间、网络延迟等

disabled:布尔值,是否禁用自动完成功能,默认为false

minLength:一个整数,默认为1,指示执行数据搜索前用户需要键入的最少字符数,作用相当于频率限制,当有少量本地数据时可以设置为0,当有巨量数据时,应该提高该值

position:一个对象,默认为:{ my: "left top", at: "left bottom", collision: "none" },指示备选列表的显示位置,默认相对于输入元素,但可用该对象的of属性指定相对于其他元素,值为选择器,详见jquery位置组件

source:指定用于自动完成的数据来源,可以是数组、字符串或函数,分别如下:

当为数组时,该数组代表本地尚未过滤过的完整数据,系统会依据输入进行匹配并过滤(匹配即是过滤),然后进行显示,数组有字符串构成和对象构成两种格式(不可混用),对象构成时,对象的“label”属性的值用于在备选列表中显示,“value”属性作为输入元素的值,以label进行输入匹配(“包含”匹配方式),对象的labelvalue属性可只存在一个,此时另一个将采用相同值;

当为字符串时,应该是一个url,会被附加term查询参数(值为用户输入)后执行ajax请求,应该返回json,解码后格式同数组,但不会再被过滤,因此远程服务器应自行过滤,相关性由服务器决定;

当为函数时,其接收两个参数source: function (request,responseFun) { },第一个参数是一个对象,称为请求对象,其仅有一个属性“term”,值为用户输入,第二个参数是一个回调函数,称为响应回调,响应回调仅有一个参数用于接收源数据,不论是否发生错误,在回调中都必须调用响应回调,接收的数据应是已被过滤过的(相关性已确定),格式同前文讲的数组情况,当发生错误时可以不传递参数,或为空数组、null、空对象

 

除以上选项外,还有以下事件选项:

changeclosecreatefocusopenresponsesearchselect

对应的值为事件处理函数

 

drupal自动完成前端库:

库名:core/drupal.autocomplete

文件:core/misc/autocomplete.es6.js

依赖以下库:

    - core/jquery
    - core/drupal
    - core/drupalSettings
    - core/drupal.ajax
    - core/jquery.ui.autocomplete


示例:

这里以本系列配套模块“yunke_help”来做演示

第一步:

建立一个表单yunke_help/src/Form/YunkeForm.php内容如下:

<?php
/**
 * 演示表单自动完成操作
 */

namespace Drupal\yunke_help\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class YunkeForm extends FormBase
{
    public function getFormId()
    {
        return 'yunke_help_form';
    }

    public function buildForm(array $form, FormStateInterface $form_state)
    {
        $form['value'] = array(
            '#type'                          => 'textfield',
            '#attributes'                    => ['data-autocomplete-first-character-blacklist' => '/#?',],
            '#autocomplete_route_name'       => 'yunke_help.test1',
            '#autocomplete_route_parameters' => [],
            '#title'                         => '输入值',
            '#description'                   => "自动完成演示示例",
        );
        $form['actions']['#type'] = 'actions';
        $form['actions']['submit'] = array(
            '#type'        => 'submit',
            '#value'       => $this->t('submit'),
            '#button_type' => 'primary',
        );
        return $form;
    }

    public function validateForm(array & $form, FormStateInterface $form_state)
    {
        //演示起见,无需验证
    }

    public function submitForm(array & $form, FormStateInterface $form_state)
    {
        $form_state->cleanValues();
        print_r($form_state->getValues());
        die;
    }
}

第二步:

\Drupal\yunke_help\Controller\Test::test方法中放入以下代码:

 return  \Drupal::formBuilder()->getForm("\Drupal\yunke_help\Form\YunkeForm");

这用于执行表单

 

第三步:

\Drupal\yunke_help\Controller\Test::test_1方法中放入以下代码:

    public function test_1(Request $request)
    {
        $input=$request->query->get('q');
        $data=[];
        for($i=0;$i<5;$i++){
             //$data[]=$i."($input)";
            $data[]=['label'=>$i."($input)",'value'=>$i];
        }
        $response = new \Symfony\Component\HttpFoundation\JsonResponse($data);
        return $response;
    }

然后访问“http://www.你的域名.com/yunke-help/test”,或点击模块主面板的“测试”按钮,即可体验drupal的自动完成功能

 

Drupal自动完成概述:

在讲述原理前,需要明白drupal的自动完成是通过AJAX从后端获取数据的,默认仅支持input表单元素,允许在一个input控件中输入多个条目,可针对每个条目单独进行自动完成功能,条目间用英文逗号分隔,发送到后端的数据并不是整个input控件的值,而是将其以英文逗号“,”分隔后的最后一段值(英文双引号“”中的逗号不算,这作为值而不是分隔符),数据通过GET查询参数“q”传递到后端。

后端返回json响应,通常是以下类对象:

\Symfony\Component\HttpFoundation\JsonResponse

json格式按前文所述的原生jquery UI数组格式,如果返回的数组不是对象构成,换句话说是字符串构成,那么已经输入的条目会从建议列表中删除,仅显示有效值,反之如果是对象构成则不会有删除动作。

页面中可以有多个自动完成元素,每个元素都需要有ID属性,为了提高性能和节约资源,每个自动完成元素的每次自动完成数据请求会被前端js缓存,以便相同请求不会再次发送,且设置了首字符黑名单,当条目首字符位于黑名单中时,不会触发自动完成功能

 

原理:

自动完成前端js首先运行的是:

Drupal.behaviors.autocomplete.attach(context)

该方法进行自动完成初始化,使用全局变量Drupal.autocomplete.options作为选项,各选项解释如下:

focus:设置聚焦事件处理回调,该事件是在菜单条目获得焦点后派发,默认动作是用条目的值替换表单的值,返回false表示取消该事件,即在菜单出现后,通过键盘方向键进行选择的过程中不要自动输入值,需要等待按压回车后才输入

search:设置搜索事件处理回调,搜索事件派发时机是在“最小长度”和“延迟时间”判断满足后,搜索执行前,如果返回false将取消本次自动完成功能执行(没有请求发起,没有建议给出),drupal通过该事件实现首字符黑名单功能:首字符在黑名单中或字符数小于最小限制将不执行搜索,不显示备选列表

select:设置选择事件处理回调,选择事件派发时机是在自动完成菜单中有条目被选中之后(回车键被按压后),默认动作是用选择的条目值替换表单值,如果返回false将阻止默认动作,但不会阻止菜单关闭,drupal利用该事件实现多条目输入功能,以允许英文逗号分隔多个值,使得之前的自动完成结果值得到保留

renderItem:在原生的jquery-ui中,并不支持该选项,这里被用来传递额外的数据,保存一个函数,用于通过jquery Ui的“_renderItemAPI进行原生扩展,使得在构建菜单条目时,lable可以是任意html内容,包含标签,且lable<a>”标签包裹

minLength:触发自动完成功能所需输入字符串最小长度,默认设置为1,以字符串的length属性来比较,意味着中文汉字并非按字节计算,通常一个字就是一个长度(但并非全部,如汉字“𠮷”长度为2

firstCharacterBlacklist:首字符黑名单,单个条目如果以黑名单中的任意字符开始,将不会触发自动完成功能,默认通过第一个自动完成元素的“data-autocomplete-first-character-blacklist”属性设置,所有自动完成元素共享相同首字母黑名单,如果需要不同,可以在获得焦点时通过以下全局对象:

Drupal.autocomplete.options.firstCharacterBlacklist

设置,然后在失去焦点时恢复之前的共享值,注意不支持首词组,仅首字符

 

部分函数解释:

showSuggestions(suggestions)

从菜单中删除已经输入过的值,仅在后端返回索引数组时起作用

Drupal.autocomplete.splitValues(value)

输入一个字符串值,返回由字符串中的逗号“,”分隔后的一个数组,注意是英文逗号,且英文的双引号“”中的逗号不算

Drupal.autocomplete.extractLastTerm(value)

返回由Drupal.autocomplete.splitValues(value)分隔后的数组的最后一个元素

 

在前端:

要应用自动完成的元素仅支持input,且还需要具备以下条件:

类属性form-autocomplete:必须值,用于表明元素需要自动完成

数据属性data-autocomplete-path:必须值,用于指定自动完成的ajax请求地址

数据属性data-autocomplete-first-character-blacklist:可选的,指定首字符黑名单

id属性:必须值,用做缓存标识符

 

在后端:

自动完成是用于表单的,因此在表单API中实现,通过“#process”回调添加相关条件,详见Textfield是如何指定自动完成处理的:

\Drupal\Core\Render\Element\Textfield

实际处理方法为:

\Drupal\Core\Render\Element\FormElement::processAutocomplete

该方法自动添加类属性“.form-autocomplete”,加载自动完成库,进行权限检查,前文示例中的表单元素即通过该方法处理

 

以上是drupal自动完成的一般性、通用的基础实现,称为自动完成API,在开发时直接使用即可,但如果是针对实体进行自动完成,开发者还需要做许多工作,因此drupal在本篇所讲API基础之上为实体提供了专门的自动完成,开箱即用,将在下一节中讲解

 

补充:

1、自动完成以编程方式改变元素的值,因此元素上的“change”事件可能不被触发,稳妥的办法是采用自动完成功能派发的change事件:

$( ".selector" ).autocomplete({
   change: function( event, ui ) {}
});

2drupal自动完成条目间的分隔符默认为英文逗号,如需其他分隔符可覆写以下方法:

  Drupal.autocomplete.splitValues(value)

3、自动完成时,服务器返回值如果是索引数组,不应该有重复值

4、被初始化的自动完成元素有一个数据属性“ui-autocomplete”(获取:data('ui-autocomplete')),储存着该元素的自动完成对象,这涉及更加底层的原生jquery ui实现,这里仅提示,不做深入讲解

 

 

添加新评论

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。
请输入以上问题的答案,换一个问题请刷新,不区分大小写