我需要jquery或javascript用搜索类型的结果来完成自动完成下拉列表。我需要将结果作为链接“”,以便我可以在新标签中打开它,也可以通过单击直接打开它。 这是我的代码:
import 'dart:async';
import 'package:flutter/material.dart';
String appTitle = 'Overlay Example';
class _CustomDelegate extends SingleChildLayoutDelegate {
final Offset target;
final double verticalOffset;
_CustomDelegate({
@required this.target,
@required this.verticalOffset,
}) : assert(target != null),
assert(verticalOffset != null);
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) => constraints.loosen();
@override
Offset getPositionForChild(Size size, Size childSize) {
return positionDependentBox(
size: size,
childSize: childSize,
target: target,
verticalOffset: verticalOffset,
preferBelow: true,
);
}
@override
bool shouldRelayout(_CustomDelegate oldDelegate) {
return
target != oldDelegate.target
|| verticalOffset != oldDelegate.verticalOffset;
}
}
class _CustomOverlay extends StatelessWidget {
final Widget child;
final Offset target;
const _CustomOverlay({
Key key,
this.child,
this.target,
}) : super(key: key);
@override
Widget build(BuildContext context) {
double borderWidth = 2.0;
Color borderColor = Theme.of(context).accentColor;
return new Positioned.fill(
child: new IgnorePointer(
ignoring: false,
child: new CustomSingleChildLayout(
delegate: new _CustomDelegate(
target: target,
verticalOffset: -5.0,
),
child: new Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: new ConstrainedBox(
constraints: new BoxConstraints(
maxHeight: 100.0,
),
child: new Container(
decoration: new BoxDecoration(
color: Colors.white,
border: new Border(
right: new BorderSide(color: borderColor, width: borderWidth),
bottom: new BorderSide(color: borderColor, width: borderWidth),
left: new BorderSide(color: borderColor, width: borderWidth),
),
),
child: child,
),
),
),
),
),
);
}
}
class _CustomInputState extends State<_CustomInput> {
TextEditingController _inputController = new TextEditingController();
FocusNode _focus = new FocusNode();
List<String> _listItems;
OverlayState _overlay;
OverlayEntry _entry;
bool _entryIsVisible = false;
StreamSubscription _sub;
void _toggleEntry(show) {
if(_overlay.mounted && _entry != null){
if(show){
_overlay.insert(_entry);
_entryIsVisible = true;
}
else{
_entry.remove();
_entryIsVisible = false;
}
}
else {
_entryIsVisible = false;
}
}
void _handleFocus(){
if(_focus.hasFocus){
_inputController.addListener(_handleInput);
print('Added input handler');
_handleInput();
}
else{
_inputController.removeListener(_handleInput);
print('Removed input handler');
}
}
void _handleInput() {
String newVal = _inputController.text;
if(widget.parentStream != null && _sub == null){
_sub = widget.parentStream.listen(_handleStream);
print('Added stream listener');
}
if(_overlay == null){
final RenderBox bounds = context.findRenderObject();
final Offset target = bounds.localToGlobal(bounds.size.bottomCenter(Offset.zero));
_entry = new OverlayEntry(builder: (BuildContext context){
return new _CustomOverlay(
target: target,
child: new Material(
child: new ListView.builder(
padding: const EdgeInsets.all(0.0),
itemBuilder: (BuildContext context, int ndx) {
String label = _listItems[ndx];
return new ListTile(
title: new Text(label),
onTap: () {
print('Chose: $label');
_handleSubmit(label);
},
);
},
itemCount: _listItems.length,
),
),
);
});
_overlay = Overlay.of(context, debugRequiredFor: widget);
}
setState(() {
// This can be used if the listItems get updated, which won't happen in
// this example, but I figured it was useful info.
if(!_entryIsVisible && _listItems.length > 0){
_toggleEntry(true);
}else if(_entryIsVisible && _listItems.length == 0){
_toggleEntry(false);
}else{
_entry.markNeedsBuild();
}
});
}
void _exitInput(){
if(_sub != null){
_sub.cancel();
_sub = null;
print('Removed stream listener');
}
// Blur the input
FocusScope.of(context).requestFocus(new FocusNode());
// hide the list
_toggleEntry(false);
}
void _handleSubmit(newVal) {
// Set to selected value
_inputController.text = newVal;
_exitInput();
}
void _handleStream(ev) {
print('Input Stream : $ev');
switch(ev){
case 'TAP_UP':
_exitInput();
break;
}
}
@override
void initState() {
super.initState();
_focus.addListener(_handleFocus);
_listItems = widget.listItems;
}
@override
void dispose() {
_inputController.removeListener(_handleInput);
_inputController.dispose();
if(mounted){
if(_sub != null) _sub.cancel();
if(_entryIsVisible){
_entry.remove();
_entryIsVisible = false;
}
if(_overlay != null && _overlay.mounted) _overlay.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext ctx) {
return new Row(
children: <Widget>[
new Expanded(
child: new TextField(
autocorrect: true,
focusNode: _focus,
controller: _inputController,
decoration: new InputDecoration(
border: new OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(5.0),
),
borderSide: new BorderSide(
color: Colors.black,
width: 1.0,
),
),
contentPadding: new EdgeInsets.all(10.0),
filled: true,
fillColor: Colors.white,
),
onSubmitted: _handleSubmit,
),
),
]
);
}
}
class _CustomInput extends StatefulWidget {
final List<String> listItems;
final Stream parentStream;
_CustomInput({
Key key,
this.listItems,
this.parentStream,
}): super(key: key);
@override
State createState() => new _CustomInputState();
}
class HomeState extends State<Home> {
List<String> _overlayItems = [
'Item 01',
'Item 02',
'Item 03',
];
StreamController _eventDispatcher = new StreamController.broadcast();
Stream get _stream => _eventDispatcher.stream;
_onTapUp(TapUpDetails details) {
_eventDispatcher.add('TAP_UP');
}
@override
void initState() {
super.initState();
}
@override
void dispose(){
super.dispose();
_eventDispatcher.close();
}
@override
Widget build(BuildContext context){
return new GestureDetector(
onTapUp: _onTapUp,
child: new Scaffold(
appBar: new AppBar(
title: new Row(
children: <Widget>[
new Padding(
padding: new EdgeInsets.only(
right: 10.0,
),
child: new Icon(Icons.layers),
),
new Text(appTitle)
],
),
bottom: new PreferredSize(
preferredSize: const Size.fromHeight(30.0),
child: new Padding(
padding: new EdgeInsets.only(
bottom: 10.0,
left: 10.0,
right: 10.0,
),
child: new _CustomInput(
key: new ObjectKey('$_overlayItems'),
listItems: _overlayItems,
parentStream: _stream,
),
),
),
),
body: const Text('Body content'),
),
);
}
}
class Home extends StatefulWidget {
@override
State createState() => new HomeState();
}
void main() => runApp(new MaterialApp(
title: appTitle,
home: new Home(),
));
答案 0 :(得分:1)
纯JavaScript可能的解决方案。
input
事件监听器input
事件上,清除列表元素的内容,并基于一些匹配函数,动态创建一个新事件,然后添加
每个匹配字符串的链接
// array of values to match against
const tags = ['bmw', 'toyota', 'opel', 'kia'];
// fetch input and list elements
const input = document.querySelector('input');
const list = document.querySelector('ul');
// simple match function, performs substing matching
const getMatch = (toMatch, tags) =>
tags.filter((tag) => tag.includes(toMatch.toLowerCase()));
input.addEventListener('input', (event) => {
// clear contents of list
list.innerHTML = '';
// start matching only when input field is non-empty
if (input.value !== '') {
// call matching function and create a link for each
// item returned by it
getMatch(input.value, tags).forEach((match) => {
const item = document.createElement('li');
list.append(item);
const link = document.createElement('a');
item.append(link);
// add href attribute and text dynamically
link.setAttribute('href', `www.example.com/${match}`);
link.textContent = match;
});
}
});
Search: <input type="text">
<ul></ul>
答案 1 :(得分:0)
我在这里使用@MatusDubrava脚本和其他帮助找到了解决方案。
$(function () {
var menuPages = $('#main-menu li a:has(.childtitle)').map(function () {
return {
label: $(this).text(),
value: $(this).attr('href')
};
}).toArray();
$("#txt_MenuSearch").autocomplete({
source: menuPages,
select: function (event, target) {
/* On select, show item's label in text input */
event.preventDefault();
$("#txt_MenuSearch").val(target.item.label);
var link = target.item.value;
window.open(link);
},
});
/* Highlight text */
$("#txt_MenuSearch").data("ui-autocomplete")._renderItem = function (ul, item) {
var newText = String(item.label).replace(
new RegExp(this.term, "gi"),
"<span style='color:#DDBA15'>$&</span>");
/* Wrapping the matching option within <a> tags */
newText = '<a href="' + item.value + '">' + newText + '</a>';
return $("<li>")
.attr("data-value", item.value)
.append(newText)
.appendTo(ul);
};
});
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<input type="text" id="txt_MenuSearch" class="search-input" placeholder="Search here.." />
<ul id="main-menu">
<li class="has-sub"><a href="javascript:;"><span class="title">Menu Header1</span></a>
<ul>
<li><a href="example.com"><span class="childtitle">brand one</span></a></li>
<li><a href="example.com"><span class="childtitle">brand two</span></a></li>
</ul>
</li>
<li class="has-sub"><a href="javascript:;"><span class="title">Menu Header2</span></a>
<ul>
<li><a href="example.com"><span class="childtitle">Car BMW</span></a></li>
<li><a href="example.com"><span class="childtitle">Car Toyota</span></a></li>
<li><a href="example.com"><span class="childtitle">Car Opel</span></a></li>
<li><a href="example.com"><span class="childtitle">Car Kia</span></a></li>
</ul>
</li>
</ul>