HTML5中定义了一种input框很好看的下拉列表--datalist,然而目前它的支持性并不好(万恶的IE,好在你要渐渐退役了...)。于是最近更据需求写了一个小型datalist插件,兼容到IE8(IE7应该没多少人用了吧?)。实现的具体需求如下:
当被选中的时候(触发blur焦点)(不管是鼠标还是tab键)清空input框并且显示自定义的下拉列表,然后可以用键盘的上下键选择(鼠标当然肯定没理由不可以啦),单击鼠标左键或者enter键将选中的列表的值输入到input框。
具体的实现代码如下:
HTML
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta name="robots" content="index, follow" />
<meta name="googlebot" content="index, follow" />
<meta name="author" content="codetker" />
<title> 表单选中弹出框</title>
<link href="css/reset.css" type="text/css" rel="Stylesheet" />
<link href="css/master.css" type="text/css" rel="Stylesheet" />
<script type="text/javascript" src="js/jquery-1.11.0.js"></script>
</head>
<body>
<div class="wrap">
<form class="center">
<div class="input_wrap">
<input name="input1" class="input input1" type="text"/>
<ul class="input1_ul select_list">
<li>问题1</li>
<li>问题2</li>
<li>问题3</li>
<li>问题4</li>
<li>问题5</li>
</ul>
</div>
</form>
</div>
<script type="text/javascript" src="js/jquery.codetker.datalist.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$(".input_wrap").myDatalist({"bgcolor":"red","widths":1,"heights":1});
});
</script>
</body>
</html>
css
.wrap{ margin:0 auto; font-family: "微软雅黑";font-size: 14px;}
.center{ margin: 0 auto; width:500px;}
.input{ margin: 0; padding: 0; /*border:none;*/ width:140px; height: 24px; float:left;}
.select_list{display: none; position:absolute; z-index: 100;}
.select_list li{ height:24px; margin: 0; padding: 0; background-color: #fff; cursor: pointer; list-style: none; position:relative;}
.select_list li:hover{ background-color: red;}
.input_wrap{ position:relative; }
js
/*
datalist 0.1
自定义datalist插件,实现html5中input元素datalist的效果
兼容IE8+,Firefox,Chrome等常见浏览器
*/
;(function($,window,document,undefined){ //undefinde是真实的undefined,并非参数
//将可选择的变量传递给方法
//定义构造函数
var Datalist=function(ele,opt){
this.$element=ele;
this.defaults={
'bgcolor':'green',
'widths':1,
'heights':1
},
this.options=$.extend({}, this.defaults, opt);
}
//定义方法
Datalist.prototype={
showList:function(){
var color=this.options.bgcolor;
var width=this.options.widths;
var height=this.options.heights; //属性值
var obj=this.$element; //obj为最外层包裹的div之类的元素,应该拥有positive:relative属性,方便datalist定位。
var input=$(obj).children().eq(0); //input元素
var inputUl=$(obj).children().eq(1); //datalist元素
//设置弹出datalist的大小和样式
$(inputUl).css({
"top":$(input).outerHeight()+"px",
"width":$(input).outerWidth()*width+"px"
});
$(inputUl).children().css({
"width":$(input).outerWidth()*width+"px",
"height":$(input).outerHeight()*height+"px"
});
$(inputUl).children('li').mouseover(function() {
$(this).css("background-color",color);
$(this).siblings().css("background-color","#fff");
});
$(inputUl).children('li').mouseout(function() {
$(this).css("background-color","#fff");
});
//再次focus变为空,也可以改为某个默认值
//datalist的显示和隐藏
$(input).focus(function() {
if($(this).val()!=""){
$(this).val("");
}
$(inputUl).slideDown(500);
var n=-1; //记录位置,-1表示未选中。当n=-1时直接按enter浏览器默认为倒数第一个
$(document).keydown(function(event) {
/* 点击键盘上下键,datalist变化 */
stopDefaultAndBubble(event);
if(event.keyCode==38){//向上按钮
if(n==0||n==-1){
n=4;
}else{
n--;
}
$(inputUl).children('li').eq(n).siblings().mouseout();
$(inputUl).children('li').eq(n).mouseover();
}else if(event.keyCode==40){//向上按钮
if(n==4){
n=0;
}else{
n++;
}
$(inputUl).children('li').eq(n).siblings().mouseout();
$(inputUl).children('li').eq(n).mouseover();
}else if(event.keyCode==13){//enter键
$(inputUl).children('li').eq(n).mouseout();
$(input).val( $(inputUl).children('li').eq(n).text() );
n=-1;
}
});
//去掉浏览器默认
function stopDefaultAndBubble(e){
e=e||window.event;
//阻止默认行为
if (e.preventDefault) {
e.preventDefault();
}
e.returnValue=false;
//阻止冒泡
if (e.stopPropagation) {
e.stopPropagation();
}
e.cancelBubble=true;
}
});
$(input).blur(function() {
$(inputUl).slideUp(500);
});
$(inputUl).delegate('li', 'click', function() {
$(input).val( $(this).text() );
});
return this;
}
}
//在插件中使用Datalist对象
$.fn.myDatalist=function(options){
//创建实体
var datalist=new Datalist(this,options);
//调用其方法
return datalist.showList();
}
})(jQuery,window,document);
这里用ul li列表模拟datalist options。实现逻辑非常简单,稍微需要注意点的是div.input_wrap是用相对定位的,方便ul.input1_ul相对进行定位。由于需求有很多的输入框且相互之间不影响,因此这里是input1。好歹是我自己开发的第一个插件,mark一记。
需要代码的可以戳https://github.com/codetker/myDatalist。
以上资料是 摘自 jQuery插件开发之datalist - codetker - 博客园
==================================
下面是fastadmin selectpage的效果
是这种效果是input的升级优化而来,
默认值
selectpage不被选中?默认值
赋值后需要刷新selectPage$('#mz-topic-id').val(data.id);
$('#mz-topic-id').selectPageRefresh();
HTML
<input id="c-name" class="form-control selectpage" name="TEST" type="text" value="">
js 第一步,引入 selectpage控件
define(['jquery', 'bootstrap', 'backend', 'table', 'form','selectpage'], function ($, undefined, Backend, Table, Form, selectpage) {
第二步
$('#c-name').selectPage({
showField : 'product',
keyField : 'id',
data : [
{"id":3,"product":"华为P40 Pro"},
{"id":4,"product":"小米10 Pro"}
]
});
这样就能显示了。当然官方提供更多属性和控制方法
动态下拉(SelectPage)
FastAdmin中的动态下拉列表使用的是优秀强大的Selectpage
插件,FastAdmin对其进行了二次开发。
常规用法
下面介绍一个基础的动态下拉列表示例,如下
<input id="c-name" data-rule="required" data-source="category/selectpage" class="form-control selectpage" name="row[name]" type="text" value="">
其中需要给元素class添加一个selectpage
,其次需要增加一个data-source="category/selectpage"
这个属性,category/selectpage
为我们控制器提交列表的方法
FastAdmin的Selectpage
列表中显示字段
默认读取的是name
字段,如果我们返回的列表中不包含name
字段,将无法展现下拉列表数据。此时我们需要添加使用data-field="你要显示的字段"
即可,例如data-field="title"
。
FastAdmin的Selectpage
列表中主键字段
默认读取的是id
字段,如果我们的主键不是id
字段,则我们可以添加并使用data-primary-key="你的主键ID字段"
来修改,例如data-primary-key="productid"
。
常用属性
属性 | 功能 | 示例 |
---|---|---|
data-source | 提供数据源的URL地址或JSON数据 | data-source="category/index" |
data-field | 列表显示读取的字段 | data-field="username" |
data-primary-key | 列表选中后渲染的字段 | data-primary-key="uid" |
data-pagination | 是否开启分页 | data-pagination="true" |
data-page-size | 分页大小 | data-page-size="10" |
data-multiple | 是否支持多选 | data-multiple="true" |
data-max-select-limit | 最多可选择数量 | data-max-select-limit="3" |
data-order-by | 排序字段 | data-order-by="id" |
data-params | 自定义扩展参数 | data-params='{"custom[type]":"test"}' |
data-select-only | 是否为只读模式 | data-select-only="true" |
data-format-item | 列表行模板 | data-format-item="{title} - {author}" |
disabled | 禁用SelectPage组件 | disabled |
附加请求参数
如果需要简单的进行搜索筛选过滤,可以使用
//筛选status为normal,type为1的数据
data-params='{"custom[status]":"normal","custom[type]":"1"}'
data-params
支持function
类型,如果需要动态传参(例如联动查询),则可以在JS中将data-params
添加一个function
处理即可,请在表单初始化Form.api.bindevent
之前使用,例如传递动态选择的类型
$("#c-name").data("params", function (obj) {
return {custom: {type: $("#c-type").val()}};
});
自定义行模板
SelectPage
的data-format-item
在1.2.0
之前的版本只支持使用JS赋值function
来实现格式化模板功能,如:
$("#c-category").data("format-item", function(row){
return row.title + " - " + row.author;
});
从FastAdmin1.2.0
版本开始,同时还支持占位符和模板,如:
占位符模式
<input type="text" ... data-format-item="{title} - {author}" />
模板模式
<input type="text" ... data-format-item="#titletpl" />
<script type="text/html" id="titletpl">
<%=title%> - <%=id%>
</script>
温馨提示:
默认由于data-field="name"
只能指定一个显示的字段,如果需要调用显示多个字段值时,必须在控制器指定
protected $selectpageFields = "id,name,title,author";
数据源
data-source
支持Object
和远程URL返回
两种方式,如:
data-source='[{"id":"1","title":"标题1"},{"id":"2","title":"标题2"}]'
和
data-source="category/index"
当使用远程数据源的方式时需要远程返回JSON数据,如:
{
"list":[{"id":4,"username":"FastAdmin","nickname":"快速后台","avatar":"","pid":0},{"id":6,"username":"CRUD","nickname":"一键CRUD","avatar":"","pid":0}],
"total":30
}
其中list
为数据列表,total
为总记录数,总记录数将用于前端显示分页使用。
事件监听
如果你需要对SelectPage
组件值变更以后的事件进行监听,可以直接监听文本框的change
事件即可,如:
$(document).on("change", "#c-title", function(){
//后续操作
});
也可使用
$("#c-title").data("eSelect", function(){
//后续操作
});
来实现,注意以上代码需要放在元素初始化Form.api.bindevent
之前。
常用方法
//刷新SelectPage
$('#category_id').selectPageRefresh();
//清除SelectPage数据
$('#category_id').selectPageClear();
//设置SelectPage数据
$('#category_id').selectPageData(数据源);
//禁用或启用SelectPage
$('#category_id').selectPageDisabled(状态);
//获取SelectPage的选中的文本
$('#category_id').selectPageText();
常用示例
//动态修改SelectPage选中项
$('#category_id').val(3);
$('#category_id').selectPageRefresh();
//设置SelectPage数据
var data = [
{id:1 ,name:'分类一'},{id:2 ,name:'分类二'}
];
$('#category_id').selectPageData(data);
//禁用
$('#category_id').selectPageDisabled(true);
//启用
$('#category_id').selectPageDisabled(false);
常见问题
1、FastAdmin在生成CRUD时会对包含下划线的字段默认生成动态下拉列表,比如user_id
将自动生成data-source="user/index"
,默认读取的是id
和name
字段,如果需要修改,请修改对应参数data-primary-key
和data-field
来重新赋值。
2、如果你在开发时遇到SelectPage
组件在编辑时总是返回第一行
或返回所有行
的数据时,请参考以下文档进行检查你的代码:
为什么Selectpage下拉列表在编辑时总是返回第一行的值? - FastAdmin问答社区
为什么Selectpage下拉列表在编辑时总是返回所有行的数据? - FastAdmin问答社区
更多的使用方法请参考Selectpage官方教程
文档最后更新时间:2022-03-04 17:24:03
=========================================
为什么Selectpage下拉列表在编辑时总是返回第一行的值?
有很多小伙伴都遇到过这个问题,那到底为什么会这样呢?是Selectpage的BUG,还是FastAdmin的BUG?其实都不是,这是因为你采用了自定义数据源导致未处理编辑时的数据导致的。
我们都知道在FastAdmin中可以给input
添加selectpage
的class
和data-source
属性值后就可以使用动态下拉列表,但往往我们会忽略对编辑时的特殊处理。
例如:
通常情况下我们的数据源data-source="category/selectpage"
,当我们点击selectpage文本框时,请求的参数为:
q_word[]: 名称
pageNumber: 1
pageSize: 10
andOr: AND
orderBy[0][]: name
orderBy[0][]: ASC
searchTable: tbl
showField: name
keyField: id
searchField[]: name
name: 名称
服务器返回的数据数据如下:
{
"total": 2,
"list": [
{
"id": "1",
"name": "名称1"
},
{
"id": "2",
"name": "名称2"
}
]
}
我们的list数据是一个二维数组,返回以上数据在添加时使用时没有任何问题的。但是我们在进入编辑页面时,Selectpage
会首先向category/selectpage
这个链接请求一次当前编辑项所对应的数据。
我们通过Chrome的开发者控制台
中的Network
中可以看到请求的参数是
searchTable: tbl
searchKey: id
searchValue: 2
orderBy[0][]: name
orderBy[0][]: ASC
showField: name
keyField: id
keyValue: 2
searchField[]: name
比我们正常请求多了个keyValue
,我们可以在我们的数据源data-source="category/selectpage"
中判断下如果存在keyValue
值时只返回与keyValue
值有关联的数据,例如我们在category/selectpage
中加个判断如下:
if($this->request->request("keyValue")){
return ['total'=>1, 'list'=>[
['id'=>2, 'name'=>'名称2']
]
];
}
通过以上判断后我们在编辑时就不会始终显示的是列表中的第一项数据了。
同理如果我们启用了data-multiple="true"
时,此时我们判断keyValue
时应该只返回与之关联的多个数据。
参考资料
动态下拉(SelectPage) - FastAdmin框架文档 - FastAdmin开发文档https://doc.fastadmin.net/doc/178.html
selectPage - FastAdmin问答社区https://ask.fastadmin.net/search.html?order=&type=docs&q=selectPage