JS处理Select Option 过滤
今天在开发中遇到一个开发需求要求在为产品添加SKU属性时,已经选择过的属性在后面的Select中将不能再被选择。视图如下图:
一、根据这个视图分为三个操作:
1. 属性选择框选择属性操作 ----- change.selet
2. 新增属性操作 ----- click.add
3. 删除属性操作 ----- click.del
二、下面根据这三个操作关联相应的DOM更新:
1. change.selet:当属性选择操作发生change事件时,
存储下当前的选择值 selected_value。
遍历文档中存在的Select元素并将该元素下,
值等于selected_value的Option选项的disabled属性设置为true;
$(document).on('change.select','.js-select-property',function(){
var _this = $(this),
_selectedValue = _this.val(),
_root = _this.parents('._specification-group'),
_row = _this.parents('._property_item'),
_siblings = _row.siblings('._property_item'),
_rows = _root.find('._property_item'),
_original = _this.data('original');
_siblings.each(function(index,item){
var _item = $(this).find('option[value='+_selectedValue+']'),
_originalIitem = $(this).find('option[value='+_original+']');
_item.prop("disabled", true);
_originalIitem.prop("disabled", false);
})
_this.data('original',_selectedValue)
})
2. click.add: 当点击新增按钮时,
遍历文档中存在的Select元素并获取该元素的value值,
新建一个Option元素值为当前获取的值,disabled属性为false。
并插入一个定义的new_select 元素中,遍历结束,
将定义的new_select 元素插入到文档中;
$(document).on('click.add','.js-add-new-property',function(){
var _this = $(this),
_root = _this.parents('._specification-group'),
_rows = _root.find('._property_item'),
_row = _this.parents('._property_item'),
_length = _rows.length,
_newItem = '<div class="row _property_item"> '
+ ' <label class="control-label _ml20 _inline_block">属性名称</label>'
+ ' <select data-original="0" class="form-control _inline_block _w240 _ml20 js-select-property" name="">'
+ '<option value="0">请选择规格属性名称</option>'
+ '<option value="1">颜色</option>'
+ '<option value="2">尺寸</option>'
+ '<option value="3">材质</option>'
+ '</select>'
+ ' <div class="input-group _w320 _vam _inline_block _ml20">'
+ '<input type="text" class="form-control _w240">'
+ '<span class="input-group-btn">'
+ '<button type="button" class="btn btn-danger js-del-new-property">删除</button>'
+ '</span></div></div>',
_newItemDom = $(_newItem);
if(_length === 3){
layer.msg('最多只能添加三条');
return
}
_rows.each(function(item){
var val = $(this).find('select').val(),
_item = _newItemDom.find('option[value='+val+']');
_item.prop("disabled", true);
});
_row.after(_newItemDom);
})
3. click.del:当点击删除按钮时,
存储下当前的选择值 selected_value。
遍历文档中存在的Select元素并将该元素下,
值等于selected_value的Option选项的disabled属性设置为false;
$(document).on('click.del','.js-del-new-property',function(){
var _this = $(this),
_root = _this.parents('._specification-group'),
_rows = _root.find('._property_item'),
_row = _this.parents('._property_item'),
_delValue = _row.find('select').val(),
_siblings = _row.siblings('._property_item');
_rows.each(function(index,item){
var _item = $(this).find('option[value='+_delValue+']');
_item.prop('disabled',false)
});
_row.remove()
})
三、总结:
1、 在选择属性时绑定的Change.select事件会将兄弟Select元素中等值的Option的Disabled属性设置为True,但是如果再次更新该Select元素值时,该Change.select事件只会重复的将兄弟Select元素中等值的Option的Disabled属性设置为True,这样就会造成兄弟元素中的Option元素都被设置成不可选状态,显然这是一个Bug;解决这个问题的办法就是在Change.select事件发生时对原来值对应的兄弟元素中的Option进行状态的释放,这里就遇到一个问题如何获得Select元素的上个状态的值,查了下Select元素的API发现并没有记录上个状态的属性,于是就设置了一个自定义属性data-original用来手动记录Select的上一个状态值;并利用_original = _this.data('original')
获取,_this.data('original',_selectedValue)
进行更新;
四、功能完善:
前端写好静态HTML页面往往需要在和后端对接的时候对页面进行调整,做一些完善功能、调整布局的操作;在这个案例中和后端对接遇到两个问题:
1. form表单元素要动态的插入name属性,这个name属性是个数组并且在插入式填写数组的下标;
2. 为了便于后端渲染,添加按钮要从第一条条目中独立出来;
下面是修改后的HTML结构:
<!-- 产品规格 -->
<div class="form-group">
<label class="col-sm-2 control-label">产品规格
</label>
<div class="col-sm-10 js-specification-groups">
<div class="blank"></div>
{volist name='data.sku_item' id='vo'}
<div class="_specification-group">
{if condition="$vo.sku_color"}
<div class="row _property_item">
<label class="control-label _ml20 _inline_block">属性名称</label>
<select data-original="0" class="form-control _inline_block _w240 _ml20 js-select-property" name="attr[1][]">
<option value="0">请选择规格属性名称</option>
<option value="color" selected>颜色</option>
<option value="size">尺寸</option>
<option value="fabric">材质</option>
</select>
<div class="input-group _w320 _vam _inline_block _ml20">
<input type="text" name="attr_cont[1][]" class="form-control _w240 js-input-property" value="{$vo.sku_color}">
<span class="input-group-btn">
<button type="button" class="btn btn-danger js-del-new-property">删除</button>
</span>
</div>
</div>
{/if} {if condition="$vo.sku_size"}
<div class="row _property_item">
<label class="control-label _ml20 _inline_block">属性名称</label>
<select data-original="0" class="form-control _inline_block _w240 _ml20 js-select-property" name="attr[1][]">
<option value="0">请选择规格属性名称</option>
<option value="color">颜色</option>
<option value="size" selected>尺寸</option>
<option value="fabric">材质</option>
</select>
<div class="input-group _w320 _vam _inline_block _ml20">
<input type="text" name="attr_cont[1][]" class="form-control _w240 js-input-property" value="{$vo.sku_size}">
<span class="input-group-btn">
<button type="button" class="btn btn-danger js-del-new-property">删除</button>
</span>
</div>
</div>
{/if} {if condition="$vo.sku_fabric"}
<div class="row _property_item">
<label class="control-label _ml20 _inline_block">属性名称</label>
<select data-original="0" class="form-control _inline_block _w240 _ml20 js-select-property" name="attr[1][]">
<option value="0">请选择规格属性名称</option>
<option value="color">颜色</option>
<option value="size">尺寸</option>
<option value="fabric" selected>材质</option>
</select>
<div class="input-group _w320 _vam _inline_block _ml20">
<input type="text" name="attr_cont[1][]" class="form-control _w240 js-input-property" value="{$vo.sku_fabric}">
<span class="input-group-btn">
<button type="button" class="btn btn-danger js-del-new-property">删除</button>
</span>
</div>
</div>
{/if}
<div class="row _mt10 js-add-new-property-box">
<div class="control-label _ml20 _inline_block _w52 _txt_align_just"></div>
<div class="_inline_block _w555 _ml20">
<button type="button" class="btn btn-primary js-add-new-property">
新增产品属性
</button>
</div>
</div>
<div class="row _mt10">
<label class="control-label _ml20 _inline_block _w52 _txt_align_just">库存</label>
<input type="text" class="form-control _inline_block _w555 _ml20 js-stock" name="stock[1]" value="{$vo.stock}">
</div>
</div>
{/volist}
<div class="row _mt10">
<div class="control-label _ml20 _inline_block _w52 _txt_align_just"></div>
<div class="_inline_block _w555 _ml20">
<button class="btn btn-primary js-add-new-specification" type="button">新增产品规格</button>
</div>
</div>
</div>
</div>
<div class="hr-line-dashed"></div>
处理好这些调整之后就是一些对JS代码的一些优化,这里我做了一些调整:
1.利用JQuery的clone方法获取Dom转化成模版的方法
var _newItemDom = $(this).parents('.js-add-new-property-box').prev('._property_item').clone();
取代以前写长长的模版字符串的方法_newItem = '<div class="row _property_item">....</div>',
2.利用JQuery设置属性方法
_new_specification_dom.attr('name','attr['+ n +'][]')
取代拼接字符串设置属性的方法name=attr_cont[' + n + '][]
;3.利用JQuery隐式迭代批量快速操作对象属性;
4.利用JQuery链式操作快速进行文档树遍历;
5.使用JQuery:get(index)获取操作对象的区间;
6.使用.match(正则),获取字符串中指定位置的字符串;
7.对插入新属性组进行排序性插入,利用序号和标号对比确定是否顺序以及插入的位置;
优化后的JS代码如下:
// 添加属性
$(document).on('click.add','.js-add-new-property',function(){
var _this = $(this),
_root = _this.parents('._specification-group'),
_rows = _root.find('._property_item'),
_wrap = _this.parents('.js-add-new-property-box'),
_row = _wrap.prev('._property_item'),
_length = _rows.length,
_newItemDom = _row.clone();
if(_length === 3){
layer.msg('最多只能添加三条');
return
}
_newItemDom
.find('.js-input-property')
.val('')
.end()
.find('.js-select-property')
.val(0)
.find('option')
.removeAttr('selected');
_rows.each(function(item){
var val = $(this).find('select').val(),
_item = _newItemDom.find('option[value='+val+']');
_item.prop("disabled", true);
});
_wrap.before(_newItemDom);
})
// 删除属性
$(document).on('click.del','.js-del-new-property',function(){
var _this = $(this),
_root = _this.parents('._specification-group'),
_rows = _root.find('._property_item'),
_length = _rows.length,
_row = _this.parents('._property_item'),
_delValue = _row.find('select').val(),
_siblings = _row.siblings('._property_item');
if(_length === 1){
layer.msg('至少有一条属性');
return
}
_rows.each(function(index,item){
var _item = $(this).find('option[value='+_delValue+']');
_item.prop('disabled',false)
});
_row.remove()
})
// 选择属性
$(document).on('change.select','.js-select-property',function(){
var _this = $(this),
_selectedValue = _this.val(),
_root = _this.parents('._specification-group'),
_row = _this.parents('._property_item'),
_siblings = _row.siblings('._property_item'),
_rows = _root.find('._property_item'),
_original = _this.data('original');
_siblings.each(function(index,item){
var _item = $(this).find('option[value='+_selectedValue+']'),
_originalIitem = $(this).find('option[value='+_original+']');
_item.prop("disabled", true);
_originalIitem.prop("disabled", false);
})
_this.data('original',_selectedValue)
})
// 添加属性组
$(document).on('click.addGroup','.js-add-new-specification',function(){
var _this = $(this),
_root = _this.parents('.js-specification-groups'),
_groups = _root.find('._specification-group'),
_length = _groups.length,
n = _length + 1,
_insert = false,
_insert_position = 0,
_add_btn = _this.parents('.row._mt10'),
_new_specification_dom = _groups.eq(0).clone();
_new_specification_dom
.addClass('_mt10')
.prepend($('<div class="hr-line-dashed _w635"></div>'))
.find('input')
.val('')
.end()
.find('option')
.prop("disabled", false)
.end()
.find('.js-stock')
.removeClass('_w555')
.addClass('_w460')
.after($('<span class="input-group-btn _inline_block"><button type="button" class="btn btn-danger js-del-spec">删除该规格</button></span>'))
.end()
.find('.js-del-new-property')
.parents('._property_item:gt(0)')
.remove();
_groups.each(function(index,item){
var _this = $(this),
_select = _this.find('select'),
_name = _select[0].name,
_index = index+1,
i = _name.match(/attr\[(\d*)\]/),
_i = Number(i[1]);
if(_index !== _i){
n = _index,
_insert_position = index,
_insert = true;
return false;
}else{
_insert = false
}
});
_new_specification_dom
.find('.js-select-property')
.attr('name','attr['+ n +'][]')
.end()
.find('.js-input-property')
.attr('name','attr_cont['+ n +'][]')
.end()
.find('.js-stock')
.attr('name','stock['+ n +']');
_insert ? _groups.eq(_insert_position)
.before(_new_specification_dom)
: _add_btn.before(_new_specification_dom);
});
// 删除属性组
$(document).on('click.delGroup','.js-del-spec',function(){
$(this).parents('._specification-group').remove();
});
调整后:
共同学习,写下你的评论
评论加载中...
作者其他优质文章