公共组件input弹出选择控件-用于建立快速的表之间的关联绑定
说明:
1、提高开发工作效率,目前主流脚手架基本上提供代码生成,单表增删改查很方便,但是针对某个数据需要绑定另外一个表的数据没有,这里希望能尽量做到通用组件化,通过一个配置,点击一个input弹出查询列表选择数据再回写,一步到位。2、如果结合vue的v-model数据绑定,需要优先初始化vm对象如:vm = new Vue({...});因为$watch监听需要vue支持
3、之后再调用bindInputFormOpen();
4、全局匹配input,检测inputfromopen属性
5、参数说明:
参数名 | 必填 | 描述 |
inputfromopen | 是 | 申明此控件需要绑定弹出选择框 |
vModelFullPath | 否 | 仅在配合使用v-model时使用,需配置通过vue对象直接访问的全路径 |
valueField | 是 | 在弹出框选择数据时,指定弹出框里面要取值的字段名用于建立绑定关系,必须是唯一性类似id的作用 |
displayField | 否 | 默认同valueField,区别不建立绑定关系,仅显示,因为如果valueField是id的话不方便显示 |
queryPageUrl | 否 | 仅在配合使用v-model时使用,用于第一次打开查询后台回显displayField |
selectCallbackFn | 否 | 默认调getSelectedRowData函数在common.js,用于从弹出页面选中jqGrid表格数据 |
layerOption | 是 | layer弹出框相关配置,参考原生api,这里直接丢给layer.open |
js示例:
$(function(){var vm = new Vue({...});
bindInputFormOpen();
});
html示例:
<input type="text" name="serverIp" v-model="apiServer.serverIp" class="form-control" placeholder="服务器IP" inputfromopen vModelFullPath="vm.apiServer.serverIp" valueField="apiCode" displayField="apiCode" queryPageUrl="${request.contextPath}/apiManage/apiloglist/list" selectCallbackFn="getSelectedRowData" layerOption="{content:'${request.contextPath}/modules/apiManage/apiloglist.html'}"/>bindFromOpen.js 代码如下
function _bindInputChange(newVal, oldVal, queryPageUrl, index){
queryPageUrl = ctx + queryPageUrl;
var valueInput = $("input[_idcard='value_"+index+"']")[0];
var displayInput = $("input[_idcard='display_"+index+"']")[0];
if(typeof(newVal) == "undefined"){
displayInput.value = "";
}else {
if(valueInput.getAttribute("valueField") == valueInput.getAttribute("displayField")){
displayInput.value = newVal;
return;
}
var data = {};
//框架后台查询都是基于表字段,此处将大写字母转下划线加小写拼接
var field = valueInput.getAttribute('valueField').replace(/[A-Z]/g,function(a,b){
return "_"+a.toLocaleLowerCase();
});
data[field] = newVal;
$.ajax({
type: "POST",
url: queryPageUrl,
data: data,
success: function(r){
if(r.code=='0' && r.page.list.length == 1){
displayInput.value = r.page.list[0][valueInput.getAttribute('displayField')];
}else{
throw "服务器返回错误!或者目标查询字段["+valueInput.getAttribute("valueField")+"]有多条数据!查询地址:"+queryPageUrl;
}
}
});
}
}
function _bindInputBtnYes(index, layero){
var currentLayer = this;
var iframeWin = window[layero.find('iframe')[0]['name']];
var data;
if(typeof(currentLayer.callback) != "undefined" && currentLayer.callback != ""){
data = eval("iframeWin."+currentLayer.callback+"();");
}else{
data = iframeWin.getSelectedRowData();
}
if(typeof(data[currentLayer.valueField]) != "undefined"){
$("input[_idCard=display_"+currentLayer.bindInputIndex+"]")[0].value=data[currentLayer.displayField];
if(currentLayer.vModelFullPath){
$("input[_idCard=value_"+currentLayer.bindInputIndex+"]")[0].value=data[currentLayer.valueField];
eval(currentLayer.vModelFullPath+"='"+data[currentLayer.valueField]+"';");
}else{
$("input[_idCard=value_"+currentLayer.bindInputIndex+"]")[0].value=data[currentLayer.valueField];
}
layer.close(index);
}else{
throw "valueField:"+currentLayer.valueField+"在选中数据行中未匹配属性;row:"+JSON.stringify(data);
}
}
function _bindInputBtnSuccess(layero, index){
var body = layer.getChildFrame('body', index);
body.find('.grid-btn').remove();
}
function bindInputFormOpen(){
var input = $("input");
var defaultOption = {
type : 2,
title : '选择窗口',
area : ['100%','100%'],
shadeClose:true,
move: false,
content : ""
};
$.each(input,function(index,valueInput){
var attr = valueInput.getAttribute('inputfromopen');
if (attr != null) {
valueInput = $(valueInput);
if(valueInput.attr("v-model")){
throw "控件申明了v-model,必须在new Vue({...});初始化之后再执行本方法!因为$watch监听需要vue支持";
}
var option = valueInput.attr('layerOption');
var valueField = valueInput.attr("valueField");
var displayField = valueInput.attr("displayField");
displayField = !displayField || displayField=='' ? valueField : displayField;
var callback = valueInput.attr("selectCallbackFn");
var vModelFullPath = valueInput.attr("vModelFullPath");
var queryPageUrl = valueInput.attr("queryPageUrl");
valueInput.removeAttr("layerOption")
.removeAttr("selectCallbackFn")
.removeAttr("queryPageUrl")
.removeAttr("inputfromopen");
var displayInput = valueInput.clone()
.removeAttr("valueField")
.removeAttr("displayField")
.attr("readonly","true")
.removeAttr("v-model")
.attr("name","display_"+valueInput.attr("name"))
.attr("id","display_"+valueInput.attr("id"))
.attr("_idCard", "display_"+index);
valueInput.after(displayInput);
valueInput
.css("display","none")
.attr("_idCard", "value_"+index);
defaultOption.displayField = displayField;
defaultOption.valueField = valueField;
defaultOption.callback = callback;
defaultOption.bindInputIndex = index;
option = eval("("+option+")");
$.each(option, function(key,value){
defaultOption[key] = value;
})
defaultOption.btn = ['确定'];
defaultOption.yes = '_bindInputBtnYes';
defaultOption.success = '_bindInputBtnSuccess';
if(vModelFullPath){//如果有配置vModelFullPath,需要监听属性变换,使用vue支持的特定的方式
defaultOption.vModelFullPath = vModelFullPath;//传递给layer,用于在yes按钮确定后赋值,v-model一旦绑定数据,不能通过传统方式赋值
var vueObjName = vModelFullPath.substring(0,vModelFullPath.indexOf("."));
var dataPath = vModelFullPath.substring(vModelFullPath.indexOf(".")+1,vModelFullPath.length);
//监听值变化,为了巧妙的增加额外参数,重新定义了function 并增加了第三个参数,巧妙的给vue回调的函数传过去我们需要的参数
eval(vueObjName+".$watch('"+dataPath+"', function(a,b,c='"+queryPageUrl+"',d="+index+"){return _bindInputChange(a,b,c,d);})");
}
var layerOption = JSON.stringify(defaultOption);
layerOption = layerOption.replace("\"_bindInputBtnYes\"",'_bindInputBtnYes');
layerOption = layerOption.replace("\"_bindInputBtnSuccess\"",'_bindInputBtnSuccess');
displayInput.attr('onclick', "layer.open("+layerOption+");");
}
});
}