我们正在使用jQuery Sortable库来进行类似于WordPress的动态菜单管理。并且具有多级管理。
<ol id="my-nav">
<li data-id="unique-id-here" data-label="">
<span>My Label</span>
<button type="button" data-toggle="#"toggle-unique-id-here">Options</button>
<div id="toggle-unique-id-here">
<input type="text" class="label-change">
</div>
<ol><!-- PLACEHOLDER FOR SUBMENU --></ol>
</li>
</ol>
<textarea id="output"></textarea>
我们想使用继承的输入字段来更新菜单标签。所以我们做了如下的事情:
$('body').on('keyup change', '.label-change', function () {
var this_menu_label_field = $(this);
var this_field_val = this_menu_label_field.val();
var this_menu_nav = this_menu_label_field.parents('li');
// Update the text string inside the <li>
this_menu_nav.find('span').html(this_field_val);
// Update the data-label attribute
this_menu_nav.attr('data-label', this_field_val).sortable('refresh');
var serialized_data = menu_container.sortable('serialize').get();
$('#output').val(JSON.stringify(serialized_data));
});
代码正在更新相应<span>
内<li>
内的字符串,并更改data-label
。但不幸的是,它仅将第一个按键更新为#output
文本区域。
例如:如果键入“ Whatever”,则可能需要“ W”或“ Wha”。并且没有更多的击键被更新到#output
中。但是,<span>
和data-label
内部的更新总是可以正常工作。
我们非常需要这种功能。但是我们如何实现呢?
答案 0 :(得分:5)
我在弄弄这个,并且能够使其工作。在这里检查我的分叉小提琴:jsfiddle.net/qf7n89oe。
我所做的唯一更改是替换了
this_menu_nav.attr('data-label', this_field_val).sortable('refresh');
与
this_menu_nav.data('label', this_field_val).sortable('refresh');
似乎使用attr()
会导致一些缓存问题,所以我用data()
替换了它,似乎没有这个问题。
答案 1 :(得分:3)
jQuery Sortable将数据存储在数据对象中。因此它不处理data- *属性。如果您想使用jQuery数据对象,则可以使用Kodos Johnson答案。另一种选择是拥有自己的序列化功能定义。参见以下示例:
/**
* ---------------------------------------
* OUR CODE STARTS HERE
* ---------------------------------------
*/
jQuery(document).ready(function($) {
var menu_container = $('#my-nav');
var menu_data_field = $('#output');
var sortable = menu_container.sortable({
delay: 500,
group: 'serialization',
onDrop: function($item, container, _super) {
var data = sortable.sortable('serialize').get();
var jsonString = JSON.stringify(data);
menu_data_field.val(jsonString);
_super($item, container);
},
serialize: function($parent, $children, parentIsContainer) {
let result = $parent.map(function(e) {
let attr = {};
$.each(this.attributes, function() {
const name = this.name.replace("data-", "");
attr[name] = this.value;
});
return attr;
});
if (parentIsContainer)
return [$children]
else if ($children[0]) {
result[0].children = $children
}
delete result.subContainers
delete result.sortable
return result.get();
},
});
$('body').on('keyup', '.label-change', function() {
var this_menu_label_field = $(this);
var this_field_val = this_menu_label_field.val();
var this_menu_nav = this_menu_label_field.parent('li');
// Update the text string inside the <li>
this_menu_nav.find('> span').html(this_field_val);
// Update the data-label attribute
this_menu_nav.attr('data-label', this_field_val).sortable('refresh');
var serialized_data = menu_container.sortable('serialize').get();
console.log(serialized_data);
$('#output').val(JSON.stringify(serialized_data));
});
});
body.dragging,
body.dragging * {
cursor: move !important;
}
input[type="text"] {
border-color: red;
}
#my-nav {
padding-left: 0;
list-style-type: none;
overflow: hidden;
}
#my-nav ol {
padding-left: 0;
margin-left: 20px;
list-style-type: none;
}
#my-nav li {
padding: 5px 10px;
background-color: #f8f8f8;
color: #333;
border: 1px solid #999;
border-radius: 3px;
margin-bottom: 10px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
cursor: move;
}
#my-nav li.placeholder {
position: relative;
border-style: dashed;
background-color: #ededed;
min-height: 34px;
}
#my-nav li.placeholder:before {
position: absolute;
}
#my-nav li.dragged {
position: absolute;
top: 0;
opacity: .5;
z-index: 2000;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.5);
}
#my-nav li.dragged i.icon-move {
color: var(--primary);
}
#my-nav li.highlight {
background: gray;
color: lightgray;
}
#my-nav li:first-of-type {
margin-top: 10px;
}
#my-nav i.icon-move {
cursor: pointer;
color: #999;
padding: 5px;
}
.dd {
position: relative;
display: block;
margin: 0;
padding: 0;
max-width: 600px;
list-style: none;
font-size: 13px;
line-height: 20px;
}
.dd-list {
display: block;
position: relative;
margin: 0;
padding: 0;
list-style: none;
}
.dd-list .dd-list {
padding-left: 30px;
}
.dd-item,
.dd-empty,
.dd-placeholder {
display: block;
position: relative;
margin: 0;
padding: 0;
min-height: 20px;
font-size: 13px;
line-height: 20px;
}
.dd-handle {
display: block;
height: 30px;
margin: 5px 0;
padding: 5px 10px;
color: #333;
text-decoration: none;
font-weight: bold;
border: 1px solid #ccc;
background: #fafafa;
border-radius: 3px;
box-sizing: border-box;
}
.dd-handle:hover {
color: #2ea8e5;
background: #fff;
}
.dd-item>button {
position: relative;
cursor: pointer;
float: left;
width: 25px;
height: 20px;
margin: 5px 0;
padding: 0;
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
border: 0;
background: transparent;
font-size: 12px;
line-height: 1;
text-align: center;
font-weight: bold;
}
.dd-item>button:before {
display: block;
position: absolute;
width: 100%;
text-align: center;
text-indent: 0;
}
.dd-item>button.dd-expand:before {
content: '+';
}
.dd-item>button.dd-collapse:before {
content: '-';
}
.dd-expand {
display: none;
}
.dd-collapsed .dd-list,
.dd-collapsed .dd-collapse {
display: none;
}
.dd-collapsed .dd-expand {
display: block;
}
.dd-empty,
.dd-placeholder {
margin: 5px 0;
padding: 0;
min-height: 30px;
background: #f2fbff;
border: 1px dashed #b6bcbf;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
.dd-empty {
border: 1px dashed #bbb;
min-height: 100px;
background-color: #e5e5e5;
background-size: 60px 60px;
background-position: 0 0, 30px 30px;
}
.dd-dragel {
position: absolute;
pointer-events: none;
z-index: 9999;
}
.dd-dragel>.dd-item .dd-handle {
margin-top: 0;
}
.dd-dragel .dd-handle {
box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, 0.1);
}
.dd-nochildren .dd-placeholder {
display: none;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-sortable/0.9.13/jquery-sortable-min.js"></script>
<ol id="my-nav">
<li data-id="unique-id-here" data-label="My Label">
<span>My Label</span>
<input type="text" class="label-change form-control" placeholder="Type here to see the impact">
<ol>
<li data-id="unique-id-here" data-label="My Sub Label">
<span>My Sub Label</span>
<input type="text" class="label-change form-control" placeholder="Type here to see the impact">
<ol>
<!-- PLACEHOLDER FOR SUBMENU -->
</ol>
</li>
</ol>
</li>
</ol>
<h4>OUTPUT HERE</h4>
<textarea id="output" class="form-control" placeholder="">[[{"label":"My Label","id":"unique-id-here","children":[[{"label":"My Sub Label","id":"unique-id-here","children":[[]]}]]}]]</textarea>