22、前端开发中的自动完成与DOM构建技巧

前端开发中的自动完成与DOM构建技巧

在前端开发中,自动完成功能和DOM元素的构建是常见的需求。自动完成功能可以提升用户输入的效率,而灵活构建DOM元素则有助于动态更新页面内容。下面将详细介绍自动完成功能的使用和DOM片段的构建方法。

自动完成功能的使用

自动完成功能可以为用户提供动态的文本输入建议,这些建议可以来自页面本地数据,也可以通过Ajax从远程数据源获取。以下是关于自动完成功能的详细介绍:

传递动态参数

可以通过 Ajax.Autocompleter 传递动态参数,例如动态时间戳和静态额外参数。示例代码如下:

new Ajax.Autocompleter('edtLibName', 'libChoices', '/completions', {
    method: 'get',
    parameters: 'static1=value1',
    callback: function(editor, paramText) {
        return paramText + '&stamp=' + new Date().getTime();
    }
});

假设输入字段的 name 属性为 libName ,当输入“ab”时,会发出类似以下的请求URL:

GET /completions?libName=ab&stamp=1178039580757&static1=value1
处理富标记选项

在自动完成列表中,可能需要提供比纯文本更丰富的内容,如图片、日期等。但自动完成功能会收集所选 <li> 元素内的所有文本节点,这可能导致不符合预期的结果。可以通过以下两种方式处理富内容:
- 使用 informal :将不需要用于完成的文本标记为 informal 类,这些元素将被自动忽略。示例如下:

<li>
    <img src="/i/mugshots/ejaubert.png" alt="[Mugshot]"/>
    <span class="contactName">Élodie Jaubert</span><br />
    <span class="job informal">Heritage consultant</span>
</li>
  • 使用 select 选项 :指定一个CSS类来标识要包含的元素。示例如下:
<li>
    <img src="/i/mugshots/ejaubert.png" alt="[Mugshot]"/>
    <span class="contactName">Élodie Jaubert</span>
    <div class="job">Heritage consultant</div>
    <div class="email">heritage@example.com</div>
    <div class="cell">Cell: (478) 555-1234</div>
</li>
new Ajax.Autocompleter('edtContact', 'contactChoices', '/completions', {
    select: 'contactName'
});

需要注意的是,这两种选择完成内容的方式是互斥的。如果指定了 select 选项, informal 类将不会被考虑。

单字段自动完成多个值

自动完成功能不限于每个字段只完成一个值,可以让用户输入多个值,通常用预定义的分隔符(如逗号、空格或换行符)分隔。可以通过 tokens 选项来实现这一功能,示例如下:

document.observe('dom:loaded', function() {
    new Ajax.Autocompleter('edtLibNames', 'libChoices', '/completions', {
        method: 'get', paramName: 'libName',
        tokens: [',', '\n'], select: 'libName'
    });
});

以下是实现多值自动完成的详细步骤:
1. 调整网页 :使用多行输入字段 <textarea> ,示例代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Advanced autocompletion</title>
    <link rel="stylesheet" type="text/css" href="demo.css" />
    <script type="text/javascript" src="prototype.js"></script>
    <script type="text/javascript"
            src="scriptaculous.js?load=effects,controls"></script>
    <script type="text/javascript" src="demo.js"></script>
</head>
<body>
    <h1>Advanced autocompletion</h1>
    <form>
        <p>
            <label for="edtLibNames" accesskey="L">Ruby libraries</label><br/>
            <textarea type="text" id="edtLibNames" name="libNames"></textarea>
            <div id="libChoices" class="autocomplete"></div>
        </p>
    </form>
</body>
</html>
  1. 服务器端处理 :创建一个 LibInfo 类来存储库的名称、最后修改时间和文件大小等信息。示例代码如下:
#! /usr/bin/env ruby

require 'cgi'
require 'erb'
require 'webrick'
include WEBrick

class LibInfo
    attr_reader :name, :mtime, :size

    def initialize(name)
        @name = File.basename(name, '.rb')
        @mtime = File.mtime(name)
        @size = File.size(name)
    end

    def <=>(other)
        self.name <=> other.name
    end
end

template_text = File.read('suggestions.rhtml')
suggestions = ERB.new(template_text)

server = HTTPServer.new(:Port => 8042)
server.mount('/', HTTPServlet::FileHandler, '.')

server.mount_proc('/completions') do |request, response|
    name_start = request.query['libName']
    suffix = "/#{Regexp.escape(name_start)}*.rb"
    libs = $LOAD_PATH.map { |dir|
        Dir.glob(dir + suffix, File::FNM_CASEFOLD).map { |f| LibInfo.new(f) }
    }.flatten.sort.uniq
    response['Content-Type'] = 'text/html'
    response.body = suggestions.result(binding)
end

trap('INT') { server.shutdown }
server.start
  1. 调整建议模板 :使用 strftime() 方法格式化修改时间,示例代码如下:
<ul>
    <% libs.each do |lib| %>
    <li>
        <div class="libName"><%= lib.name %></div>
        <div class="libMTime"><%= lib.mtime.strftime('%m/%d/%Y %H:%M:%S') %></div>
        <div class="libSize"><%= lib.size %> bytes</div>
    </li>
    <% end %>
</ul>
  1. 调整CSS样式 :为新的CSS类添加自定义样式,示例代码如下:
h1 { font-size: 1.5em; }
div.autocomplete {
    position: absolute;
    width: 250px; /* will be adjusted by script.aculo.us */
    background-color: white; border: 1px solid #888;
    margin: 0px; padding: 0px;
}
div.autocomplete ul {
    list-style-type: none; margin: 0px; padding: 0px;
}
div.autocomplete ul li.selected { background-color: #ff9;}
div.autocomplete ul li {
    list-style-type: none; display: block;
    font-family: sans-serif; font-size: smaller; color: #444;
    margin: 0; padding: 0.1em; height: 3.5em;
    cursor: pointer;
}
#edtLibNames {
    border: 0.1em solid gray; padding: 0.1em; height: 4em;
}
div.libMTime, div.libSize {
    font-size: 80%;
    color: #444;
}
div.libMTime {
    margin: 0.2ex 0 0 2ex;
}
div.libName {
    font-weight: bold;
}
div.libSize {
    margin: 0 0 0.5em 2ex;
}
完成回调

自动完成器提供了几个回调函数,可以自定义完成列表的显示和隐藏方式,以及在完成选择时进行相应的操作。以下是这些回调函数的详细介绍:
| 回调函数 | 描述 | 参数 |
| ---- | ---- | ---- |
| onShow | 负责定位和显示选择列表。默认行为是将完成容器定位在输入字段下方,对齐宽度,并使用 Effect.Appear 快速淡入(0.15秒)。 | 输入字段和完成容器 |
| updateElement | 负责在接受 <li> 完成选择时实际完成输入字段的值。此函数很少被重写,因为它替换了默认行为,该行为负责处理很多事情,如处理富结构内容、处理标记化、更新输入字段的值,并最终调用 afterUpdateElement 回调。 | 接受的 <li> 元素 |
| afterUpdateElement | 最常用的回调函数,在默认的 updateElement 行为完成值的完成后触发。可以通过它轻松对完成操作做出反应。 | 输入字段和接受的 <li> 元素 |
| onHide | 负责隐藏选择列表。默认行为是在0.15秒内淡出。 | 输入字段和完成容器 |

自动完成功能总结
  • 最常见的自动完成形式是通过 Ajax.Autocompleter 实现,但也可以基于JavaScript数组实现本地完成。
  • 可以通过调整 minChars frequency 等选项来轻松调整完成过程的触发时间和方式。
  • 基于Ajax的完成需要 <ul>/<li> 结构作为响应,但列表项的内容可以根据需要丰富。
  • 回调函数可以增强基本的完成过程,例如从所选元素中获取隐藏数据以填充可视和隐藏表单字段。
  • 通过 tokens 选项可以在单个字段中完成多个值。
DOM片段的构建

在前端开发中,经常需要向页面文档中注入新内容。根据内容的复杂性和潜在的浏览器兼容性问题,可以选择以下三种方式:
- 使用Element扩展方法 :如果生成内容的标记文本足够简单,可以使用 insert() replace() update() 等方法。但这些方法内部通常依赖 innerHTML 属性,可能会导致浏览器不一致问题,尤其是在处理 <select> <option> 元素时。
- 使用 new Element(...) 语法 :可以满足简单的手动元素构建需求,但目前不能指定文本或嵌套元素作为创建元素的内容,只能指定元素的标签名和属性列表。
- 使用Builder :适用于需要创建实际DOM树或遇到基于 innerHTML 方法的问题时。Builder可以让你使用简洁、表达性强的语法快速指定DOM片段的构建。

Builder的基本使用

Builder的基本构建块是 Builder.node() ,可以通过多种方式调用,示例如下:

Builder.node(tagName) → Element
Builder.node(tagName, attributes) → Element
Builder.node(tagName, text | child | [ child, ... ]) → Element
Builder.node(tagName, attributes, text | child | [ child, ... ]) → Element

以下是不同调用方式的示例:
- 创建单个元素

Builder.node('a', { href: 'http://script.aculo.us' })
Builder.node('label', { htmlFor: 'edtLogin', accesskey: 'L' })
Builder.node('p', { className: 'intro' })
  • 创建带有文本内容的元素
// Text child
Builder.node('h1', 'Builder rules')
// Attributes, text child
Builder.node('a', { href: 'http://prototypejs.org' }, 'Prototype!')
  • 创建嵌套元素
// Element child
Builder.node('h1', Builder.node('code', 'Builder'))
// Multiple children
Builder.node('h1', [Builder.node('code', 'Builder'), ' rules'])
// Attributes, element child
Builder.node('p', { className: 'submission' },
    Builder.node('input', { type: 'submit', value: 'Sign in' }))
// Attributes, multiple children
Builder.node('a',
    { href: 'http://prototypejs.org/api/ajax/update' },
    [Builder.node('code', 'Ajax.Updater'), ' documentation'])
方法简化

可以通过调用 Builder.dump() 为任何对象(包括全局作用域)添加方便的方法,这些方法是 Builder.node() 的包装器,示例如下:

// 简化前
Builder.node('h1', Builder.node('code', 'Builder'))
// 简化后
H1(CODE('Builder'))

// 简化前
Builder.node('h1', [Builder.node('code', 'Builder'), ' rules'])
// 简化后
H1([CODE('Builder'), ' rules'])

// 简化前
Builder.node('p', { className: 'submission' },
    Builder.node('input', { type: 'submit', value: 'Sign in' }))
// 简化后
P({ className: 'submission' }, INPUT({ type: 'submit', value: 'Sign in'}))

// 简化前
Builder.node('a',
    { href: 'http://prototypejs.org/api/ajax/update' },
    [Builder.node('code', 'Ajax.Updater'), ' documentation' ])
// 简化后
A({ href: 'http://prototypejs.org/api/ajax/update' }, [CODE('Ajax.Updater'), 'documentation'])

调用 Builder.dump() 的示例如下:

Builder.build( [ scope = window ] )

调用时不传递参数会在全局作用域中添加大写方法。

通过以上介绍,我们可以看到自动完成功能和DOM片段构建在前端开发中的重要性和实用性。合理运用这些技术可以提升用户体验和开发效率。

前端开发中的自动完成与DOM构建技巧

不同场景下自动完成功能的选择与应用

在实际的前端开发中,需要根据不同的场景来选择合适的自动完成方式和配置。以下是一些常见场景及对应的选择建议:

数据来源场景
数据来源 选择建议
本地数据 如果数据量较小且不经常更新,可以基于JavaScript数组实现本地完成。这种方式无需与服务器进行交互,响应速度快。例如,实现一个简单的城市选择自动完成,城市数据可以预先存储在一个JavaScript数组中。
远程数据 当数据量较大或需要实时更新时,使用 Ajax.Autocompleter 通过Ajax从远程数据源获取数据是更好的选择。例如,在搜索商品时,商品数据通常存储在服务器端,需要通过Ajax请求获取最新的商品列表。
内容复杂度场景
内容复杂度 选择建议
简单文本内容 直接使用默认的自动完成机制即可,无需额外处理。例如,在输入用户名时,自动完成列表只显示用户名。
富内容 可以使用 informal 类或 select 选项来处理富内容。如果内容结构相对简单,使用 informal 类标记不需要用于完成的文本;如果内容结构复杂,使用 select 选项指定要包含的元素。例如,在联系人自动完成中,每个联系人除了姓名还有职位、邮箱等信息,可以使用 select 选项只选择姓名用于完成。
多值输入场景

如果需要在单个字段中输入多个值,可以使用 tokens 选项。例如,在为文章添加标签时,用户可以输入多个标签,用逗号或换行符分隔。以下是一个简单的流程图,展示了多值自动完成的处理流程:

graph TD
    A[用户输入] --> B{是否有分隔符}
    B -- 是 --> C[提取最新的标记]
    B -- 否 --> D[使用整个输入作为标记]
    C --> E[进行自动完成查询]
    D --> E
    E --> F[显示自动完成列表]
    F --> G{用户选择完成项}
    G -- 是 --> H[更新输入字段的值]
    G -- 否 --> A
自动完成功能的优化建议

为了提高自动完成功能的性能和用户体验,可以考虑以下优化建议:
- 减少请求次数 :通过调整 minChars 选项,设置用户至少输入多少个字符后才触发自动完成请求,避免不必要的请求。例如,将 minChars 设置为2,用户输入至少2个字符后才开始请求数据。
- 缓存数据 :对于一些不经常变化的数据,可以在本地进行缓存。当用户再次输入相同的内容时,直接从缓存中获取数据,而无需再次请求服务器。
- 优化服务器端处理 :在服务器端对数据进行筛选和排序,只返回符合条件的数据,减少传输的数据量。例如,在搜索商品时,服务器只返回名称以用户输入内容开头的商品。

DOM构建的深入应用

在实际开发中,Builder可以用于构建复杂的DOM结构。以下是一个使用Builder构建一个包含表格的DOM片段的示例:

// 创建表格
const table = Builder.node('table', { className: 'data-table' });

// 创建表头
const thead = Builder.node('thead');
const headerRow = Builder.node('tr');
const headers = ['Name', 'Age', 'Email'];
headers.forEach(headerText => {
    const th = Builder.node('th', headerText);
    headerRow.appendChild(th);
});
thead.appendChild(headerRow);
table.appendChild(thead);

// 创建表体
const tbody = Builder.node('tbody');
const data = [
    { name: 'John', age: 25, email: 'john@example.com' },
    { name: 'Jane', age: 30, email: 'jane@example.com' }
];
data.forEach(item => {
    const row = Builder.node('tr');
    const cells = [item.name, item.age, item.email];
    cells.forEach(cellText => {
        const td = Builder.node('td', cellText);
        row.appendChild(td);
    });
    tbody.appendChild(row);
});
table.appendChild(tbody);

// 将表格添加到页面中
document.body.appendChild(table);
DOM构建的注意事项

在使用Builder进行DOM构建时,需要注意以下几点:
- 浏览器兼容性 :虽然Builder可以避免一些 innerHTML 带来的浏览器兼容性问题,但仍然需要测试不同浏览器的兼容性。特别是在处理一些特殊元素时,如 <select> <option> ,可能会存在一些细微的差异。
- 性能问题 :在构建复杂的DOM结构时,频繁的DOM操作可能会影响性能。可以考虑批量创建元素,减少DOM操作的次数。例如,先创建所有的表格行,然后一次性将它们添加到表格中。

总结与展望

自动完成功能和DOM构建是前端开发中非常实用的技术。通过合理运用自动完成功能,可以提升用户输入的效率和体验;使用Builder可以方便地构建复杂的DOM结构,提高开发效率。在未来的开发中,随着前端技术的不断发展,自动完成功能和DOM构建可能会有更多的优化和创新。例如,结合人工智能技术,实现更智能的自动完成;使用虚拟DOM技术,进一步提高DOM构建的性能。开发者需要不断学习和掌握这些新技术,以适应不断变化的前端开发需求。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值