jQuery基本的提前输入实现-当字符串匹配第一个或最后一个字符时不工作


jQuery basic Typeahead implementation - not working when string matches first or last character

我认为问题涉及到.split()方法。当字符匹配名称的开头或结尾时,这似乎不起作用。

在这里查看JSFiddle: http://jsfiddle.net/5uebxvex/

作为参考,我使用了Northwind数据库中的Employees表。例如,其中一个员工是Andrew Fuller。如果您首先输入andr,它将显示相关的结果,但它不会通过在结果中添加粗体、斜体和下划线HTML格式来修改结果的外观。但是,如果您开始键入与字符串中间匹配的字母,例如drew,那么它会显示正确的结果,并且添加HTML格式。此外,正如您从下面的PHP中看到的,您可以键入人员的全名,如rew ful,它将显示正确匹配的Employees。但是,一旦在空格后面添加字符,它将停止添加格式。我真的不知道为什么。

除了这个问题之外,我还注意到,如果您在输入文本字段中快速键入,它通常会给您带来相同结果的倍数。例如,在文本字段中快速键入andrew。或者尝试在文本字段中快速键入uller。它会显示唯一的结果,直到你到达最后,它有时会显示多个相同的结果。

这是怎么回事?有人能解释一下是什么问题吗?

这是PHP - northwind.php:(问题不存在于PHP中-请查看上面的JSFiddle)

<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
$db_user = 'user';
$db_pass = 'pass';
$db_name = 'name';
$db_host = 'host';
$conn = new mysqli($db_host, $db_user, $db_pass, $db_name);
if ($conn->connection_error) { die('Connection error: '. $conn->connection_error); }
$data = $_GET ? $_GET : $_POST;
if (strlen($data['name']) > 0) {
    $sql = '
        SELECT
            CONCAT(FirstName, " ", LastName) AS name,
            EmployeeID AS id
        FROM
            Employees
        WHERE
            FirstName LIKE "%'. $data['name'] .'%"
        OR
            LastName LIKE "%'. $data['name'] .'%"
        OR
            CONCAT(FirstName, " ", LastName) LIKE "%'. $data['name'] .'%"
    ';
    $result = $conn->query($sql) OR die('Query error: '. mysqli_error($conn));
    if ($result->num_rows > 0) {
        $json = array();
        while ($row = $result->fetch_assoc()) {
            $json[] = array('id' => $row['id'], 'name' => $row['name']);
        }
        print json_encode($json);
    }
    else { print '[]'; }
}
?>

查看上面的JSFiddle以获取其余代码。提前感谢您对上述问题的见解。

请在这里找到完整的代码:http://jsfiddle.net

不修改结果的匹配子字符串

问题:匹配子字符串的外观没有改变。匹配的子字符串应该被<span class="highlight">封装。

解决方案:由于在搜索子字符串时区分大小写,会发生这种情况。这可以通过下面的代码来修复:

$(response).each(function(i, e) {
    q = $('#typeahead').val();
    //Find substring,encapsulate each substring with span.highlight.
    var match = e.name.replace(new RegExp(q,"i"), function(m){
        return "<span class='highlight'>"+m+"</span>"
    });
    $('#list').append('<li class="employeeID-'+ e.id +'">'+ match +'</li>');
});

输入匹配字符串中间位置的字母

问题:如果我们键入的查询从字符串(员工姓名)的中间开始,则看起来没有返回预期的结果。例如:如果我们输入drew, Andrew Fuller将在响应数据中不可用。

我认为问题在于服务器代码。CMIIW。我已经简要地查看了您的PHP代码,但无法找到问题可能存在的地方。我现在无法测试你的PHP代码。

快速输入导致多个相同结果的问题

这个问题是由于以前的AJAX请求仍然是活动的。如果我们快速键入"ann",就会有3个Anne Dodsworth和2个Andrew Fuller。

您需要通过使用xhr.abort()中止先前的AJAX请求。xhr是之前的AJAX请求(保存在一个变量中)。

请在这里找到完整的代码:http://jsfiddle.net

您必须在JavaScript中修剪字符串,Typehead的值以便从结果中分割字符串,参见工作示例。

http://jsfiddle.net/5uebxvex/3/

你必须在PHP中修剪字符串

当你在MySQL上搜索 new full 时,查询将检查每个以whatever开头的名字,后面跟着rew, space full和whatever。

所以当你在MySQL上传递rew full(space)时,你会检查任何以rew(space)full(space)开头的人,我很确定当你插入它们时,你所有的名字都被修剪过。

所以请将你的代码更新为这个:

<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
$db_user = 'user';
$db_pass = 'pass';
$db_name = 'name';
$db_host = 'host';
$conn = new mysqli($db_host, $db_user, $db_pass, $db_name);
if ($conn->connection_error) { die('Connection error: '. $conn->connection_error); }
$data = $_GET ? $_GET : $_POST;
if (strlen($data['name']) > 0) {
    $name = trim($data['name']);
    $sql = '
        SELECT
            CONCAT(FirstName, " ", LastName) AS name,
            EmployeeID AS id
        FROM
            Employees
        WHERE
            FirstName LIKE "%'. $name .'%"
        OR
            LastName LIKE "%'. $name .'%"
        OR
            CONCAT(FirstName, " ", LastName) LIKE "%'. $data['name'] .'%"
    ';
    $result = $conn->query($sql) OR die('Query error: '. mysqli_error($conn));
    if ($result->num_rows > 0) {
        $json = array();
        while ($row = $result->fetch_assoc()) {
            $json[] = array('id' => $row['id'], 'name' => $row['name']);
        }
        print json_encode($json);
    }
    else { print '[]'; }
}
?>

但是使用Like来比较字符串的效率不如使用MySQL全文检索功能。

https://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html

您必须使包含文本的字段作为全文索引,然后您可以执行如下查询:

SELECT * FROM `peoples` WHERE MATCH (firstname) AGAINST ('*andrew*' IN BOOLEAN MODE);

您考虑过区分大小写和不区分大小写的搜索吗?如果你用"Andr"填充字段,它会突出显示,如果你搜索"Andr",它不会。为什么?因为"Andrew"answers"Andrew"不一样。a和a是不同的字符,因此不会匹配相同的字符。显然,您的数据库忽略了这一事实,并进行了大小写不敏感的搜索(https://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html: "默认字符集和排序规则是latin1和latin1_swedish_ci,因此非二进制字符串比较默认情况下是不区分大小写的。"),而且很明显,您的.split函数确实区分了小写和大写。因此,如果您查找输入字段的值,它与ajax调用返回的值不同。你现在要做的是:

  • 小写你的搜索字符串和结果字符串
  • 搜索结果字符串
  • 中搜索字符串出现的位置
  • 在原始结果字符串的位置插入您的格式,并在searchstring处终止您的格式。原始结果字符串中的长度

下面的代码片段已经可以工作了,但是所有内容都是小写的,这说明这是大小写问题。

	$(document).ready(function() {
		$('#typeahead').on({
			input: function() {
				$('#list li').remove();
				$.ajax({
					url: 'http://smpl-php.com/jquery/test/northwind.php',
                    method: 'post',
					data: { 'name': $('#typeahead').val() },
					dataType: 'json',
					success: function(response) {
						$(response).each(function(i, e) {
							var match = e.name.toLowerCase()
                            				.split($('#typeahead').val().toLowerCase())
                            				.join('<span class="highlight">'+ $('#typeahead').val() +'</span>');
							$('#list').append('<li class="employeeID-'+ e.id +'">'+ match +'</li>');
						});
					},
					error: function(error) {}
				});
			}
		});
	});
.highlight {
	font-weight: bold;
	text-decoration: underline;
	font-style: italic;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="typeahead" type="text" />
<ul id="list"></ul>